omniauth_openid_connect_test 0.3.6

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.
@@ -0,0 +1,620 @@
1
+ require_relative '../../../test_helper'
2
+
3
+ module OmniAuth
4
+ module Strategies
5
+ class OpenIDConnectTest < StrategyTestCase
6
+ def test_client_options_defaults
7
+ assert_equal 'https', strategy.options.client_options.scheme
8
+ assert_equal 443, strategy.options.client_options.port
9
+ assert_equal '/authorize', strategy.options.client_options.authorization_endpoint
10
+ assert_equal '/token', strategy.options.client_options.token_endpoint
11
+ end
12
+
13
+ def test_request_phase
14
+ expected_redirect = /^https:\/\/example\.com\/authorize\?client_id=1234&nonce=\w{32}&response_type=code&scope=openid&state=\w{32}$/
15
+ strategy.options.issuer = 'example.com'
16
+ strategy.options.client_options.host = 'example.com'
17
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
18
+ strategy.request_phase
19
+ end
20
+
21
+ def test_logout_phase_with_discovery
22
+ expected_redirect = %r{^https:\/\/example\.com\/logout$}
23
+ strategy.options.client_options.host = 'example.com'
24
+ strategy.options.discovery = true
25
+
26
+ issuer = stub('OpenIDConnect::Discovery::Issuer')
27
+ issuer.stubs(:issuer).returns('https://example.com/')
28
+ ::OpenIDConnect::Discovery::Provider.stubs(:discover!).returns(issuer)
29
+
30
+ config = stub('OpenIDConnect::Discovery::Provder::Config')
31
+ config.stubs(:authorization_endpoint).returns('https://example.com/authorization')
32
+ config.stubs(:token_endpoint).returns('https://example.com/token')
33
+ config.stubs(:userinfo_endpoint).returns('https://example.com/userinfo')
34
+ config.stubs(:jwks_uri).returns('https://example.com/jwks')
35
+ config.stubs(:end_session_endpoint).returns('https://example.com/logout')
36
+ ::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
37
+
38
+ request.stubs(:path_info).returns('/auth/openid_connect/logout')
39
+
40
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
41
+ strategy.other_phase
42
+ end
43
+
44
+ def test_logout_phase_with_discovery_and_post_logout_redirect_uri
45
+ expected_redirect = 'https://example.com/logout?post_logout_redirect_uri=https%3A%2F%2Fmysite.com'
46
+ strategy.options.client_options.host = 'example.com'
47
+ strategy.options.discovery = true
48
+ strategy.options.post_logout_redirect_uri = 'https://mysite.com'
49
+
50
+ issuer = stub('OpenIDConnect::Discovery::Issuer')
51
+ issuer.stubs(:issuer).returns('https://example.com/')
52
+ ::OpenIDConnect::Discovery::Provider.stubs(:discover!).returns(issuer)
53
+
54
+ config = stub('OpenIDConnect::Discovery::Provder::Config')
55
+ config.stubs(:authorization_endpoint).returns('https://example.com/authorization')
56
+ config.stubs(:token_endpoint).returns('https://example.com/token')
57
+ config.stubs(:userinfo_endpoint).returns('https://example.com/userinfo')
58
+ config.stubs(:jwks_uri).returns('https://example.com/jwks')
59
+ config.stubs(:end_session_endpoint).returns('https://example.com/logout')
60
+ ::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
61
+
62
+ request.stubs(:path_info).returns('/auth/openid_connect/logout')
63
+
64
+ strategy.expects(:redirect).with(expected_redirect)
65
+ strategy.other_phase
66
+ end
67
+
68
+ def test_logout_phase
69
+ strategy.options.issuer = 'example.com'
70
+ strategy.options.client_options.host = 'example.com'
71
+
72
+ request.stubs(:path_info).returns('/auth/openid_connect/logout')
73
+
74
+ strategy.expects(:call_app!)
75
+ strategy.other_phase
76
+ end
77
+
78
+ def test_request_phase_with_params
79
+ expected_redirect = /^https:\/\/example\.com\/authorize\?claims_locales=es&client_id=1234&login_hint=john.doe%40example.com&nonce=\w{32}&response_type=code&scope=openid&state=\w{32}&ui_locales=en$/
80
+ strategy.options.issuer = 'example.com'
81
+ strategy.options.client_options.host = 'example.com'
82
+ request.stubs(:params).returns('login_hint' => 'john.doe@example.com', 'ui_locales' => 'en', 'claims_locales' => 'es')
83
+
84
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
85
+ strategy.request_phase
86
+ end
87
+
88
+ def test_request_phase_with_discovery
89
+ expected_redirect = /^https:\/\/example\.com\/authorization\?client_id=1234&nonce=\w{32}&response_type=code&scope=openid&state=\w{32}$/
90
+ strategy.options.client_options.host = 'example.com'
91
+ strategy.options.discovery = true
92
+
93
+ issuer = stub('OpenIDConnect::Discovery::Issuer')
94
+ issuer.stubs(:issuer).returns('https://example.com/')
95
+ ::OpenIDConnect::Discovery::Provider.stubs(:discover!).returns(issuer)
96
+
97
+ config = stub('OpenIDConnect::Discovery::Provder::Config')
98
+ config.stubs(:authorization_endpoint).returns('https://example.com/authorization')
99
+ config.stubs(:token_endpoint).returns('https://example.com/token')
100
+ config.stubs(:userinfo_endpoint).returns('https://example.com/userinfo')
101
+ config.stubs(:jwks_uri).returns('https://example.com/jwks')
102
+ ::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
103
+
104
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
105
+ strategy.request_phase
106
+
107
+ assert_equal strategy.options.issuer, 'https://example.com/'
108
+ assert_equal strategy.options.client_options.authorization_endpoint, 'https://example.com/authorization'
109
+ assert_equal strategy.options.client_options.token_endpoint, 'https://example.com/token'
110
+ assert_equal strategy.options.client_options.userinfo_endpoint, 'https://example.com/userinfo'
111
+ assert_equal strategy.options.client_options.jwks_uri, 'https://example.com/jwks'
112
+ assert_nil strategy.options.client_options.end_session_endpoint
113
+ end
114
+
115
+ def test_request_phase_with_response_mode
116
+ 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}$/
117
+ strategy.options.issuer = 'example.com'
118
+ strategy.options.response_mode = 'form_post'
119
+ strategy.options.response_type = 'id_token'
120
+ strategy.options.client_options.host = 'example.com'
121
+
122
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
123
+ strategy.request_phase
124
+ end
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
+
146
+ def test_option_custom_attributes
147
+ strategy.options.client_options[:host] = 'foobar.com'
148
+ strategy.options.extra_authorize_params = {resource: 'xyz'}
149
+
150
+ assert(strategy.authorize_uri =~ /resource=xyz/, 'URI must contain custom params')
151
+ end
152
+
153
+ def test_uid
154
+ assert_equal user_info.sub, strategy.uid
155
+
156
+ strategy.options.uid_field = 'preferred_username'
157
+ assert_equal user_info.preferred_username, strategy.uid
158
+
159
+ strategy.options.uid_field = 'something'
160
+ assert_equal user_info.sub, strategy.uid
161
+ end
162
+
163
+ def test_callback_phase(session = {}, params = {})
164
+ code = SecureRandom.hex(16)
165
+ state = SecureRandom.hex(16)
166
+ nonce = SecureRandom.hex(16)
167
+ request.stubs(:params).returns('code' => code, 'state' => state)
168
+ request.stubs(:path_info).returns('')
169
+
170
+ strategy.options.issuer = 'example.com'
171
+ strategy.options.client_signing_alg = :RS256
172
+ strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
173
+ strategy.options.response_type = 'code'
174
+
175
+ strategy.unstub(:user_info)
176
+ access_token = stub('OpenIDConnect::AccessToken')
177
+ access_token.stubs(:access_token)
178
+ access_token.stubs(:refresh_token)
179
+ access_token.stubs(:expires_in)
180
+ access_token.stubs(:scope)
181
+ access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
182
+ client.expects(:access_token!).at_least_once.returns(access_token)
183
+ access_token.expects(:userinfo!).returns(user_info)
184
+
185
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
186
+ id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
187
+ id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
188
+ id_token.expects(:verify!)
189
+
190
+ strategy.expects(:decode_id_token).twice.with(access_token.id_token).returns(id_token)
191
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
192
+ strategy.callback_phase
193
+ end
194
+
195
+ def test_callback_phase_with_id_token
196
+ code = SecureRandom.hex(16)
197
+ state = SecureRandom.hex(16)
198
+ nonce = SecureRandom.hex(16)
199
+ request.stubs(:params).returns('id_token' => code, 'state' => state)
200
+ request.stubs(:path_info).returns('')
201
+
202
+ strategy.options.issuer = 'example.com'
203
+ strategy.options.client_signing_alg = :RS256
204
+ strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
205
+ strategy.options.response_type = 'id_token'
206
+
207
+ strategy.unstub(:user_info)
208
+ access_token = stub('OpenIDConnect::AccessToken')
209
+ access_token.stubs(:access_token)
210
+ access_token.stubs(:refresh_token)
211
+ access_token.stubs(:expires_in)
212
+ access_token.stubs(:scope)
213
+ access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
214
+
215
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
216
+ id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
217
+ id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
218
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
219
+ id_token.expects(:verify!)
220
+
221
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
222
+ strategy.callback_phase
223
+ end
224
+
225
+ def test_callback_phase_with_discovery
226
+ code = SecureRandom.hex(16)
227
+ state = SecureRandom.hex(16)
228
+ nonce = SecureRandom.hex(16)
229
+ jwks = JSON::JWK::Set.new(JSON.parse(File.read('test/fixtures/jwks.json'))['keys'])
230
+
231
+ request.stubs(:params).returns('code' => code, 'state' => state)
232
+ request.stubs(:path_info).returns('')
233
+
234
+ strategy.options.client_options.host = 'example.com'
235
+ strategy.options.discovery = true
236
+
237
+ issuer = stub('OpenIDConnect::Discovery::Issuer')
238
+ issuer.stubs(:issuer).returns('https://example.com/')
239
+ ::OpenIDConnect::Discovery::Provider.stubs(:discover!).returns(issuer)
240
+
241
+ config = stub('OpenIDConnect::Discovery::Provder::Config')
242
+ config.stubs(:authorization_endpoint).returns('https://example.com/authorization')
243
+ config.stubs(:token_endpoint).returns('https://example.com/token')
244
+ config.stubs(:userinfo_endpoint).returns('https://example.com/userinfo')
245
+ config.stubs(:jwks_uri).returns('https://example.com/jwks')
246
+ config.stubs(:jwks).returns(jwks)
247
+
248
+ ::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
249
+
250
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
251
+ id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
252
+ id_token.stubs(:verify!).with(issuer: 'https://example.com/', client_id: @identifier, nonce: nonce).returns(true)
253
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
254
+
255
+ strategy.unstub(:user_info)
256
+ access_token = stub('OpenIDConnect::AccessToken')
257
+ access_token.stubs(:access_token)
258
+ access_token.stubs(:refresh_token)
259
+ access_token.stubs(:expires_in)
260
+ access_token.stubs(:scope)
261
+ access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
262
+ client.expects(:access_token!).at_least_once.returns(access_token)
263
+ access_token.expects(:userinfo!).returns(user_info)
264
+
265
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
266
+ strategy.callback_phase
267
+ end
268
+
269
+ def test_callback_phase_with_error
270
+ state = SecureRandom.hex(16)
271
+ nonce = SecureRandom.hex(16)
272
+ request.stubs(:params).returns('error' => 'invalid_request')
273
+ request.stubs(:path_info).returns('')
274
+
275
+ strategy.call!({'rack.session' => {'omniauth.state' => state, 'omniauth.nonce' => nonce}})
276
+ strategy.expects(:fail!)
277
+ strategy.callback_phase
278
+ end
279
+
280
+ def test_callback_phase_with_invalid_state
281
+ code = SecureRandom.hex(16)
282
+ state = SecureRandom.hex(16)
283
+ nonce = SecureRandom.hex(16)
284
+ request.stubs(:params).returns('code' => code, 'state' => 'foobar')
285
+ request.stubs(:path_info).returns('')
286
+
287
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
288
+ strategy.expects(:fail!)
289
+ strategy.callback_phase
290
+ end
291
+
292
+ def test_callback_phase_without_code
293
+ state = SecureRandom.hex(16)
294
+ nonce = SecureRandom.hex(16)
295
+ request.stubs(:params).returns('state' => state)
296
+ request.stubs(:path_info).returns('')
297
+
298
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
299
+
300
+ strategy.expects(:fail!).with(:missing_code, is_a(OmniAuth::OpenIDConnect::MissingCodeError))
301
+ strategy.callback_phase
302
+ end
303
+
304
+ def test_callback_phase_without_id_token
305
+ state = SecureRandom.hex(16)
306
+ nonce = SecureRandom.hex(16)
307
+ request.stubs(:params).returns('state' => state)
308
+ request.stubs(:path_info).returns('')
309
+ strategy.options.response_type = 'id_token'
310
+
311
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
312
+
313
+ strategy.expects(:fail!).with(:missing_id_token, is_a(OmniAuth::OpenIDConnect::MissingIdTokenError))
314
+ strategy.callback_phase
315
+ end
316
+
317
+ def test_callback_phase_without_id_token_symbol
318
+ state = SecureRandom.hex(16)
319
+ nonce = SecureRandom.hex(16)
320
+ request.stubs(:params).returns('state' => state)
321
+ request.stubs(:path_info).returns('')
322
+ strategy.options.response_type = :id_token
323
+
324
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
325
+
326
+ strategy.expects(:fail!).with(:missing_id_token, is_a(OmniAuth::OpenIDConnect::MissingIdTokenError))
327
+ strategy.callback_phase
328
+ end
329
+
330
+ def test_callback_phase_with_timeout
331
+ code = SecureRandom.hex(16)
332
+ state = SecureRandom.hex(16)
333
+ nonce = SecureRandom.hex(16)
334
+ request.stubs(:params).returns('code' => code, 'state' => state)
335
+ request.stubs(:path_info).returns('')
336
+
337
+ strategy.options.issuer = 'example.com'
338
+
339
+ strategy.stubs(:access_token).raises(::Timeout::Error.new('error'))
340
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
341
+ strategy.expects(:fail!)
342
+
343
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
344
+ id_token.stubs(:verify!).with(issuer: 'example.com', client_id: @identifier, nonce: nonce).returns(true)
345
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
346
+
347
+ strategy.callback_phase
348
+ end
349
+
350
+ def test_callback_phase_with_etimeout
351
+ code = SecureRandom.hex(16)
352
+ state = SecureRandom.hex(16)
353
+ nonce = SecureRandom.hex(16)
354
+ request.stubs(:params).returns('code' => code, 'state' => state)
355
+ request.stubs(:path_info).returns('')
356
+
357
+ strategy.options.issuer = 'example.com'
358
+
359
+ strategy.stubs(:access_token).raises(::Errno::ETIMEDOUT.new('error'))
360
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
361
+ strategy.expects(:fail!)
362
+
363
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
364
+ id_token.stubs(:verify!).with(issuer: 'example.com', client_id: @identifier, nonce: nonce).returns(true)
365
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
366
+
367
+ strategy.callback_phase
368
+ end
369
+
370
+ def test_callback_phase_with_socket_error
371
+ code = SecureRandom.hex(16)
372
+ state = SecureRandom.hex(16)
373
+ nonce = SecureRandom.hex(16)
374
+ request.stubs(:params).returns('code' => code, 'state' => state)
375
+ request.stubs(:path_info).returns('')
376
+
377
+ strategy.options.issuer = 'example.com'
378
+
379
+ strategy.stubs(:access_token).raises(::SocketError.new('error'))
380
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
381
+ strategy.expects(:fail!)
382
+
383
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
384
+ id_token.stubs(:verify!).with(issuer: 'example.com', client_id: @identifier, nonce: nonce).returns(true)
385
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
386
+
387
+ strategy.callback_phase
388
+ end
389
+
390
+ def test_callback_phase_with_rack_oauth2_client_error
391
+ code = SecureRandom.hex(16)
392
+ state = SecureRandom.hex(16)
393
+ nonce = SecureRandom.hex(16)
394
+ request.stubs(:params).returns('code' => code, 'state' => state)
395
+ request.stubs(:path_info).returns('')
396
+
397
+ strategy.options.issuer = 'example.com'
398
+
399
+ strategy.stubs(:access_token).raises(::Rack::OAuth2::Client::Error.new('error', error: 'Unknown'))
400
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
401
+ strategy.expects(:fail!)
402
+
403
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
404
+ id_token.stubs(:verify!).with(issuer: 'example.com', client_id: @identifier, nonce: nonce).returns(true)
405
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
406
+
407
+ strategy.callback_phase
408
+ end
409
+
410
+ def test_info
411
+ info = strategy.info
412
+ assert_equal user_info.name, info[:name]
413
+ assert_equal user_info.email, info[:email]
414
+ assert_equal user_info.preferred_username, info[:nickname]
415
+ assert_equal user_info.given_name, info[:first_name]
416
+ assert_equal user_info.family_name, info[:last_name]
417
+ assert_equal user_info.gender, info[:gender]
418
+ assert_equal user_info.picture, info[:image]
419
+ assert_equal user_info.phone_number, info[:phone]
420
+ assert_equal({ website: user_info.website }, info[:urls])
421
+ end
422
+
423
+ def test_extra
424
+ assert_equal({ raw_info: user_info.as_json }, strategy.extra)
425
+ end
426
+
427
+ def test_credentials
428
+ strategy.options.issuer = 'example.com'
429
+ strategy.options.client_signing_alg = :RS256
430
+ strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
431
+
432
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
433
+ id_token.stubs(:verify!).returns(true)
434
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
435
+
436
+ access_token = stub('OpenIDConnect::AccessToken')
437
+ access_token.stubs(:access_token).returns(SecureRandom.hex(16))
438
+ access_token.stubs(:refresh_token).returns(SecureRandom.hex(16))
439
+ access_token.stubs(:expires_in).returns(Time.now)
440
+ access_token.stubs(:scope).returns('openidconnect')
441
+ access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
442
+
443
+ client.expects(:access_token!).returns(access_token)
444
+ access_token.expects(:refresh_token).returns(access_token.refresh_token)
445
+ access_token.expects(:expires_in).returns(access_token.expires_in)
446
+
447
+ assert_equal(
448
+ {
449
+ id_token: access_token.id_token,
450
+ token: access_token.access_token,
451
+ refresh_token: access_token.refresh_token,
452
+ expires_in: access_token.expires_in,
453
+ scope: access_token.scope
454
+ },
455
+ strategy.credentials
456
+ )
457
+ end
458
+
459
+ def test_option_send_nonce
460
+ strategy.options.client_options[:host] = 'foobar.com'
461
+
462
+ assert(strategy.authorize_uri =~ /nonce=/, 'URI must contain nonce')
463
+
464
+ strategy.options.send_nonce = false
465
+ assert(!(strategy.authorize_uri =~ /nonce=/), 'URI must not contain nonce')
466
+ end
467
+
468
+ def test_failure_endpoint_redirect
469
+ OmniAuth.config.stubs(:failure_raise_out_environments).returns([])
470
+ strategy.stubs(:env).returns({})
471
+ request.stubs(:params).returns('error' => 'access denied')
472
+
473
+ result = strategy.callback_phase
474
+
475
+ assert(result.is_a? Array)
476
+ assert(result[0] == 302, 'Redirect')
477
+ assert(result[1]["Location"] =~ /\/auth\/failure/)
478
+ end
479
+
480
+ def test_state
481
+ strategy.options.state = -> { 42 }
482
+
483
+ expected_redirect = /&state=42/
484
+ strategy.options.issuer = 'example.com'
485
+ strategy.options.client_options.host = 'example.com'
486
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
487
+ strategy.request_phase
488
+
489
+ session = { 'state' => 42 }
490
+ # this should succeed as the correct state is passed with the request
491
+ test_callback_phase(session, { 'state' => 42 })
492
+
493
+ # the following should fail because the wrong state is passed to the callback
494
+ code = SecureRandom.hex(16)
495
+ request.stubs(:params).returns('code' => code, 'state' => 43)
496
+ request.stubs(:path_info).returns('')
497
+
498
+ strategy.call!('rack.session' => session)
499
+ strategy.expects(:fail!)
500
+ strategy.callback_phase
501
+ end
502
+
503
+ def test_dynamic_state
504
+ # Stub request parameters
505
+ request.stubs(:path_info).returns('')
506
+ strategy.call!('rack.session' => { }, QUERY_STRING: { state: 'abc', client_id: '123' } )
507
+
508
+ strategy.options.state = lambda { |env|
509
+ # Get params from request, e.g. CGI.parse(env['QUERY_STRING'])
510
+ env[:QUERY_STRING][:state] + env[:QUERY_STRING][:client_id]
511
+ }
512
+
513
+ expected_redirect = /&state=abc123/
514
+ strategy.options.issuer = 'example.com'
515
+ strategy.options.client_options.host = 'example.com'
516
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
517
+ strategy.request_phase
518
+ end
519
+
520
+ def test_option_client_auth_method
521
+ state = SecureRandom.hex(16)
522
+ nonce = SecureRandom.hex(16)
523
+
524
+ opts = strategy.options.client_options
525
+ opts[:host] = 'foobar.com'
526
+ strategy.options.issuer = 'foobar.com'
527
+ strategy.options.client_auth_method = :not_basic
528
+ strategy.options.client_signing_alg = :RS256
529
+ strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
530
+
531
+ json_response = {
532
+ access_token: 'test_access_token',
533
+ id_token: File.read('test/fixtures/id_token.txt'),
534
+ token_type: 'Bearer',
535
+ }.to_json
536
+ success = Struct.new(:status, :body).new(200, json_response)
537
+
538
+ request.stubs(:path_info).returns('')
539
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
540
+
541
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
542
+ id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
543
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
544
+
545
+ HTTPClient.any_instance.stubs(:post).with(
546
+ "#{ opts.scheme }://#{ opts.host }:#{ opts.port }#{ opts.token_endpoint }",
547
+ { scope: 'openid', grant_type: :client_credentials, client_id: @identifier, client_secret: @secret },
548
+ {}
549
+ ).returns(success)
550
+
551
+ assert(strategy.send :access_token)
552
+ end
553
+
554
+ def test_public_key_with_jwks
555
+ strategy.options.client_signing_alg = :RS256
556
+ strategy.options.client_jwk_signing_key = File.read('./test/fixtures/jwks.json')
557
+
558
+ assert_equal JSON::JWK::Set, strategy.public_key.class
559
+ end
560
+
561
+ def test_public_key_with_jwk
562
+ strategy.options.client_signing_alg = :RS256
563
+ jwks_str = File.read('./test/fixtures/jwks.json')
564
+ jwks = JSON.parse(jwks_str)
565
+ jwk = jwks['keys'].first
566
+ strategy.options.client_jwk_signing_key = jwk.to_json
567
+
568
+ assert_equal JSON::JWK, strategy.public_key.class
569
+ end
570
+
571
+ def test_public_key_with_x509
572
+ strategy.options.client_signing_alg = :RS256
573
+ strategy.options.client_x509_signing_key = File.read('./test/fixtures/test.crt')
574
+ assert_equal OpenSSL::PKey::RSA, strategy.public_key.class
575
+ end
576
+
577
+ def test_public_key_with_hmac
578
+ strategy.options.client_options.secret = 'secret'
579
+ strategy.options.client_signing_alg = :HS256
580
+ assert_equal strategy.options.client_options.secret, strategy.public_key
581
+ end
582
+
583
+ def test_id_token_auth_hash
584
+ state = SecureRandom.hex(16)
585
+ nonce = SecureRandom.hex(16)
586
+ strategy.options.response_type = 'id_token'
587
+ strategy.options.issuer = 'example.com'
588
+
589
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
590
+ id_token.stubs(:verify!).returns(true)
591
+ id_token.stubs(:raw_attributes, :to_h).returns(
592
+ {
593
+ "iss": "http://server.example.com",
594
+ "sub": "248289761001",
595
+ "aud": "s6BhdRkqt3",
596
+ "nonce": "n-0S6_WzA2Mj",
597
+ "exp": 1311281970,
598
+ "iat": 1311280970,
599
+ }
600
+ )
601
+
602
+ request.stubs(:params).returns('state' => state, 'nounce' => nonce, 'id_token' => id_token)
603
+ request.stubs(:path_info).returns('')
604
+
605
+ strategy.stubs(:decode_id_token).returns(id_token)
606
+ strategy.stubs(:stored_state).returns(state)
607
+
608
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
609
+ strategy.callback_phase
610
+
611
+ auth_hash = strategy.send(:env)['omniauth.auth']
612
+ assert auth_hash.key?('provider')
613
+ assert auth_hash.key?('uid')
614
+ assert auth_hash.key?('info')
615
+ assert auth_hash.key?('extra')
616
+ assert auth_hash['extra'].key?('raw_info')
617
+ end
618
+ end
619
+ end
620
+ end