omniauth-wechat-oauth2 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a58c603f945673a1f7f58354fc3a38e733b5ba4d7e7ec6d75b263b1464deedf
4
- data.tar.gz: 35b9a1e4e87ae4ae232ddb737d4f26272322050d2694c61b1a973614dc91f833
3
+ metadata.gz: 80313d7db1a1d6df69ed886099adead9279872a8fb49de1b8b961a8483fd6276
4
+ data.tar.gz: db075a26ae635ab40180b0b3f937bbad0484111c06dd54d3512067424e31c74b
5
5
  SHA512:
6
- metadata.gz: 9164a1d25b4e22498a9d821019287922f49887901464dd5930b68c601207874a06f0e9340d0d309c97110f9ef0b71bd2e097749cac8e306e66ed8fb5978c012e
7
- data.tar.gz: b9f728e86f74428d04bff8cd0b3ba2da5dd07b393b7b034cefd233c98f2fb27e56528f3d2d072992d2aac0cf4022941b5f274ad140fd7805e32cc3eb7ad65259
6
+ metadata.gz: 65f903b8e65eedb5017d1763919b92679e0f798eb3dd3df22d66067ba28e3e9d4492ed9b755249ec0b0cd57e53f7fcb61d058930b892c65a931bf756c686bc70
7
+ data.tar.gz: 1a95f075d1f32e42feca3ade502f874ca455832a8da6fc466c298f470fa28530773e256de98260c345f9adb83053d73da935576a02a2eb8adf0bddd72d48602c
checksums.yaml.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -93,6 +93,37 @@ Here's an example of an authentication hash available in the callback by accessi
93
93
 
94
94
  ## Wechat Qiye OAuth2
95
95
 
96
+ Both enterprise strategies (`qiye_web` and `wechat_qiye`) require a successful
97
+ WeCom API response (`errcode: 0`) and a nonempty member `userid`. A corporate
98
+ access token does not authenticate a user: the callback's authorization code
99
+ must also resolve to a member. Invalid codes, API errors, malformed responses,
100
+ and nonmember identities fail authentication without invoking the application
101
+ callback. TLS certificate verification is enabled by default.
102
+
103
+ ### WeCom web login
104
+
105
+ ```ruby
106
+ config.omniauth :qiye_web, ENV['WECOM_CORP_ID'], ENV['WECOM_CORP_SECRET'],
107
+ agentid: ENV['WECOM_AGENT_ID']
108
+ ```
109
+
110
+ Start login through OmniAuth's POST request phase with your application's CSRF
111
+ protection. Keep `provider_ignores_state` at its default (`false`): the callback
112
+ must return the generated state in the same browser session. State is consumed
113
+ when checked, so a completed callback cannot be replayed. If valid logins fail
114
+ with `csrf_detected`, check the session cookie, callback host, and proxy/HTTPS
115
+ configuration instead of disabling state validation.
116
+
117
+ When upgrading an existing deployment, publish or pin the fixed gem revision,
118
+ update the application's lockfile, and restart its processes. A Bundler local
119
+ override only changes the developer's checkout. This fix does not invalidate
120
+ previously issued application sessions or tokens; revoke those associated with
121
+ any confirmed unauthorized login separately. Applications should also reject
122
+ blank `auth.uid` values before looking up local accounts and avoid logging the
123
+ full authentication hash, which contains credentials.
124
+
125
+ ### Legacy enterprise OAuth2
126
+
96
127
  Wechat Qiey usage and configuration are the same with normal account above.
97
128
 
