omniauth_openid_connect 0.3.2 → 0.3.3
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +5 -7
- data/lib/omniauth/openid_connect/errors.rb +1 -0
- data/lib/omniauth/openid_connect/version.rb +1 -1
- data/lib/omniauth/strategies/openid_connect.rb +45 -11
- data/omniauth_openid_connect.gemspec +1 -1
- data/test/lib/omniauth/strategies/openid_connect_test.rb +116 -7
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1782deb4f35b91b78092d0d12a274e5a2cf8e072a287f38446a33f675c5a9fa3
|
4
|
+
data.tar.gz: fbcd06a634f452db1b5172f5ef0fd06fe154aab1b4305271c37d6f066349165a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 367cfbd61e617f8f8f6cae9a6b4f6ee0b6c225bc551d60b1815964eefd63d3088dcbcbf6202bf44f82ae21fc7ae1ec7e303f8d9dd39946556b77c6bfafee9d00
|
7
|
+
data.tar.gz: 322d7f6656131e37c4edc0850d8917c3a1fdc0ed5a3cc2065c0a3ac61228849a0fe892e917df2dbc5f379f8a04ba08366b24d595e7f4a0d0e345d5cab7d8f786
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# v0.3.3 (09.11.2019)
|
2
|
+
|
3
|
+
- Pass `acr_values` to authorize url [#43](https://github.com/m0n9oose/omniauth_openid_connect/pull/43)
|
4
|
+
- Add raw info for id token [#42](https://github.com/m0n9oose/omniauth_openid_connect/pull/42)
|
5
|
+
- Fixed `id_token` verification when `id_token` is not used [#41](https://github.com/m0n9oose/omniauth_openid_connect/pull/41)
|
6
|
+
- Cast `response_type` to string when checking if it is set in params [#36](https://github.com/m0n9oose/omniauth_openid_connect/pull/36)
|
7
|
+
- Support both symbol and string version of `response_type` option [#35](https://github.com/m0n9oose/omniauth_openid_connect/pull/35)
|
8
|
+
- Fix gemspec homepage [#33](https://github.com/m0n9oose/omniauth_openid_connect/pull/33)
|
9
|
+
- Add support for `response_type` `id_token` [#32](https://github.com/m0n9oose/omniauth_openid_connect/pull/32)
|
10
|
+
|
1
11
|
# v0.3.2 (03.08.2019)
|
2
12
|
|
3
13
|
- Use response_mode in `authorize_uri` if the option is defined [#30](https://github.com/m0n9oose/omniauth_openid_connect/pull/30)
|
data/README.md
CHANGED
@@ -48,11 +48,9 @@ Configuration details:
|
|
48
48
|
**NOTE**: if you use this gem with Devise you should use `:openid_connect` name,
|
49
49
|
or Devise would route to 'users/auth/:provider' rather than 'users/auth/openid_connect'
|
50
50
|
|
51
|
-
*
|
52
|
-
|
53
|
-
|
54
|
-
server side web apps anyway and are designed more for native/mobile apps.
|
55
|
-
* If you want to pass `state` paramete by yourself. You can set Proc Object.
|
51
|
+
* `response_type` tells the authorization server which grant type the application wants to use,
|
52
|
+
currently, only `:code` (Authorization Code grant) and `:id_token` (Implicit grant) are valid.
|
53
|
+
* If you want to pass `state` paramete by yourself. You can set Proc Object.
|
56
54
|
e.g. `state: Proc.new { SecureRandom.hex(32) }`
|
57
55
|
* `nonce` is optional. If don't want to pass "nonce" parameter to provider, You should specify
|
58
56
|
`false` to `send_nonce` option. (default true)
|
@@ -60,8 +58,8 @@ Configuration details:
|
|
60
58
|
`:client_auth_method` option, automatically set `:basic`.
|
61
59
|
* Use "OpenID Connect Discovery", You should specify `true` to `discovery` option. (default false)
|
62
60
|
* In "OpenID Connect Discovery", generally provider should have Webfinger endpoint.
|
63
|
-
If provider does not have Webfinger endpoint, You can specify "Issuer" to option.
|
64
|
-
e.g. `issuer: "https://myprovider.com"`
|
61
|
+
If provider does not have Webfinger endpoint, You can specify "Issuer" to option.
|
62
|
+
e.g. `issuer: "https://myprovider.com"`
|
65
63
|
It means to get configuration from "https://myprovider.com/.well-known/openid-configuration".
|
66
64
|
* The uid is by default using the `sub` value from the `user_info` response,
|
67
65
|
which in some applications is not the expected value. To avoid such limitations, the uid label can be
|
@@ -14,6 +14,11 @@ module OmniAuth
|
|
14
14
|
include OmniAuth::Strategy
|
15
15
|
extend Forwardable
|
16
16
|
|
17
|
+
RESPONSE_TYPE_EXCEPTIONS = {
|
18
|
+
'id_token' => { exception_class: OmniAuth::OpenIDConnect::MissingIdTokenError, key: :missing_id_token }.freeze,
|
19
|
+
'code' => { exception_class: OmniAuth::OpenIDConnect::MissingCodeError, key: :missing_code }.freeze,
|
20
|
+
}.freeze
|
21
|
+
|
17
22
|
def_delegator :request, :params
|
18
23
|
|
19
24
|
option :name, 'openid_connect'
|
@@ -35,7 +40,7 @@ module OmniAuth
|
|
35
40
|
option :client_jwk_signing_key
|
36
41
|
option :client_x509_signing_key
|
37
42
|
option :scope, [:openid]
|
38
|
-
option :response_type, 'code'
|
43
|
+
option :response_type, 'code' # ['code', 'id_token']
|
39
44
|
option :state
|
40
45
|
option :response_mode # [:query, :fragment, :form_post, :web_message]
|
41
46
|
option :display, nil # [:page, :popup, :touch, :wap]
|
@@ -106,20 +111,18 @@ module OmniAuth
|
|
106
111
|
invalid_state = params['state'].to_s.empty? || params['state'] != stored_state
|
107
112
|
|
108
113
|
raise CallbackError.new(params['error'], error_description, params['error_uri']) if error
|
109
|
-
|
110
114
|
raise CallbackError, 'Invalid state parameter' if invalid_state
|
111
115
|
|
112
|
-
return
|
116
|
+
return unless valid_response_type?
|
113
117
|
|
114
118
|
options.issuer = issuer if options.issuer.nil? || options.issuer.empty?
|
115
119
|
|
116
|
-
|
117
|
-
.verify! issuer: options.issuer,
|
118
|
-
client_id: client_options.identifier,
|
119
|
-
nonce: stored_nonce
|
120
|
-
|
120
|
+
verify_id_token!
|
121
121
|
discover!
|
122
122
|
client.redirect_uri = redirect_uri
|
123
|
+
|
124
|
+
return id_token_callback_phase if configured_response_type == 'id_token'
|
125
|
+
|
123
126
|
client.authorization_code = authorization_code
|
124
127
|
access_token
|
125
128
|
super
|
@@ -165,6 +168,7 @@ module OmniAuth
|
|
165
168
|
prompt: options.prompt,
|
166
169
|
nonce: (new_nonce if options.send_nonce),
|
167
170
|
hd: options.hd,
|
171
|
+
acr_values: options.acr_values,
|
168
172
|
}
|
169
173
|
client.authorization_uri(opts.reject { |_k, v| v.nil? })
|
170
174
|
end
|
@@ -198,9 +202,7 @@ module OmniAuth
|
|
198
202
|
end
|
199
203
|
|
200
204
|
def access_token
|
201
|
-
|
202
|
-
|
203
|
-
@access_token = client.access_token!(
|
205
|
+
@access_token ||= client.access_token!(
|
204
206
|
scope: (options.scope if options.send_scope_to_token_endpoint),
|
205
207
|
client_auth_method: options.client_auth_method
|
206
208
|
)
|
@@ -294,6 +296,38 @@ module OmniAuth
|
|
294
296
|
@logout_path_pattern ||= %r{\A#{Regexp.quote(request_path)}(/logout)}
|
295
297
|
end
|
296
298
|
|
299
|
+
def id_token_callback_phase
|
300
|
+
user_data = decode_id_token(params['id_token']).raw_attributes
|
301
|
+
env['omniauth.auth'] = AuthHash.new(
|
302
|
+
provider: name,
|
303
|
+
uid: user_data['sub'],
|
304
|
+
info: { name: user_data['name'], email: user_data['email'] },
|
305
|
+
extra: { raw_info: user_data }
|
306
|
+
)
|
307
|
+
call_app!
|
308
|
+
end
|
309
|
+
|
310
|
+
def valid_response_type?
|
311
|
+
return true if params.key?(configured_response_type)
|
312
|
+
|
313
|
+
error_attrs = RESPONSE_TYPE_EXCEPTIONS[configured_response_type]
|
314
|
+
fail!(error_attrs[:key], error_attrs[:exception_class].new(params['error']))
|
315
|
+
|
316
|
+
false
|
317
|
+
end
|
318
|
+
|
319
|
+
def configured_response_type
|
320
|
+
@configured_response_type ||= options.response_type.to_s
|
321
|
+
end
|
322
|
+
|
323
|
+
def verify_id_token!
|
324
|
+
return unless configured_response_type == 'id_token'
|
325
|
+
|
326
|
+
decode_id_token(params['id_token']).verify!(issuer: options.issuer,
|
327
|
+
client_id: client_options.identifier,
|
328
|
+
nonce: stored_nonce)
|
329
|
+
end
|
330
|
+
|
297
331
|
class CallbackError < StandardError
|
298
332
|
attr_accessor :error, :error_reason, :error_uri
|
299
333
|
|
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.email = ['jjbohn@gmail.com', 'm0n9oose@gmail.com']
|
12
12
|
spec.summary = 'OpenID Connect Strategy for OmniAuth'
|
13
13
|
spec.description = 'OpenID Connect Strategy for OmniAuth.'
|
14
|
-
spec.homepage = 'https://github.com/
|
14
|
+
spec.homepage = 'https://github.com/m0n9oose/omniauth_openid_connect'
|
15
15
|
spec.license = 'MIT'
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0")
|
@@ -123,6 +123,26 @@ module OmniAuth
|
|
123
123
|
strategy.request_phase
|
124
124
|
end
|
125
125
|
|
126
|
+
def test_request_phase_with_response_mode_symbol
|
127
|
+
expected_redirect = /^https:\/\/example\.com\/authorize\?client_id=1234&nonce=\w{32}&response_mode=form_post&response_type=id_token&scope=openid&state=\w{32}$/
|
128
|
+
strategy.options.issuer = 'example.com'
|
129
|
+
strategy.options.response_mode = 'form_post'
|
130
|
+
strategy.options.response_type = :id_token
|
131
|
+
strategy.options.client_options.host = 'example.com'
|
132
|
+
|
133
|
+
strategy.expects(:redirect).with(regexp_matches(expected_redirect))
|
134
|
+
strategy.request_phase
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_option_acr_values
|
138
|
+
strategy.options.client_options[:host] = 'foobar.com'
|
139
|
+
|
140
|
+
assert(!(strategy.authorize_uri =~ /acr_values=/), 'URI must not contain acr_values')
|
141
|
+
|
142
|
+
strategy.options.acr_values = 'urn:some:acr:values:value'
|
143
|
+
assert(strategy.authorize_uri =~ /acr_values=/, 'URI must contain acr_values')
|
144
|
+
end
|
145
|
+
|
126
146
|
def test_uid
|
127
147
|
assert_equal user_info.sub, strategy.uid
|
128
148
|
|
@@ -143,11 +163,7 @@ module OmniAuth
|
|
143
163
|
strategy.options.issuer = 'example.com'
|
144
164
|
strategy.options.client_signing_alg = :RS256
|
145
165
|
strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
|
146
|
-
|
147
|
-
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
|
148
|
-
id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
|
149
|
-
::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
|
150
|
-
id_token.expects(:verify!)
|
166
|
+
strategy.options.response_type = :code
|
151
167
|
|
152
168
|
strategy.unstub(:user_info)
|
153
169
|
access_token = stub('OpenIDConnect::AccessToken')
|
@@ -163,6 +179,36 @@ module OmniAuth
|
|
163
179
|
strategy.callback_phase
|
164
180
|
end
|
165
181
|
|
182
|
+
def test_callback_phase_with_id_token
|
183
|
+
code = SecureRandom.hex(16)
|
184
|
+
state = SecureRandom.hex(16)
|
185
|
+
nonce = SecureRandom.hex(16)
|
186
|
+
request.stubs(:params).returns('id_token' => code, 'state' => state)
|
187
|
+
request.stubs(:path_info).returns('')
|
188
|
+
|
189
|
+
strategy.options.issuer = 'example.com'
|
190
|
+
strategy.options.client_signing_alg = :RS256
|
191
|
+
strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
|
192
|
+
strategy.options.response_type = 'id_token'
|
193
|
+
|
194
|
+
strategy.unstub(:user_info)
|
195
|
+
access_token = stub('OpenIDConnect::AccessToken')
|
196
|
+
access_token.stubs(:access_token)
|
197
|
+
access_token.stubs(:refresh_token)
|
198
|
+
access_token.stubs(:expires_in)
|
199
|
+
access_token.stubs(:scope)
|
200
|
+
access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
|
201
|
+
|
202
|
+
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
|
203
|
+
id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
|
204
|
+
id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
|
205
|
+
::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
|
206
|
+
id_token.expects(:verify!)
|
207
|
+
|
208
|
+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
209
|
+
strategy.callback_phase
|
210
|
+
end
|
211
|
+
|
166
212
|
def test_callback_phase_with_discovery
|
167
213
|
code = SecureRandom.hex(16)
|
168
214
|
state = SecureRandom.hex(16)
|
@@ -237,7 +283,33 @@ module OmniAuth
|
|
237
283
|
|
238
284
|
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
239
285
|
|
240
|
-
strategy.expects(:fail!)
|
286
|
+
strategy.expects(:fail!).with(:missing_code, is_a(OmniAuth::OpenIDConnect::MissingCodeError))
|
287
|
+
strategy.callback_phase
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_callback_phase_without_id_token
|
291
|
+
state = SecureRandom.hex(16)
|
292
|
+
nonce = SecureRandom.hex(16)
|
293
|
+
request.stubs(:params).returns('state' => state)
|
294
|
+
request.stubs(:path_info).returns('')
|
295
|
+
strategy.options.response_type = 'id_token'
|
296
|
+
|
297
|
+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
298
|
+
|
299
|
+
strategy.expects(:fail!).with(:missing_id_token, is_a(OmniAuth::OpenIDConnect::MissingIdTokenError))
|
300
|
+
strategy.callback_phase
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_callback_phase_without_id_token_symbol
|
304
|
+
state = SecureRandom.hex(16)
|
305
|
+
nonce = SecureRandom.hex(16)
|
306
|
+
request.stubs(:params).returns('state' => state)
|
307
|
+
request.stubs(:path_info).returns('')
|
308
|
+
strategy.options.response_type = :id_token
|
309
|
+
|
310
|
+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
311
|
+
|
312
|
+
strategy.expects(:fail!).with(:missing_id_token, is_a(OmniAuth::OpenIDConnect::MissingIdTokenError))
|
241
313
|
strategy.callback_phase
|
242
314
|
end
|
243
315
|
|
@@ -416,7 +488,8 @@ module OmniAuth
|
|
416
488
|
|
417
489
|
def test_dynamic_state
|
418
490
|
# Stub request parameters
|
419
|
-
|
491
|
+
request.stubs(:path_info).returns('')
|
492
|
+
strategy.call!('rack.session' => { }, QUERY_STRING: { state: 'abc', client_id: '123' } )
|
420
493
|
|
421
494
|
strategy.options.state = lambda { |env|
|
422
495
|
# Get params from request, e.g. CGI.parse(env['QUERY_STRING'])
|
@@ -492,6 +565,42 @@ module OmniAuth
|
|
492
565
|
strategy.options.client_signing_alg = :HS256
|
493
566
|
assert_equal strategy.options.client_options.secret, strategy.public_key
|
494
567
|
end
|
568
|
+
|
569
|
+
def test_id_token_auth_hash
|
570
|
+
state = SecureRandom.hex(16)
|
571
|
+
nonce = SecureRandom.hex(16)
|
572
|
+
strategy.options.response_type = 'id_token'
|
573
|
+
strategy.options.issuer = 'example.com'
|
574
|
+
|
575
|
+
id_token = stub('OpenIDConnect::ResponseObject::IdToken')
|
576
|
+
id_token.stubs(:verify!).returns(true)
|
577
|
+
id_token.stubs(:raw_attributes, :to_h).returns(
|
578
|
+
{
|
579
|
+
"iss": "http://server.example.com",
|
580
|
+
"sub": "248289761001",
|
581
|
+
"aud": "s6BhdRkqt3",
|
582
|
+
"nonce": "n-0S6_WzA2Mj",
|
583
|
+
"exp": 1311281970,
|
584
|
+
"iat": 1311280970,
|
585
|
+
}
|
586
|
+
)
|
587
|
+
|
588
|
+
request.stubs(:params).returns('state' => state, 'nounce' => nonce, 'id_token' => id_token)
|
589
|
+
request.stubs(:path_info).returns('')
|
590
|
+
|
591
|
+
strategy.stubs(:decode_id_token).returns(id_token)
|
592
|
+
strategy.stubs(:stored_state).returns(state)
|
593
|
+
|
594
|
+
strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
|
595
|
+
strategy.callback_phase
|
596
|
+
|
597
|
+
auth_hash = strategy.send(:env)['omniauth.auth']
|
598
|
+
assert auth_hash.key?('provider')
|
599
|
+
assert auth_hash.key?('uid')
|
600
|
+
assert auth_hash.key?('info')
|
601
|
+
assert auth_hash.key?('extra')
|
602
|
+
assert auth_hash['extra'].key?('raw_info')
|
603
|
+
end
|
495
604
|
end
|
496
605
|
end
|
497
606
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniauth_openid_connect
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Bohn
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-11-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: addressable
|
@@ -222,7 +222,7 @@ files:
|
|
222
222
|
- test/lib/omniauth/strategies/openid_connect_test.rb
|
223
223
|
- test/strategy_test_case.rb
|
224
224
|
- test/test_helper.rb
|
225
|
-
homepage: https://github.com/
|
225
|
+
homepage: https://github.com/m0n9oose/omniauth_openid_connect
|
226
226
|
licenses:
|
227
227
|
- MIT
|
228
228
|
metadata: {}
|