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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0024abec2d29c79f701d7de6af9e5addf2be2e3da443413d8e1eb90ab5a1edb0
4
- data.tar.gz: 4d564cf7d4f5fcf4da6a961cdf39c7d8a1e943addb3e39a82953a2aaa2757db6
3
+ metadata.gz: 1782deb4f35b91b78092d0d12a274e5a2cf8e072a287f38446a33f675c5a9fa3
4
+ data.tar.gz: fbcd06a634f452db1b5172f5ef0fd06fe154aab1b4305271c37d6f066349165a
5
5
  SHA512:
6
- metadata.gz: 5411ae4999e350a9127890ad4041c099bbefdc765a40f98db108018f9d09f4f402f93f28466c1b079412b875da00ba609906ed04da55addf2a7b486819b65887
7
- data.tar.gz: 0a4b11ac66f14441d106c9d41a02f2464632592c7e746086675b8b3504570fcaf63cc9af55306dd447fa57cc502abb8fc6185beee6f09822693124221b8010aa
6
+ metadata.gz: 367cfbd61e617f8f8f6cae9a6b4f6ee0b6c225bc551d60b1815964eefd63d3088dcbcbf6202bf44f82ae21fc7ae1ec7e303f8d9dd39946556b77c6bfafee9d00
7
+ data.tar.gz: 322d7f6656131e37c4edc0850d8917c3a1fdc0ed5a3cc2065c0a3ac61228849a0fe892e917df2dbc5f379f8a04ba08366b24d595e7f4a0d0e345d5cab7d8f786
@@ -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
- * Although `response_type` is an available option, currently, only `:code`
52
- is valid. There are plans to bring in implicit flow and hybrid flow at some
53
- point, but it hasn't come up yet for me. Those flows aren't best practive for
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
@@ -4,5 +4,6 @@ module OmniAuth
4
4
  module OpenIDConnect
5
5
  class Error < RuntimeError; end
6
6
  class MissingCodeError < Error; end
7
+ class MissingIdTokenError < Error; end
7
8
  end
8
9
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAuth
4
4
  module OpenIDConnect
5
- VERSION = '0.3.2'
5
+ VERSION = '0.3.3'
6
6
  end
7
7
  end
@@ -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 fail!(:missing_code, OmniAuth::OpenIDConnect::MissingCodeError.new(params['error'])) unless params['code']
116
+ return unless valid_response_type?
113
117
 
114
118
  options.issuer = issuer if options.issuer.nil? || options.issuer.empty?
115
119
 
116
- decode_id_token(params['id_token'])
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
- return @access_token if @access_token
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/jjbohn/omniauth-openid-connect'
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
- Strategy.send(:define_method, 'env', -> { { QUERY_STRING: { state: 'abc', client_id: '123' } } })
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.2
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-08-03 00:00:00.000000000 Z
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/jjbohn/omniauth-openid-connect
225
+ homepage: https://github.com/m0n9oose/omniauth_openid_connect
226
226
  licenses:
227
227
  - MIT
228
228
  metadata: {}