jwt 2.3.0 → 2.5.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +8 -0
  3. data/.github/workflows/coverage.yml +27 -0
  4. data/.github/workflows/test.yml +15 -22
  5. data/.gitignore +2 -0
  6. data/.reek.yml +22 -0
  7. data/.rubocop.yml +17 -47
  8. data/.sourcelevel.yml +3 -4
  9. data/AUTHORS +60 -53
  10. data/Appraisals +3 -0
  11. data/CHANGELOG.md +47 -0
  12. data/CODE_OF_CONDUCT.md +84 -0
  13. data/CONTRIBUTING.md +99 -0
  14. data/Gemfile +3 -1
  15. data/README.md +114 -34
  16. data/Rakefile +2 -0
  17. data/lib/jwt/algos/ecdsa.rb +37 -8
  18. data/lib/jwt/algos/eddsa.rb +5 -0
  19. data/lib/jwt/algos/hmac.rb +2 -0
  20. data/lib/jwt/algos/none.rb +2 -0
  21. data/lib/jwt/algos/ps.rb +3 -3
  22. data/lib/jwt/algos/rsa.rb +4 -1
  23. data/lib/jwt/algos/unsupported.rb +2 -0
  24. data/lib/jwt/claims_validator.rb +3 -1
  25. data/lib/jwt/configuration/container.rb +21 -0
  26. data/lib/jwt/configuration/decode_configuration.rb +46 -0
  27. data/lib/jwt/configuration/jwk_configuration.rb +27 -0
  28. data/lib/jwt/configuration.rb +15 -0
  29. data/lib/jwt/decode.rb +42 -8
  30. data/lib/jwt/encode.rb +6 -6
  31. data/lib/jwt/error.rb +1 -0
  32. data/lib/jwt/jwk/ec.rb +92 -43
  33. data/lib/jwt/jwk/hmac.rb +19 -10
  34. data/lib/jwt/jwk/key_base.rb +23 -6
  35. data/lib/jwt/jwk/key_finder.rb +1 -1
  36. data/lib/jwt/jwk/kid_as_key_digest.rb +15 -0
  37. data/lib/jwt/jwk/rsa.rb +54 -31
  38. data/lib/jwt/jwk/thumbprint.rb +26 -0
  39. data/lib/jwt/jwk.rb +1 -0
  40. data/lib/jwt/security_utils.rb +2 -0
  41. data/lib/jwt/signature.rb +3 -7
  42. data/lib/jwt/verify.rb +10 -2
  43. data/lib/jwt/version.rb +6 -2
  44. data/lib/jwt/x5c_key_finder.rb +55 -0
  45. data/lib/jwt.rb +5 -4
  46. data/ruby-jwt.gemspec +6 -3
  47. metadata +31 -7
  48. data/.rubocop_todo.yml +0 -185
  49. data/lib/jwt/default_options.rb +0 -16
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,99 @@
1
+ # Contributing to [ruby-jwt](https://github.com/jwt/ruby-jwt)
2
+
3
+ ## Forking the project
4
+
5
+ Fork the project on GitHub and clone your own fork. Instuctions on forking can be found from the [GitHub Docs](https://docs.github.com/en/get-started/quickstart/fork-a-repo)
6
+
7
+ ```
8
+ git clone git@github.com:you/ruby-jwt.git
9
+ cd ruby-jwt
10
+ git remote add upstream https://github.com/jwt/ruby-jwt
11
+ ```
12
+
13
+ ## Create a branch for your implementation
14
+
15
+ Make sure you have the latest upstream master branch of the project.
16
+
17
+ ```
18
+ git fetch --all
19
+ git checkout master
20
+ git rebase upstream/master
21
+ git push origin master
22
+ git checkout -b fix-a-little-problem
23
+ ```
24
+
25
+ ## Running the tests and linter
26
+
27
+ Before you start with your implementation make sure you are able to get a succesful test run with the current revision.
28
+
29
+ The tests are written with rspec and [Appraisal](https://github.com/thoughtbot/appraisal) is used to ensure compatibility with 3rd party dependencies providing cryptographic features.
30
+
31
+ [Rubocop](https://github.com/rubocop/rubocop) is used to enforce the Ruby style.
32
+
33
+ To run the complete set of tests and linter run the following
34
+
35
+ ```bash
36
+ bundle install
37
+ bundle exec appraisal rake test
38
+ bundle exec rubocop
39
+ ```
40
+
41
+ ## Implement your feature
42
+
43
+ Implement tests and your change. Don't be shy adding a little something in the [README](README.md).
44
+ Add a short description of the change in either the `Features` or `Fixes` section in the [CHANGELOG](CHANGELOG.md) file.
45
+
46
+ The form of the row (You need to return to the row when you know the pull request id)
47
+ ```
48
+ - Fix a little problem [#123](https://github.com/jwt/ruby-jwt/pull/123) - [@you](https://github.com/you).
49
+ ```
50
+
51
+ ## Push your branch and create a pull request
52
+
53
+ Before pushing make sure the tests pass and RuboCop is happy.
54
+
55
+ ```
56
+ bundle exec appraisal rake test
57
+ bundle exec rubocop
58
+ git push origin fix-a-little-problem
59
+ ```
60
+
61
+ Make a new pull request on the [ruby-jwt project](https://github.com/jwt/ruby-jwt/pulls) with a description what the change is about.
62
+
63
+ ## Update the CHANGELOG, again
64
+
65
+ Update the [CHANGELOG](CHANGELOG.md) with the pull request id from the previous step.
66
+
67
+ You can ammend the previous commit with the updated changelog change and force push your branch. The PR will get automatically updated.
68
+
69
+ ```
70
+ git add CHANGELOG.md
71
+ git commit --amend --no-edit
72
+ git push origin fix-a-little-problem -f
73
+ ```
74
+
75
+ ## Keep an eye on your pull request
76
+
77
+ A maintainer will review and probably merge you changes when time allows, be patient.
78
+
79
+ ## Keeping your branch up-to-date
80
+
81
+ It's recommended that you keep your branch up-to-date by rebasing to the upstream master.
82
+
83
+ ```
84
+ git fetch upstream
85
+ git checkout fix-a-little-problem
86
+ git rebase upstream/master
87
+ git push origin fix-a-little-problem -f
88
+ ```
89
+
90
+ # Releasing a new version
91
+
92
+ The version is using the [Semantic Versioning](http://semver.org/) and the version is located in the [version.rb](lib/jwt/version.rb) file.
93
+ Also update the [CHANGELOG](CHANGELOG.md) to reflect the upcoming version release.
94
+
95
+ ```bash
96
+ rake release
97
+ ```
98
+
99
+ **If you want a release cut with your PR, please include a version bump according to **
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
4
6
 
5
- gem 'rubocop', '~> 0.52.0' # Same as codeclimate default
7
+ gem 'rubocop', '~> 1.23.0' # Keep .codeclimate.yml channel in sync with this one
data/README.md CHANGED
@@ -12,10 +12,12 @@ A ruby implementation of the [RFC 7519 OAuth JSON Web Token (JWT)](https://tools
12
12
  If you have further questions related to development or usage, join us: [ruby-jwt google group](https://groups.google.com/forum/#!forum/ruby-jwt).
13
13
 
14
14
  ## Announcements
15
-
15
+ * Ruby 2.4 support was dropped in version 2.4.0
16
16
  * Ruby 1.9.3 support was dropped at December 31st, 2016.
17
17
  * Version 1.5.3 yanked. See: [#132](https://github.com/jwt/ruby-jwt/issues/132) and [#133](https://github.com/jwt/ruby-jwt/issues/133)
18
18
 
19
+ See [CHANGELOG.md](CHANGELOG.md) for a complete set of changes.
20
+
19
21
  ## Sponsors
20
22
 
21
23
  |Logo|Message|
@@ -42,7 +44,7 @@ The JWT spec supports NONE, HMAC, RSASSA, ECDSA and RSASSA-PSS algorithms for cr
42
44
 
43
45
  See: [ JSON Web Algorithms (JWA) 3.1. "alg" (Algorithm) Header Parameter Values for JWS](https://tools.ietf.org/html/rfc7518#section-3.1)
44
46
 
45
- **NONE**
47
+ ### **NONE**
46
48
 
47
49
  * none - unsigned token
48
50
 
@@ -68,7 +70,7 @@ decoded_token = JWT.decode token, nil, false
68
70
  puts decoded_token
69
71
  ```
70
72
 
71
- **HMAC**
73
+ ### **HMAC**
72
74
 
73
75
  * HS256 - HMAC using SHA-256 hash algorithm
74
76
  * HS512256 - HMAC using SHA-512-256 hash algorithm (only available with RbNaCl; see note below)
@@ -100,7 +102,7 @@ Note: If [RbNaCl](https://github.com/cryptosphere/rbnacl) is loadable, ruby-jwt
100
102
  [libsodium](https://github.com/jedisct1/libsodium), it can be installed
101
103
  on MacOS with `brew install libsodium`.
102
104
 
103
- **RSA**
105
+ ### **RSA**
104
106
 
105
107
  * RS256 - RSA using SHA-256 hash algorithm
106
108
  * RS384 - RSA using SHA-384 hash algorithm
@@ -125,24 +127,22 @@ decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'RS256' }
125
127
  puts decoded_token
126
128
  ```
127
129
 
128
- **ECDSA**
130
+ ### **ECDSA**
129
131
 
130
132
  * ES256 - ECDSA using P-256 and SHA-256
131
133
  * ES384 - ECDSA using P-384 and SHA-384
132
134
  * ES512 - ECDSA using P-521 and SHA-512
135
+ * ES256K - ECDSA using P-256K and SHA-256
133
136
 
134
137
  ```ruby
135
- ecdsa_key = OpenSSL::PKey::EC.new 'prime256v1'
136
- ecdsa_key.generate_key
137
- ecdsa_public = OpenSSL::PKey::EC.new ecdsa_key
138
- ecdsa_public.private_key = nil
138
+ ecdsa_key = OpenSSL::PKey::EC.generate('prime256v1')
139
139
 
140
140
  token = JWT.encode payload, ecdsa_key, 'ES256'
141
141
 
142
142
  # eyJhbGciOiJFUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.AlLW--kaF7EX1NMX9WJRuIW8NeRJbn2BLXHns7Q5TZr7Hy3lF6MOpMlp7GoxBFRLISQ6KrD0CJOrR8aogEsPeg
143
143
  puts token
144
144
 
145
- decoded_token = JWT.decode token, ecdsa_public, true, { algorithm: 'ES256' }
145
+ decoded_token = JWT.decode token, ecdsa_key, true, { algorithm: 'ES256' }
146
146
 
147
147
  # Array
148
148
  # [
@@ -152,7 +152,7 @@ decoded_token = JWT.decode token, ecdsa_public, true, { algorithm: 'ES256' }
152
152
  puts decoded_token
153
153
  ```
154
154
 
155
- **EDDSA**
155
+ ### **EDDSA**
156
156
 
157
157
  In order to use this algorithm you need to add the `RbNaCl` gem to you `Gemfile`.
158
158
 
@@ -181,9 +181,9 @@ decoded_token = JWT.decode token, public_key, true, { algorithm: 'ED25519' }
181
181
 
182
182
  ```
183
183
 
184
- **RSASSA-PSS**
184
+ ### **RSASSA-PSS**
185
185
 
186
- In order to use this algorithm you need to add the `openssl` gem to you `Gemfile` with a version greater or equal to `2.1`.
186
+ In order to use this algorithm you need to add the `openssl` gem to your `Gemfile` with a version greater or equal to `2.1`.
187
187
 
188
188
  ```ruby
189
189
  gem 'openssl', '~> 2.1'
@@ -370,6 +370,36 @@ rescue JWT::InvalidIssuerError
370
370
  end
371
371
  ```
372
372
 
373
+ You can also pass a Regexp or Proc (with arity 1), verification will pass if the regexp matches or the proc returns truthy.
374
+ On supported ruby versions (>= 2.5) you can also delegate to methods, on older versions you will have
375
+ to convert them to proc (using `to_proc`)
376
+
377
+ ```ruby
378
+ JWT.decode token, hmac_secret, true,
379
+ iss: %r'https://my.awesome.website/',
380
+ verify_iss: true,
381
+ algorithm: 'HS256'
382
+ ```
383
+
384
+ ```ruby
385
+ JWT.decode token, hmac_secret, true,
386
+ iss: ->(issuer) { issuer.start_with?('My Awesome Company Inc') },
387
+ verify_iss: true,
388
+ algorithm: 'HS256'
389
+ ```
390
+
391
+ ```ruby
392
+ JWT.decode token, hmac_secret, true,
393
+ iss: method(:valid_issuer?),
394
+ verify_iss: true,
395
+ algorithm: 'HS256'
396
+
397
+ # somewhere in the same class:
398
+ def valid_issuer?(issuer)
399
+ # custom validation
400
+ end
401
+ ```
402
+
373
403
  ### Audience Claim
374
404
 
375
405
  From [Oauth JSON Web Token 4.1.3. "aud" (Audience) Claim](https://tools.ietf.org/html/rfc7519#section-4.1.3):
@@ -486,36 +516,68 @@ end
486
516
 
487
517
  You can specify claims that must be present for decoding to be successful. JWT::MissingRequiredClaim will be raised if any are missing
488
518
  ```ruby
489
- # Will raise a JWT::ExpiredSignature error if the 'exp' claim is absent
519
+ # Will raise a JWT::MissingRequiredClaim error if the 'exp' claim is absent
490
520
  JWT.decode token, hmac_secret, true, { required_claims: ['exp'], algorithm: 'HS256' }
491
521
  ```
492
522
 
493
- ### JSON Web Key (JWK)
523
+ ### X.509 certificates in x5c header
494
524
 
495
- JWK is a JSON structure representing a cryptographic key. Currently only supports RSA public keys.
525
+ A JWT signature can be verified using certificate(s) given in the `x5c` header. Before doing that, the trustworthiness of these certificate(s) must be established. This is done in accordance with RFC 5280 which (among other things) verifies the certificate(s) are issued by a trusted root certificate, the timestamps are valid, and none of the certificate(s) are revoked (i.e. being present in the root certificate's Certificate Revocation List).
496
526
 
497
527
  ```ruby
498
- jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), "optional-kid")
499
- payload, headers = { data: 'data' }, { kid: jwk.kid }
500
-
501
- token = JWT.encode(payload, jwk.keypair, 'RS512', headers)
502
-
503
- # The jwk loader would fetch the set of JWKs from a trusted source
504
- jwk_loader = ->(options) do
505
- @cached_keys = nil if options[:invalidate] # need to reload the keys
506
- @cached_keys ||= { keys: [jwk.export] }
528
+ root_certificates = [] # trusted `OpenSSL::X509::Certificate` objects
529
+ crl_uris = root_certificates.map(&:crl_uris)
530
+ crls = crl_uris.map do |uri|
531
+ # look up cached CRL by `uri` and return it if found, otherwise continue
532
+ crl = Net::HTTP.get(uri)
533
+ crl = OpenSSL::X509::CRL.new(crl)
534
+ # cache `crl` using `uri` as the key, expiry set to `crl.next_update` timestamp
507
535
  end
508
536
 
509
537
  begin
510
- JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwk_loader})
511
- rescue JWT::JWKError
512
- # Handle problems with the provided JWKs
538
+ JWT.decode(token, nil, true, { x5c: { root_certificates: root_certificates, crls: crls })
513
539
  rescue JWT::DecodeError
514
- # Handle other decode related issues e.g. no kid in header, no matching public key found etc.
540
+ # Handle error, e.g. x5c header certificate revoked or expired
515
541
  end
516
542
  ```
517
543
 
518
- or by passing JWK as a simple Hash
544
+ ### JSON Web Key (JWK)
545
+
546
+ JWK is a JSON structure representing a cryptographic key. Currently only supports RSA, EC and HMAC keys. The `jwks` option can be given as a lambda that evaluates every time a kid is resolved.
547
+
548
+ If the kid is not found from the given set the loader will be called a second time with the `kid_not_found` option set to `true`. The application can choose to implement some kind of JWK cache invalidation or other mechanism to handle such cases.
549
+
550
+ ```ruby
551
+ jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), 'optional-kid')
552
+ payload = { data: 'data' }
553
+ headers = { kid: jwk.kid }
554
+
555
+ token = JWT.encode(payload, jwk.keypair, 'RS512', headers)
556
+
557
+ # The jwk loader would fetch the set of JWKs from a trusted source,
558
+ # to avoid malicious requests triggering cache invalidations there needs to be some kind of grace time or other logic for determining the validity of the invalidation.
559
+ # This example only allows cache invalidations every 5 minutes.
560
+ jwk_loader = ->(options) do
561
+ if options[:kid_not_found] && @cache_last_update < Time.now.to_i - 300
562
+ logger.info("Invalidating JWK cache. #{options[:kid]} not found from previous cache")
563
+ @cached_keys = nil
564
+ end
565
+ @cached_keys ||= begin
566
+ @cache_last_update = Time.now.to_i
567
+ { keys: [jwk.export] }
568
+ end
569
+ end
570
+
571
+ begin
572
+ JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwk_loader })
573
+ rescue JWT::JWKError
574
+ # Handle problems with the provided JWKs
575
+ rescue JWT::DecodeError
576
+ # Handle other decode related issues e.g. no kid in header, no matching public key found etc.
577
+ end
578
+ ```
579
+
580
+ or by passing the JWKs as a simple Hash
519
581
 
520
582
  ```
521
583
  jwks = { keys: [{ ... }] } # keys accepts both of string and symbol
@@ -524,7 +586,7 @@ JWT.decode(token, nil, true, { algorithms: ['RS512'], jwks: jwks})
524
586
 
525
587
  ### Importing and exporting JSON Web Keys
526
588
 
527
- The ::JWT::JWK class can be used to import and export both the public key (default behaviour) and the private key. To include the private key in the export pass the `include_private` parameter to the export method.
589
+ The ::JWT::JWK class can be used to import and export both the public key (default behaviour) and the private key. To include the private key in the export pass the `include_private` parameter to the export method.
528
590
 
529
591
  ```ruby
530
592
  jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048))
@@ -533,6 +595,23 @@ jwk_hash = jwk.export
533
595
  jwk_hash_with_private_key = jwk.export(include_private: true)
534
596
  ```
535
597
 
598
+ ### Key ID (kid) and JWKs
599
+
600
+ The key id (kid) generation in the gem is a custom algorithm and not based on any standards. To use a standardized JWK thumbprint (RFC 7638) as the kid for JWKs a generator type can be specified in the global configuration or can be given to the JWK instance on initialization.
601
+
602
+ ```ruby
603
+ JWT.configuration.jwk.kid_generator_type = :rfc7638_thumbprint
604
+ # OR
605
+ JWT.configuration.jwk.kid_generator = ::JWT::JWK::Thumbprint
606
+ # OR
607
+ jwk = JWT::JWK.new(OpenSSL::PKey::RSA.new(2048), kid_generator: ::JWT::JWK::Thumbprint)
608
+
609
+ jwk_hash = jwk.export
610
+
611
+ thumbprint_as_the_kid = jwk_hash[:kid]
612
+
613
+ ```
614
+
536
615
  # Development and Tests
537
616
 
538
617
  We depend on [Bundler](http://rubygems.org/gems/bundler) for defining gemspec and performing releases to rubygems.org, which can be done with
@@ -548,12 +627,13 @@ bundle install
548
627
  bundle exec appraisal rake test
549
628
  ```
550
629
 
551
- **If you want a release cut with your PR, please include a version bump according to [Semantic Versioning](http://semver.org/)**
630
+ ## How to contribute
631
+ See [CONTRIBUTING](CONTRIBUTING.md).
552
632
 
553
633
  ## Contributors
554
634
 
555
- See `AUTHORS` file.
635
+ See [AUTHORS](AUTHORS).
556
636
 
557
637
  ## License
558
638
 
559
- See `LICENSE` file.
639
+ See [LICENSE](LICENSE).
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'bundler/gem_tasks'
3
5
 
@@ -1,35 +1,64 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Ecdsa
4
6
  module_function
5
7
 
6
- SUPPORTED = %w[ES256 ES384 ES512].freeze
7
8
  NAMED_CURVES = {
8
- 'prime256v1' => 'ES256',
9
- 'secp384r1' => 'ES384',
10
- 'secp521r1' => 'ES512'
9
+ 'prime256v1' => {
10
+ algorithm: 'ES256',
11
+ digest: 'sha256'
12
+ },
13
+ 'secp256r1' => { # alias for prime256v1
14
+ algorithm: 'ES256',
15
+ digest: 'sha256'
16
+ },
17
+ 'secp384r1' => {
18
+ algorithm: 'ES384',
19
+ digest: 'sha384'
20
+ },
21
+ 'secp521r1' => {
22
+ algorithm: 'ES512',
23
+ digest: 'sha512'
24
+ },
25
+ 'secp256k1' => {
26
+ algorithm: 'ES256K',
27
+ digest: 'sha256'
28
+ }
11
29
  }.freeze
12
30
 
31
+ SUPPORTED = NAMED_CURVES.map { |_, c| c[:algorithm] }.uniq.freeze
32
+
13
33
  def sign(to_sign)
14
34
  algorithm, msg, key = to_sign.values
15
- key_algorithm = NAMED_CURVES[key.group.curve_name]
35
+ curve_definition = curve_by_name(key.group.curve_name)
36
+ key_algorithm = curve_definition[:algorithm]
16
37
  if algorithm != key_algorithm
17
38
  raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided"
18
39
  end
19
40
 
20
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
41
+ digest = OpenSSL::Digest.new(curve_definition[:digest])
21
42
  SecurityUtils.asn1_to_raw(key.dsa_sign_asn1(digest.digest(msg)), key)
22
43
  end
23
44
 
24
45
  def verify(to_verify)
25
46
  algorithm, public_key, signing_input, signature = to_verify.values
26
- key_algorithm = NAMED_CURVES[public_key.group.curve_name]
47
+ curve_definition = curve_by_name(public_key.group.curve_name)
48
+ key_algorithm = curve_definition[:algorithm]
27
49
  if algorithm != key_algorithm
28
50
  raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
29
51
  end
30
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
52
+
53
+ digest = OpenSSL::Digest.new(curve_definition[:digest])
31
54
  public_key.dsa_verify_asn1(digest.digest(signing_input), SecurityUtils.raw_to_asn1(signature, public_key))
32
55
  end
56
+
57
+ def curve_by_name(name)
58
+ NAMED_CURVES.fetch(name) do
59
+ raise UnsupportedEcdsaCurve, "The ECDSA curve '#{name}' is not supported"
60
+ end
61
+ end
33
62
  end
34
63
  end
35
64
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Eddsa
@@ -23,7 +25,10 @@ module JWT
23
25
  raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key.primitive} signing key was provided"
24
26
  end
25
27
  raise DecodeError, "key given is a #{public_key.class} but has to be a RbNaCl::Signatures::Ed25519::VerifyKey" if public_key.class != RbNaCl::Signatures::Ed25519::VerifyKey
28
+
26
29
  public_key.verify(signature, signing_input)
30
+ rescue RbNaCl::CryptoError
31
+ false
27
32
  end
28
33
  end
29
34
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Hmac
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module None
data/lib/jwt/algos/ps.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Ps
@@ -29,9 +31,7 @@ module JWT
29
31
 
30
32
  def require_openssl!
31
33
  if Object.const_defined?('OpenSSL')
32
- major, minor = OpenSSL::VERSION.split('.').first(2)
33
-
34
- unless major.to_i >= 2 && minor.to_i >= 1
34
+ if ::Gem::Version.new(OpenSSL::VERSION) < ::Gem::Version.new('2.1')
35
35
  raise JWT::RequiredDependencyError, "You currently have OpenSSL #{OpenSSL::VERSION}. PS support requires >= 2.1"
36
36
  end
37
37
  else
data/lib/jwt/algos/rsa.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Rsa
@@ -7,7 +9,8 @@ module JWT
7
9
 
8
10
  def sign(to_sign)
9
11
  algorithm, msg, key = to_sign.values
10
- raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance." if key.class == String
12
+ raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance." if key.instance_of?(String)
13
+
11
14
  key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
12
15
  end
13
16
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module JWT
2
4
  module Algos
3
5
  module Unsupported
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative './error'
2
4
 
3
5
  module JWT
@@ -9,7 +11,7 @@ module JWT
9
11
  ].freeze
10
12
 
11
13
  def initialize(payload)
12
- @payload = payload.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
14
+ @payload = payload.transform_keys(&:to_sym)
13
15
  end
14
16
 
15
17
  def validate!
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'decode_configuration'
4
+ require_relative 'jwk_configuration'
5
+
6
+ module JWT
7
+ module Configuration
8
+ class Container
9
+ attr_accessor :decode, :jwk
10
+
11
+ def initialize
12
+ reset!
13
+ end
14
+
15
+ def reset!
16
+ @decode = DecodeConfiguration.new
17
+ @jwk = JwkConfiguration.new
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ module Configuration
5
+ class DecodeConfiguration
6
+ attr_accessor :verify_expiration,
7
+ :verify_not_before,
8
+ :verify_iss,
9
+ :verify_iat,
10
+ :verify_jti,
11
+ :verify_aud,
12
+ :verify_sub,
13
+ :leeway,
14
+ :algorithms,
15
+ :required_claims
16
+
17
+ def initialize
18
+ @verify_expiration = true
19
+ @verify_not_before = true
20
+ @verify_iss = false
21
+ @verify_iat = false
22
+ @verify_jti = false
23
+ @verify_aud = false
24
+ @verify_sub = false
25
+ @leeway = 0
26
+ @algorithms = ['HS256']
27
+ @required_claims = []
28
+ end
29
+
30
+ def to_h
31
+ {
32
+ verify_expiration: verify_expiration,
33
+ verify_not_before: verify_not_before,
34
+ verify_iss: verify_iss,
35
+ verify_iat: verify_iat,
36
+ verify_jti: verify_jti,
37
+ verify_aud: verify_aud,
38
+ verify_sub: verify_sub,
39
+ leeway: leeway,
40
+ algorithms: algorithms,
41
+ required_claims: required_claims
42
+ }
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../jwk/kid_as_key_digest'
4
+ require_relative '../jwk/thumbprint'
5
+
6
+ module JWT
7
+ module Configuration
8
+ class JwkConfiguration
9
+ def initialize
10
+ self.kid_generator_type = :key_digest
11
+ end
12
+
13
+ def kid_generator_type=(value)
14
+ self.kid_generator = case value
15
+ when :key_digest
16
+ JWT::JWK::KidAsKeyDigest
17
+ when :rfc7638_thumbprint
18
+ JWT::JWK::Thumbprint
19
+ else
20
+ raise ArgumentError, "#{value} is not a valid kid generator type."
21
+ end
22
+ end
23
+
24
+ attr_accessor :kid_generator
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'configuration/container'
4
+
5
+ module JWT
6
+ module Configuration
7
+ def configure
8
+ yield(configuration)
9
+ end
10
+
11
+ def configuration
12
+ @configuration ||= ::JWT::Configuration::Container.new
13
+ end
14
+ end
15
+ end