98
129
  ```ruby
@@ -0,0 +1,59 @@
1
+ require "omniauth-oauth2"
2
+ require "omniauth/strategies/wecom_validation"
3
+
4
+ module OmniAuth
5
+ module Strategies
6
+ class QiyeWeb < OmniAuth::Strategies::OAuth2
7
+ include WecomValidation
8
+
9
+ option :name, 'qiye_web'
10
+
11
+ option :client_options, { site: 'https://qyapi.weixin.qq.com',
12
+ authorize_url: 'https://login.work.weixin.qq.com/wwlogin/sso/login',
13
+ token_url: '/cgi-bin/gettoken',
14
+ token_method: :get }
15
+
16
+ option :authorize_options, %i[agentid state login_type]
17
+ option :token_params, { parse: :json }
18
+ option :agentid, nil
19
+
20
+ uid do
21
+ raw_info
22
+ end
23
+
24
+ info do
25
+ { userid: uid }
26
+ end
27
+
28
+ extra do
29
+ { raw_info: nil }
30
+ end
31
+
32
+ # Inherit OAuth2#callback_phase so state, provider errors, and failures are
33
+ # checked before an authentication hash can reach the application.
34
+ def request_phase
35
+ raise ArgumentError, 'agentid is required for QiyeWeb strategy' if options.agentid.to_i <= 0
36
+
37
+ ap = authorize_params
38
+ params = {
39
+ 'login_type' => ap[:login_type] || 'CorpApp',
40
+ 'appid' => client.id,
41
+ 'agentid' => options.agentid,
42
+ 'redirect_uri' => callback_url,
43
+ 'state' => ap[:state]
44
+ }
45
+
46
+ redirect client.authorize_url(params)
47
+ end
48
+
49
+ def raw_info
50
+ @uid ||= begin
51
+ access_token.options[:mode] = :query
52
+ response = access_token.get('/cgi-bin/auth/getuserinfo',
53
+ params: { 'code' => authorization_code }, parse: :json)
54
+ wecom_userid(wecom_response(response))
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,18 +1,18 @@
1
1
  require "omniauth-oauth2"
2
+ require "omniauth/strategies/wecom_validation"
2
3
 
3
4
  module OmniAuth
4
5
  module Strategies
5
6
  class WechatQiye < OmniAuth::Strategies::OAuth2
7
+ include WecomValidation
8
+
6
9
  option :name, "wechat_qiye"
7
10
 
8
11
  option :client_options, {
9
12
  :site => "https://qyapi.weixin.qq.com",
10
13
  authorize_url: "https://open.weixin.qq.com/connect/oauth2/authorize#wechat_redirect",
11
14
  token_url: "/cgi-bin/gettoken",
12
- token_method: :get,
13
- connection_opts: {
14
- ssl: { verify: false }
15
- }
15
+ token_method: :get
16
16
  }
17
17
 
18
18
  option :authorize_params, {scope: "snsapi_userinfo"}
@@ -46,35 +46,23 @@ module OmniAuth
46
46
  end
47
47
 
48
48
  def raw_info
49
- # step 2: get userid via code and access_token
50
- @code ||= access_token[:code]
51
-
52
- # step 3: get user info via userid
53
49
  @uid ||= begin
54
50
  access_token.options[:mode] = :query
55
- response = access_token.get('/cgi-bin/user/getuserinfo', :params => {'code' => @code}, parse: :json)
56
- response.parsed['UserId']
51
+ response = access_token.get('/cgi-bin/user/getuserinfo',
52
+ :params => {'code' => authorization_code}, parse: :json)
53
+ wecom_userid(wecom_response(response))
57
54
  end
58
55
 
59
56
  @raw_info ||= begin
60
57
  access_token.options[:mode] = :query
61
58
  response = access_token.get("/cgi-bin/user/get", :params => {"userid" => @uid}, parse: :json)
62
- response.parsed
59
+ data = wecom_response(response)
60
+ unless wecom_userid(data).casecmp(@uid).zero?
61
+ raise CallbackError.new(:invalid_uid, 'WeCom member profile does not match the authenticated userid')
62
+ end
63
+ data
63
64
  end
64
65
  end
65
-
66
- protected
67
- def build_access_token
68
- # step 0: wechat respond code
69
- code = request.params['code']
70
-
71
- # step 1: get access token
72
- params = {
73
- 'corpid' => client.id,
74
- 'corpsecret' => client.secret,
75
- }.merge(token_params.to_hash(symbolize_keys: true))
76
- client.get_token(params, deep_symbolize(options.auth_token_params.merge({code: code})))
77
- end
78
66
  end
79
67
  end
80
68
  end
@@ -0,0 +1,62 @@
1
+ module OmniAuth
2
+ module Strategies
3
+ # WeCom returns API failures as HTTP 200 responses. A corporate access token
4
+ # alone does not authenticate the user presenting the callback code.
5
+ module WecomValidation
6
+ protected
7
+
8
+ def secure_compare(left, right)
9
+ return false unless left.is_a?(String) && right.is_a?(String)
10
+
11
+ super
12
+ end
13
+
14
+ def authorization_code
15
+ code = request.params['code']
16
+ unless code.is_a?(String) && !code.strip.empty?
17
+ raise OAuth2::CallbackError.new(:invalid_code, 'Missing or invalid WeCom authorization code')
18
+ end
19
+
20
+ code
21
+ end
22
+
23
+ def build_access_token
24
+ authorization_code
25
+ params = {
26
+ 'corpid' => client.id,
27
+ 'corpsecret' => client.secret
28
+ }.merge(token_params.to_hash(symbolize_keys: true))
29
+
30
+ client.get_token(params, deep_symbolize(options.auth_token_params)).tap do |token|
31
+ unless token && token.token.is_a?(String) && !token.token.strip.empty?
32
+ raise OAuth2::CallbackError.new(:invalid_token, 'Missing WeCom access token')
33
+ end
34
+ validate_wecom_response(token.params)
35
+ end
36
+ end
37
+
38
+ def wecom_response(response)
39
+ validate_wecom_response(response.parsed)
40
+ end
41
+
42
+ def validate_wecom_response(data)
43
+ unless data.is_a?(Hash) && data['errcode'] == 0
44
+ raise OAuth2::CallbackError.new(:invalid_response, 'WeCom API did not return a successful response')
45
+ end
46
+
47
+ data
48
+ end
49
+
50
+ def wecom_userid(data)
51
+ # Support both the current API and the legacy UserId response. OAuth2's
52
+ # SnakyHash also accepts the original spelling of normalized keys.
53
+ userid = data['userid'] || data['UserId']
54
+ unless userid.is_a?(String) && !userid.strip.empty?
55
+ raise OAuth2::CallbackError.new(:invalid_uid, 'WeCom did not return a member userid')
56
+ end
57
+
58
+ userid
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,2 +1,3 @@
1
1
  require "omniauth/strategies/wechat"
2
2
  require "omniauth/strategies/wechat_qiye"
3
+ require "omniauth/strategies/qiye_web"
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,43 +1,42 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-wechat-oauth2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Hu
8
8
  - Never Min
9
9
  - Eric Guo
10
- autorequire:
11
10
  bindir: bin
12
11
  cert_chain:
13
12
  - |
14
13
  -----BEGIN CERTIFICATE-----
15
14
  MIIEeDCCAuCgAwIBAgIBATANBgkqhkiG9w0BAQsFADBBMRMwEQYDVQQDDAplcmlj
16
15
  Lmd1b2N6MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNj
17
- b20wHhcNMjIxMjA5MDcyMTE1WhcNMjMxMjA5MDcyMTE1WjBBMRMwEQYDVQQDDApl
16
+ b20wHhcNMjYwNTIyMTUyNDI0WhcNMjcwNTIyMTUyNDI0WjBBMRMwEQYDVQQDDApl
18
17
  cmljLmd1b2N6MRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
19
- FgNjb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC6jGarls5mU792
20
- leWot9tWKXnnvVnj1oUPea8M77PpHcYMVmjUTkjgsrKiOFNv2nAjUIDrUaLJvuKi
21
- 95zZYLIT3uWqI9QvSSDr+rs4HyIDcXuWWB89GpKN5WgyCVel6V9X5PN0C5hIiz8T
22
- ThW7ZqkS8mTmHm2micL8/lmnelpxj9EjCin7xOCvebB9pdA7Y0kXMLbnRq4QK2lB
23
- O2YRbLvYKWOQfO/sqLlwFsNWMNkj5ZROIqmKRvOHQdchox2RfBNsWRZ7XH8tTW1L
24
- cqx95dI2qC6Xg+IHjN4Wc6n+Ak1KENlVjI4mGcuk+34d1S9gaZT8vW/cYcL30Nbg
25
- AAUQvS4AQ8gmAkk1+oNs+725QLBprbnSN5PJr9VQiDteNHHkY5ugjndeAByOGy8h
26
- /TgV4tBZQ0IT37ZRDcP4dayFMm2DVjS4uU7RUXLgc8sdOGeMmsFwdz9QrBPGeKsV
27
- 4+dXjrzzUvwRX4K21mx4ZSP9eSOscOEuzRIRTnab0GniDhkkHc8CAwEAAaN7MHkw
28
- CQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFPGkToJNhoEfhsOYqnTH
29
- MZDYyjQtMB8GA1UdEQQYMBaBFGVyaWMuZ3VvY3pAZ21haWwuY29tMB8GA1UdEgQY
30
- MBaBFGVyaWMuZ3VvY3pAZ21haWwuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQCdTl5T
31
- qfcrbo4KdgZM84ZbeiUIXcRy/chbfQfPZ/qPp7qKARLxRJINmaqt/bP+RrlQypEe
32
- 1EIYhbxLGo1TvpbRFuADUhZjGZ8Vaa+bgPfj8Dxa71ow5dF9nrqidddV7qjmk57F
33
- klOrOl+99Ryx01OAdlxGZqz/VrHrzbhQNtiUl2BYnosZLddYPTzuhNLe72eIypkY
34
- synsOqoXRuegCtO4sSGSvRV79/GyN0jqtptpa61MaxgYG13+P8QwXeTo2Ro86ZAJ
35
- h+KBs65p0MiFHl6zc2oany9Pk0kqs50TDKOCT7ZdSxz5xes0SvTi3mmX3XemjQhm
36
- qNb+5zsj4Kn5auKYA7GupfLYKS/dYt4EIfNKhSEHgkVFdVPxSAQ73UAWsndINTTA
37
- HjK18j09PoL9vWMUtyez2xpxlRDA+bEkF74AEVwMYozjP8VNM1ERTG+8kROuQjGV
38
- aWhGk3yVuHjmlBvfDpPqmux3ulWXnvHulcYiPxETh/m3PUfIKMTHydjAz88=
18
+ FgNjb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC49ueF2WFVqQye
19
+ d1kwtvBNyXx9AI8fLWwLHJqf+3ojjWEYwf8NtwYbBgptw7sMDfbpu+H0TjLSYW9e
20
+ R5IVlfP0v55JtDNjZLnQTtXxaiGLZ9aZgT1t5Rn42RSYqfjLKN2maKpRUCnw8Tw4
21
+ +G1tdxFnYIsHda7jiNvetZjqeVhaoN4enfPk2pTeHpmXvH/FzLuKRkPz0yQOFD6P
22
+ IFdE1a4sPs7Fk9QJa6zyPQ/7cL1Uu+IjNzibvTot+Go1GtWvc7bqdDueX6MSo9Ki
23
+ 7XBVH4Svk9BqGKKCJFibYjBRxMbzlwA8fik9JUKj9Q0gmXeRRf+tQUZWJHKF5Y/4
24
+ wzqyT6k4u5e3S/QnpD/ZNo1ESiu1Bxc6KvlIihKlOvA8+RSgSAmZtcHhk2en4DtP
25
+ aeBgCrJABFbkMVk9+OiRcq1kDAIJHnH9XxyrM/s4x5FYPgZWbqfbYltHp+Y9ByNw
26
+ uzG6YQkT6PkKRAdl8i6udI70iLQZIE8sI+4bwl3JnTfDrJsklhsCAwEAAaN7MHkw
27
+ CQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0OBBYEFAAS4PVX34FrNYW9Iv16
28
+ R4Qyoj1CMB8GA1UdEQQYMBaBFGVyaWMuZ3VvY3pAZ21haWwuY29tMB8GA1UdEgQY
29
+ MBaBFGVyaWMuZ3VvY3pAZ21haWwuY29tMA0GCSqGSIb3DQEBCwUAA4IBgQBFdbRh
30
+ Wh50P882h5BMysO8Ru/cnqUENIsHxUnZsssHuFcU3Gn3Sq43ixKzFhA4uOCDfY36
31
+ xvX7johxHhukDAdo4lD9h+f5Vck35Qns5Ln+b0o0iTyENOFou57CgeqpWeVkDIi4
32
+ vlwdgCunr64KKW7snC4E76AUXRnOYC0UhZL2VQRc54sN6eMIACogJ9ZHii3h5FmG
33
+ ep6LMfi1oKBrU7MLT5BidvCxG3ePEtdfACGznDE7GgimLVcsb3Ft+sNeP6fBtvrM
34
+ OljHZezOIi+Wbot4pvwdt8tCI4eCoAWAYuoCtyav5dDRUeqI7TPdQGgMPDcVckNE
35
+ e3iKcBAe/0pRYSZxORE63n3SOo9MPL2oGe9A21LR/tk/CJ8kZxDdeTh4zL+Ufw3R
36
+ G4TR+pkSPTTDPI2Ft/RAqHjqectqrcz4gZ4e/x1nBhoF8QKrBuEvHXNTR5EtMzcz
37
+ CU8I1U00X8GGbinHiVIfDJnOkCq7cBmbTamZpNwZLCrgQupqUNhEP2vcZVg=
39
38
  -----END CERTIFICATE-----
40
- date: 2023-02-19 00:00:00.000000000 Z
39
+ date: 1980-01-02 00:00:00.000000000 Z
41
40
  dependencies:
42
41
  - !ruby/object:Gem::Dependency
43
42
  name: omniauth-oauth2
@@ -45,28 +44,28 @@ dependencies:
45
44
  requirements:
46
45
  - - ">="
47
46
  - !ruby/object:Gem::Version
48
- version: 1.7.3
47
+ version: 1.8.0
49
48
  type: :runtime
50
49
  prerelease: false
51
50
  version_requirements: !ruby/object:Gem::Requirement
52
51
  requirements:
53
52
  - - ">="
54
53
  - !ruby/object:Gem::Version
55
- version: 1.7.3
54
+ version: 1.8.0
56
55
  - !ruby/object:Gem::Dependency
57
56
  name: rspec
58
57
  requirement: !ruby/object:Gem::Requirement
59
58
  requirements:
60
59
  - - "~>"
61
60
  - !ruby/object:Gem::Version
62
- version: 3.10.0
61
+ version: 3.13.1
63
62
  type: :development
64
63
  prerelease: false
65
64
  version_requirements: !ruby/object:Gem::Requirement
66
65
  requirements:
67
66
  - - "~>"
68
67
  - !ruby/object:Gem::Version
69
- version: 3.10.0
68
+ version: 3.13.1
70
69
  description: Using OAuth2 to authenticate wechat user when web resources being viewed
71
70
  within wechat(weixin) client.
72
71
  email:
@@ -79,14 +78,15 @@ extra_rdoc_files: []
79
78
  files:
80
79
  - README.md
81
80
  - lib/omniauth-wechat-oauth2.rb
81
+ - lib/omniauth/strategies/qiye_web.rb
82
82
  - lib/omniauth/strategies/wechat.rb
83
83
  - lib/omniauth/strategies/wechat_qiye.rb
84
+ - lib/omniauth/strategies/wecom_validation.rb
84
85
  - lib/omniauth/wechat.rb
85
86
  homepage: https://github.com/nevermin/omniauth-wechat-oauth2
86
87
  licenses:
87
88
  - MIT
88
89
  metadata: {}
89
- post_install_message:
90
90
  rdoc_options: []
91
91
  require_paths:
92
92
  - lib
@@ -102,8 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
102
  version: '0'
103
103
  requirements:
104
104
  - none
105
- rubygems_version: 3.4.7
106
- signing_key:
105
+ rubygems_version: 4.0.22
107
106
  specification_version: 4
108
107
  summary: Omniauth strategy for wechat(weixin)
109
108
  test_files: []
metadata.gz.sig CHANGED
Binary file