gitlab-omniauth-openid-connect 0.5.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cee603f7fbf49710ecee6e6953ca205feb9620c25dc9d865d7b44dda22a7b0dc
4
- data.tar.gz: 18ecc1ef7a21e86a2e2554d10d3a95dc2c9dcd26cf0a66509f931a62ce0b4e7d
3
+ metadata.gz: 37197f76441b711d0f9ecbc461b533298e827e0a0be5679994e7c2e72d930695
4
+ data.tar.gz: d854e863540d1132cd182988f909338b192e0655da0872f9b357d0a165a1a4c2
5
5
  SHA512:
6
- metadata.gz: 2959c9ee30ca4e8c84b57f578d142744fea140c94c60daafcefb83c6aabfb707610f47c9f1ae2186033bf98d992e799614c24760393a63ce03473a1fb4301e77
7
- data.tar.gz: 1fd6fb3c3d009d011ca4fd595756ea6d46d34d7ad8a0fc93d4921684f0e4cec92b1e20a4ecc1d49beaa28eff6731e02df616e2f7f99e3ec4419273a179aeb139
6
+ metadata.gz: 184378eed49019d8fe115ea54071cc17d97a9482ad16ae0fb5ad33e4985ee49ef29ad20c52d66a6e7a016bb14a28ced575f0b73d820e87e0663f234f66304183
7
+ data.tar.gz: 468a122b46e8a1e9fc62d380131500471d66d68285753334cf60b699c7e3d6e87ecd44b3d4f9ded43bf3bfb968bfe3403133b31cd6d0af456e180e90bc0cb979
data/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ # v0.9.0 (01.03.2022)
2
+
3
+ - [Add support for ES[256|384|512|256K] algorithms](https://gitlab.com/gitlab-org/gitlab-omniauth-openid-connect/-/merge_requests/17)
4
+
5
+ # v0.8.0 (07.16.2021)
6
+
7
+ - [Add `jwt_secret_base64` option to support binary secrets](https://gitlab.com/gitlab-org/gitlab-omniauth-openid-connect/-/merge_requests/12)
8
+
9
+ # v0.7.0 (07.16.2021)
10
+
11
+ - [Add `jwt_secret` option to support Keycloak private key](https://gitlab.com/gitlab-org/gitlab-omniauth-openid-connect/-/merge_requests/10)
12
+
13
+ # v0.6.0 (07.08.2021)
14
+
15
+ - [Support verification of HS256-signed JWTs](https://gitlab.com/gitlab-org/gitlab-omniauth-openid-connect/-/merge_requests/8)
16
+
1
17
  # v0.5.0 (05.07.2021)
2
18
 
3
19
  - [Add email_verified field to info dict](https://gitlab.com/gitlab-org/gitlab-omniauth-openid-connect/-/merge_requests/7)
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,40 @@
1
+ ## Developer Certificate of Origin and License
2
+
3
+ By contributing to GitLab B.V., you accept and agree to the following terms and
4
+ conditions for your present and future contributions submitted to GitLab B.V.
5
+ Except for the license granted herein to GitLab B.V. and recipients of software
6
+ distributed by GitLab B.V., you reserve all right, title, and interest in and to
7
+ your Contributions.
8
+
9
+ All contributions are subject to the Developer Certificate of Origin and license set out at [docs.gitlab.com/ce/legal/developer_certificate_of_origin](https://docs.gitlab.com/ce/legal/developer_certificate_of_origin).
10
+
11
+ _This notice should stay as the first item in the CONTRIBUTING.md file._
12
+
13
+ ## Code of conduct
14
+
15
+ As contributors and maintainers of this project, we pledge to respect all people
16
+ who contribute through reporting issues, posting feature requests, updating
17
+ documentation, submitting pull requests or patches, and other activities.
18
+
19
+ We are committed to making participation in this project a harassment-free
20
+ experience for everyone, regardless of level of experience, gender, gender
21
+ identity and expression, sexual orientation, disability, personal appearance,
22
+ body size, race, ethnicity, age, or religion.
23
+
24
+ Examples of unacceptable behavior by participants include the use of sexual
25
+ language or imagery, derogatory comments or personal attacks, trolling, public
26
+ or private harassment, insults, or other unprofessional conduct.
27
+
28
+ Project maintainers have the right and responsibility to remove, edit, or reject
29
+ comments, commits, code, wiki edits, issues, and other contributions that are
30
+ not aligned to this Code of Conduct. Project maintainers who do not follow the
31
+ Code of Conduct may be removed from the project team.
32
+
33
+ This code of conduct applies both within project spaces and in public spaces
34
+ when an individual is representing the project or its community.
35
+
36
+ Instances of abusive, harassing, or otherwise unacceptable behavior can be
37
+ reported by emailing contact@gitlab.com.
38
+
39
+ This Code of Conduct is adapted from the [Contributor Covenant](https://contributor-covenant.org), version 1.1.0,
40
+ available at [https://contributor-covenant.org/version/1/1/0/](https://contributor-covenant.org/version/1/1/0/).
data/README.md CHANGED
@@ -66,6 +66,8 @@ config.omniauth :openid_connect, {
66
66
  | post_logout_redirect_uri | The logout redirect uri to use per the [session management draft](https://openid.net/specs/openid-connect-session-1_0.html) | no | empty | https://myapp.com/logout/callback |
67
67
  | uid_field | The field of the user info response to be used as a unique id | no | 'sub' | "sub", "preferred_username" |
68
68
  | client_options | A hash of client options detailed in its own section | yes | | |
69
+ | jwt_secret | For HMAC with SHA2 (e.g. HS256) signing algorithms, specify the secret used to sign the JWT token. Defaults to the OAuth2 client secret if not specified. For secrets in binary, use `jwt_secret_base64`. | no | client_options.secret | "mysecret" |
70
+ | jwt_secret_base64 | For HMAC with SHA2 (e.g. HS256) signing algorithms, specify the base64-encoded secret used to sign the JWT token. Defaults to the OAuth2 client secret if not specified. `jwt_secret` takes precedence. | no | client_options.secret | "bXlzZWNyZXQ=\n"
69
71
 
70
72
  ### Client Config Options
71
73
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OmniAuth
4
4
  module OpenIDConnect
5
- VERSION = '0.5.0'
5
+ VERSION = '0.9.0'
6
6
  end
7
7
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'addressable/uri'
4
+ require 'base64'
4
5
  require 'timeout'
5
6
  require 'net/http'
6
7
  require 'open-uri'
@@ -36,7 +37,9 @@ module OmniAuth
36
37
 
37
38
  option :issuer
38
39
  option :discovery, false
39
- option :client_signing_alg
40
+ option :client_signing_alg # Deprecated since we detect what is used to sign the JWT
41
+ option :jwt_secret
42
+ option :jwt_secret_base64
40
43
  option :client_jwk_signing_key
41
44
  option :client_x509_signing_key
42
45
  option :scope, [:openid]
@@ -181,16 +184,28 @@ module OmniAuth
181
184
  @public_key ||= begin
182
185
  if options.discovery
183
186
  config.jwks
184
- elsif key_or_secret
185
- key_or_secret
187
+ elsif configured_public_key
188
+ configured_public_key
186
189
  elsif client_options.jwks_uri
187
190
  fetch_key
188
191
  end
189
192
  end
190
193
  end
191
194
 
195
+ # Some OpenID providers use the OAuth2 client secret as the shared secret, but
196
+ # Keycloak uses a separate key that's stored inside the database.
197
+ def secret
198
+ options.jwt_secret || base64_decoded_jwt_secret || client_options.secret
199
+ end
200
+
192
201
  private
193
202
 
203
+ def base64_decoded_jwt_secret
204
+ return unless options.jwt_secret_base64
205
+
206
+ Base64.decode64(options.jwt_secret_base64)
207
+ end
208
+
194
209
  def fetch_key
195
210
  @fetch_key ||= parse_jwk_key(::OpenIDConnect.http_client.get_content(client_options.jwks_uri))
196
211
  end
@@ -236,31 +251,55 @@ module OmniAuth
236
251
  @access_token
237
252
  end
238
253
 
254
+ # Unlike ::OpenIDConnect::ResponseObject::IdToken.decode, this
255
+ # method splits the decoding and verification of JWT into two
256
+ # steps. First, we decode the JWT without verifying it to
257
+ # determine the algorithm used to sign. Then, we verify it using
258
+ # the appropriate public key (e.g. if algorithm is RS256) or
259
+ # shared secret (e.g. if algorithm is HS256). This works around a
260
+ # limitation in the openid_connect gem:
261
+ # https://github.com/nov/openid_connect/issues/61
239
262
  def decode_id_token(id_token)
240
- decode!(id_token, public_key)
263
+ decoded = JSON::JWT.decode(id_token, :skip_verification)
264
+ algorithm = decoded.algorithm.to_sym
265
+
266
+ keyset =
267
+ case algorithm
268
+ when :ES256, :ES384, :ES512, :ES256K, :RS256, :RS384, :RS512
269
+ public_key
270
+ when :HS256, :HS384, :HS512
271
+ secret
272
+ end
273
+
274
+ decoded.verify!(keyset)
275
+ ::OpenIDConnect::ResponseObject::IdToken.new(decoded)
241
276
  rescue JSON::JWK::Set::KidNotFound
242
- # Either the JWT doesn't have kid specified or the set of keys doesn't
243
- # have a matching key. Since we can't tell the first case from the second,
244
- # try each key individually to see if one works.
277
+ # If the JWT has a key ID (kid), then we know that the set of
278
+ # keys supplied doesn't contain the one we want, and we're
279
+ # done. However, if there is no kid, then we try each key
280
+ # individually to see if one works:
245
281
  # https://github.com/nov/json-jwt/pull/92#issuecomment-824654949
246
- decoded = decode_with_each_key!(id_token)
282
+ raise if decoded&.header&.key?('kid')
283
+
284
+ decoded = decode_with_each_key!(id_token, keyset)
247
285
 
248
286
  raise unless decoded
249
287
 
250
288
  decoded
289
+
251
290
  end
252
291
 
253
292
  def decode!(id_token, key)
254
293
  ::OpenIDConnect::ResponseObject::IdToken.decode(id_token, key)
255
294
  end
256
295
 
257
- def decode_with_each_key!(id_token)
258
- return unless public_key.is_a?(JSON::JWK::Set)
296
+ def decode_with_each_key!(id_token, keyset)
297
+ return unless keyset.is_a?(JSON::JWK::Set)
259
298
 
260
- public_key.each do |key|
299
+ keyset.each do |key|
261
300
  begin
262
301
  decoded = decode!(id_token, key)
263
- rescue JSON::JWS::VerificationFailed
302
+ rescue JSON::JWS::VerificationFailed, JSON::JWS::UnexpectedAlgorithm, JSON::JWS::UnknownAlgorithm
264
303
  next
265
304
  end
266
305
 
@@ -303,18 +342,14 @@ module OmniAuth
303
342
  super
304
343
  end
305
344
 
306
- def key_or_secret
307
- @key_or_secret ||=
308
- case options.client_signing_alg&.to_sym
309
- when :HS256, :HS384, :HS512
310
- client_options.secret
311
- when :RS256, :RS384, :RS512
312
- if options.client_jwk_signing_key
313
- parse_jwk_key(options.client_jwk_signing_key)
314
- elsif options.client_x509_signing_key
315
- parse_x509_key(options.client_x509_signing_key)
316
- end
345
+ def configured_public_key
346
+ @configured_public_key ||= begin
347
+ if options.client_jwk_signing_key
348
+ parse_jwk_key(options.client_jwk_signing_key)
349
+ elsif options.client_x509_signing_key
350
+ parse_x509_key(options.client_x509_signing_key)
317
351
  end
352
+ end
318
353
  end
319
354
 
320
355
  def parse_x509_key(key)
@@ -168,7 +168,7 @@ module OmniAuth
168
168
 
169
169
  strategy.options.issuer = 'example.com'
170
170
  strategy.options.client_signing_alg = :RS256
171
- strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
171
+ strategy.options.client_jwk_signing_key = jwks.to_s
172
172
  strategy.options.response_type = 'code'
173
173
 
174
174
  strategy.unstub(:user_info)
@@ -177,7 +177,7 @@ module OmniAuth
177
177
  access_token.stubs(:refresh_token)
178
178
  access_token.stubs(:expires_in)
179
179
  access_token.stubs(:scope)
180
- access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
180
+ access_token.stubs(:id_token).returns(jwt.to_s)
181
181
  client.expects(:access_token!).at_least_once.returns(access_token)
182
182
  access_token.expects(:userinfo!).returns(user_info)
183
183
 
@@ -192,14 +192,13 @@ module OmniAuth
192
192
  end
193
193
 
194
194
  def test_callback_phase_with_id_token
195
- code = SecureRandom.hex(16)
196
195
  state = SecureRandom.hex(16)
197
- request.stubs(:params).returns('id_token' => code, 'state' => state)
196
+ request.stubs(:params).returns('id_token' => jwt.to_s, 'state' => state)
198
197
  request.stubs(:path_info).returns('')
199
198
 
200
199
  strategy.options.issuer = 'example.com'
201
200
  strategy.options.client_signing_alg = :RS256
202
- strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
201
+ strategy.options.client_jwk_signing_key = jwks.to_json
203
202
  strategy.options.response_type = 'id_token'
204
203
 
205
204
  strategy.unstub(:user_info)
@@ -208,7 +207,7 @@ module OmniAuth
208
207
  access_token.stubs(:refresh_token)
209
208
  access_token.stubs(:expires_in)
210
209
  access_token.stubs(:scope)
211
- access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
210
+ access_token.stubs(:id_token).returns(jwt.to_s)
212
211
 
213
212
  id_token = stub('OpenIDConnect::ResponseObject::IdToken')
214
213
  id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
@@ -221,14 +220,12 @@ module OmniAuth
221
220
  end
222
221
 
223
222
  def test_callback_phase_with_id_token_no_kid
224
- rsa_private = OpenSSL::PKey::RSA.generate(2048)
225
223
  other_rsa_private = OpenSSL::PKey::RSA.generate(2048)
226
224
 
227
- key = JSON::JWK.new(rsa_private)
225
+ key = JSON::JWK.new(private_key)
228
226
  other_key = JSON::JWK.new(other_rsa_private)
229
- token = JSON::JWT.new(payload).sign(rsa_private, :RS256).to_s
230
227
  state = SecureRandom.hex(16)
231
- request.stubs(:params).returns('id_token' => token, 'state' => state)
228
+ request.stubs(:params).returns('id_token' => jwt.to_s, 'state' => state)
232
229
  request.stubs(:path_info).returns('')
233
230
 
234
231
  strategy.options.issuer = issuer
@@ -241,6 +238,93 @@ module OmniAuth
241
238
  strategy.callback_phase
242
239
  end
243
240
 
241
+ def test_callback_phase_with_id_token_with_kid
242
+ other_rsa_private = OpenSSL::PKey::RSA.generate(2048)
243
+
244
+ key = JSON::JWK.new(private_key)
245
+ other_key = JSON::JWK.new(other_rsa_private)
246
+ state = SecureRandom.hex(16)
247
+ jwt_with_kid = JSON::JWT.new(payload).sign(key, :RS256)
248
+ request.stubs(:params).returns('id_token' => jwt_with_kid.to_s, 'state' => state)
249
+ request.stubs(:path_info).returns('')
250
+
251
+ strategy.options.issuer = issuer
252
+ strategy.options.client_signing_alg = :RS256
253
+ strategy.options.client_jwk_signing_key = { 'keys' => [other_key, key] }.to_json
254
+ strategy.options.response_type = 'id_token'
255
+
256
+ strategy.unstub(:user_info)
257
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
258
+ strategy.callback_phase
259
+ end
260
+
261
+ def test_callback_phase_with_id_token_with_kid_and_no_matching_kid
262
+ other_rsa_private = OpenSSL::PKey::RSA.generate(2048)
263
+
264
+ key = JSON::JWK.new(private_key)
265
+ other_key = JSON::JWK.new(other_rsa_private)
266
+ state = SecureRandom.hex(16)
267
+ jwt_with_kid = JSON::JWT.new(payload).sign(key, :RS256)
268
+ request.stubs(:params).returns('id_token' => jwt_with_kid.to_s, 'state' => state)
269
+ request.stubs(:path_info).returns('')
270
+
271
+ strategy.options.issuer = issuer
272
+ strategy.options.client_signing_alg = :RS256
273
+ # We use private_key here instead of the wrapped key, which contains a kid
274
+ strategy.options.client_jwk_signing_key = { 'keys' => [other_key, private_key] }.to_json
275
+ strategy.options.response_type = 'id_token'
276
+
277
+ strategy.unstub(:user_info)
278
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
279
+
280
+ assert_raises JSON::JWK::Set::KidNotFound do
281
+ strategy.callback_phase
282
+ end
283
+ end
284
+
285
+ def test_callback_phase_with_id_token_with_hs256
286
+ state = SecureRandom.hex(16)
287
+ request.stubs(:params).returns('id_token' => jwt_with_hs256.to_s, 'state' => state)
288
+ request.stubs(:path_info).returns('')
289
+
290
+ strategy.options.issuer = issuer
291
+ strategy.options.client_options.secret = hmac_secret
292
+ strategy.options.client_signing_alg = :HS256
293
+ strategy.options.response_type = 'id_token'
294
+
295
+ strategy.unstub(:user_info)
296
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
297
+ strategy.callback_phase
298
+ end
299
+
300
+ def test_callback_phase_with_hs256_jwt_secret
301
+ state = SecureRandom.hex(16)
302
+ request.stubs(:params).returns('id_token' => jwt_with_hs256.to_s, 'state' => state)
303
+ request.stubs(:path_info).returns('')
304
+
305
+ strategy.options.issuer = issuer
306
+ strategy.options.jwt_secret = hmac_secret
307
+ strategy.options.response_type = 'id_token'
308
+
309
+ strategy.unstub(:user_info)
310
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
311
+ strategy.callback_phase
312
+ end
313
+
314
+ def test_callback_phase_with_hs256_base64_jwt_secret
315
+ state = SecureRandom.hex(16)
316
+ request.stubs(:params).returns('id_token' => jwt_with_hs256.to_s, 'state' => state)
317
+ request.stubs(:path_info).returns('')
318
+
319
+ strategy.options.issuer = issuer
320
+ strategy.options.jwt_secret_base64 = Base64.encode64(hmac_secret)
321
+ strategy.options.response_type = 'id_token'
322
+
323
+ strategy.unstub(:user_info)
324
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
325
+ strategy.callback_phase
326
+ end
327
+
244
328
  def test_callback_phase_with_id_token_no_matching_key
245
329
  rsa_private = OpenSSL::PKey::RSA.generate(2048)
246
330
  other_rsa_private = OpenSSL::PKey::RSA.generate(2048)
@@ -266,11 +350,9 @@ module OmniAuth
266
350
  end
267
351
 
268
352
  def test_callback_phase_with_discovery
269
- code = SecureRandom.hex(16)
270
353
  state = SecureRandom.hex(16)
271
- jwks = JSON::JWK::Set.new(JSON.parse(File.read('test/fixtures/jwks.json'))['keys'])
272
354
 
273
- request.stubs(:params).returns('code' => code, 'state' => state)
355
+ request.stubs(:params).returns('code' => jwt.to_s, 'state' => state)
274
356
  request.stubs(:path_info).returns('')
275
357
 
276
358
  strategy.options.client_options.host = 'example.com'
@@ -285,7 +367,7 @@ module OmniAuth
285
367
  config.stubs(:token_endpoint).returns('https://example.com/token')
286
368
  config.stubs(:userinfo_endpoint).returns('https://example.com/userinfo')
287
369
  config.stubs(:jwks_uri).returns('https://example.com/jwks')
288
- config.stubs(:jwks).returns(jwks)
370
+ config.stubs(:jwks).returns(JSON::JWK::Set.new(jwks['keys']))
289
371
 
290
372
  ::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
291
373
 
@@ -300,7 +382,7 @@ module OmniAuth
300
382
  access_token.stubs(:refresh_token)
301
383
  access_token.stubs(:expires_in)
302
384
  access_token.stubs(:scope)
303
- access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
385
+ access_token.stubs(:id_token).returns(jwt.to_s)
304
386
  client.expects(:access_token!).at_least_once.returns(access_token)
305
387
  access_token.expects(:userinfo!).returns(user_info)
306
388
 
@@ -309,9 +391,9 @@ module OmniAuth
309
391
  end
310
392
 
311
393
  def test_callback_phase_with_jwks_uri
312
- code = SecureRandom.hex(16)
394
+ id_token = jwt.to_s
313
395
  state = SecureRandom.hex(16)
314
- request.stubs(:params).returns('id_token' => code, 'state' => state)
396
+ request.stubs(:params).returns('id_token' => id_token, 'state' => state)
315
397
  request.stubs(:path_info).returns('')
316
398
 
317
399
  strategy.options.issuer = 'example.com'
@@ -321,7 +403,7 @@ module OmniAuth
321
403
  HTTPClient
322
404
  .any_instance.stubs(:get_content)
323
405
  .with(strategy.options.client_options.jwks_uri)
324
- .returns(File.read('test/fixtures/jwks.json'))
406
+ .returns(jwks.to_json)
325
407
 
326
408
  strategy.unstub(:user_info)
327
409
  access_token = stub('OpenIDConnect::AccessToken')
@@ -329,7 +411,7 @@ module OmniAuth
329
411
  access_token.stubs(:refresh_token)
330
412
  access_token.stubs(:expires_in)
331
413
  access_token.stubs(:scope)
332
- access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
414
+ access_token.stubs(:id_token).returns(id_token)
333
415
 
334
416
  id_token = stub('OpenIDConnect::ResponseObject::IdToken')
335
417
  id_token.stubs(:raw_attributes).returns('sub' => 'sub', 'name' => 'name', 'email' => 'email')
@@ -494,7 +576,7 @@ module OmniAuth
494
576
  def test_credentials
495
577
  strategy.options.issuer = 'example.com'
496
578
  strategy.options.client_signing_alg = :RS256
497
- strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
579
+ strategy.options.client_jwk_signing_key = jwks.to_json
498
580
 
499
581
  id_token = stub('OpenIDConnect::ResponseObject::IdToken')
500
582
  id_token.stubs(:verify!).returns(true)
@@ -505,7 +587,7 @@ module OmniAuth
505
587
  access_token.stubs(:refresh_token).returns(SecureRandom.hex(16))
506
588
  access_token.stubs(:expires_in).returns(Time.now)
507
589
  access_token.stubs(:scope).returns('openidconnect')
508
- access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
590
+ access_token.stubs(:id_token).returns(jwt.to_s)
509
591
 
510
592
  client.expects(:access_token!).returns(access_token)
511
593
  access_token.expects(:refresh_token).returns(access_token.refresh_token)
@@ -592,11 +674,11 @@ module OmniAuth
592
674
  strategy.options.issuer = 'foobar.com'
593
675
  strategy.options.client_auth_method = :not_basic
594
676
  strategy.options.client_signing_alg = :RS256
595
- strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
677
+ strategy.options.client_jwk_signing_key = jwks.to_json
596
678
 
597
679
  json_response = {
598
680
  access_token: 'test_access_token',
599
- id_token: File.read('test/fixtures/id_token.txt'),
681
+ id_token: jwt.to_s,
600
682
  token_type: 'Bearer',
601
683
  }.to_json
602
684
  success = Struct.new(:status, :body).new(200, json_response)
@@ -619,16 +701,14 @@ module OmniAuth
619
701
 
620
702
  def test_public_key_with_jwks
621
703
  strategy.options.client_signing_alg = :RS256
622
- strategy.options.client_jwk_signing_key = File.read('./test/fixtures/jwks.json')
704
+ strategy.options.client_jwk_signing_key = jwks.to_json
623
705
 
624
706
  assert_equal JSON::JWK::Set, strategy.public_key.class
625
707
  end
626
708
 
627
709
  def test_public_key_with_jwk
628
710
  strategy.options.client_signing_alg = :RS256
629
- jwks_str = File.read('./test/fixtures/jwks.json')
630
- jwks = JSON.parse(jwks_str)
631
- jwk = jwks['keys'].first
711
+ jwk = jwks[:keys].first
632
712
  strategy.options.client_jwk_signing_key = jwk.to_json
633
713
 
634
714
  assert_equal JSON::JWK, strategy.public_key.class
@@ -640,10 +720,10 @@ module OmniAuth
640
720
  assert_equal OpenSSL::PKey::RSA, strategy.public_key.class
641
721
  end
642
722
 
643
- def test_public_key_with_hmac
723
+ def test_secret_with_hmac
644
724
  strategy.options.client_options.secret = 'secret'
645
725
  strategy.options.client_signing_alg = :HS256
646
- assert_equal strategy.options.client_options.secret, strategy.public_key
726
+ assert_equal strategy.options.client_options.secret, strategy.secret
647
727
  end
648
728
 
649
729
  def test_id_token_auth_hash
@@ -653,16 +733,7 @@ module OmniAuth
653
733
 
654
734
  id_token = stub('OpenIDConnect::ResponseObject::IdToken')
655
735
  id_token.stubs(:verify!).returns(true)
656
- id_token.stubs(:raw_attributes, :to_h).returns(
657
- {
658
- "iss": "http://server.example.com",
659
- "sub": "248289761001",
660
- "aud": "s6BhdRkqt3",
661
- "nonce": "n-0S6_WzA2Mj",
662
- "exp": 1311281970,
663
- "iat": 1311280970,
664
- }
665
- )
736
+ id_token.stubs(:raw_attributes, :to_h).returns(payload)
666
737
 
667
738
  request.stubs(:params).returns('state' => state, 'nounce' => nonce, 'id_token' => id_token)
668
739
  request.stubs(:path_info).returns('')
@@ -27,6 +27,30 @@ class StrategyTestCase < MiniTest::Test
27
27
  }
28
28
  end
29
29
 
30
+ def private_key
31
+ @private_key ||= OpenSSL::PKey::RSA.generate(512)
32
+ end
33
+
34
+ def jwt
35
+ @jwt ||= JSON::JWT.new(payload).sign(private_key, :RS256)
36
+ end
37
+
38
+ def hmac_secret
39
+ @hmac_secret ||= SecureRandom.hex(16)
40
+ end
41
+
42
+ def jwt_with_hs256
43
+ @jwt_with_hs256 ||= JSON::JWT.new(payload).sign(hmac_secret, :HS256)
44
+ end
45
+
46
+ def jwks
47
+ @jwks ||= begin
48
+ key = JSON::JWK.new(private_key)
49
+ keyset = JSON::JWK::Set.new(key)
50
+ { keys: keyset }
51
+ end
52
+ end
53
+
30
54
  def user_info
31
55
  @user_info ||= OpenIDConnect::ResponseObject::UserInfo.new(
32
56
  sub: SecureRandom.hex(16),
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-omniauth-openid-connect
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Bohn
8
8
  - Ilya Shcherbinin
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-05-07 00:00:00.000000000 Z
12
+ date: 2022-01-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: addressable
@@ -209,6 +209,7 @@ files:
209
209
  - ".rubocop.yml"
210
210
  - ".travis.yml"
211
211
  - CHANGELOG.md
212
+ - CONTRIBUTING.md
212
213
  - Gemfile
213
214
  - Guardfile
214
215
  - LICENSE.txt
@@ -220,7 +221,6 @@ files:
220
221
  - lib/omniauth/openid_connect/version.rb
221
222
  - lib/omniauth/strategies/openid_connect.rb
222
223
  - lib/omniauth_openid_connect.rb
223
- - test/fixtures/id_token.txt
224
224
  - test/fixtures/jwks.json
225
225
  - test/fixtures/test.crt
226
226
  - test/lib/omniauth/strategies/openid_connect_test.rb
@@ -230,7 +230,7 @@ homepage: https://gitlab.com/gitlab-org/gitlab-omniauth-openid-connect
230
230
  licenses:
231
231
  - MIT
232
232
  metadata: {}
233
- post_install_message:
233
+ post_install_message:
234
234
  rdoc_options: []
235
235
  require_paths:
236
236
  - lib
@@ -245,12 +245,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
245
245
  - !ruby/object:Gem::Version
246
246
  version: '0'
247
247
  requirements: []
248
- rubygems_version: 3.1.4
249
- signing_key:
248
+ rubygems_version: 3.2.28
249
+ signing_key:
250
250
  specification_version: 4
251
251
  summary: OpenID Connect Strategy for OmniAuth
252
252
  test_files:
253
- - test/fixtures/id_token.txt
254
253
  - test/fixtures/jwks.json
255
254
  - test/fixtures/test.crt
256
255
  - test/lib/omniauth/strategies/openid_connect_test.rb
@@ -1 +0,0 @@
1
- eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6qJp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJNqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7TpdQyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoSK5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg