jwt 2.8.2 → 2.10.2

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +79 -0
  3. data/README.md +189 -93
  4. data/lib/jwt/base64.rb +3 -0
  5. data/lib/jwt/claims/audience.rb +30 -0
  6. data/lib/jwt/claims/crit.rb +35 -0
  7. data/lib/jwt/claims/decode_verifier.rb +40 -0
  8. data/lib/jwt/claims/expiration.rb +32 -0
  9. data/lib/jwt/claims/issued_at.rb +22 -0
  10. data/lib/jwt/claims/issuer.rb +34 -0
  11. data/lib/jwt/claims/jwt_id.rb +35 -0
  12. data/lib/jwt/claims/not_before.rb +32 -0
  13. data/lib/jwt/claims/numeric.rb +77 -0
  14. data/lib/jwt/claims/required.rb +33 -0
  15. data/lib/jwt/claims/subject.rb +30 -0
  16. data/lib/jwt/claims/verification_methods.rb +20 -0
  17. data/lib/jwt/claims/verifier.rb +61 -0
  18. data/lib/jwt/claims.rb +74 -0
  19. data/lib/jwt/claims_validator.rb +6 -25
  20. data/lib/jwt/configuration/container.rb +20 -0
  21. data/lib/jwt/configuration/decode_configuration.rb +24 -0
  22. data/lib/jwt/configuration/jwk_configuration.rb +1 -0
  23. data/lib/jwt/configuration.rb +8 -0
  24. data/lib/jwt/decode.rb +28 -70
  25. data/lib/jwt/deprecations.rb +1 -0
  26. data/lib/jwt/encode.rb +17 -60
  27. data/lib/jwt/encoded_token.rb +139 -0
  28. data/lib/jwt/error.rb +34 -0
  29. data/lib/jwt/json.rb +1 -1
  30. data/lib/jwt/jwa/compat.rb +32 -0
  31. data/lib/jwt/jwa/ecdsa.rb +39 -25
  32. data/lib/jwt/jwa/eddsa.rb +20 -27
  33. data/lib/jwt/jwa/hmac.rb +25 -18
  34. data/lib/jwt/jwa/hmac_rbnacl.rb +43 -43
  35. data/lib/jwt/jwa/hmac_rbnacl_fixed.rb +40 -39
  36. data/lib/jwt/jwa/none.rb +8 -3
  37. data/lib/jwt/jwa/ps.rb +20 -15
  38. data/lib/jwt/jwa/rsa.rb +20 -10
  39. data/lib/jwt/jwa/signing_algorithm.rb +63 -0
  40. data/lib/jwt/jwa/unsupported.rb +9 -8
  41. data/lib/jwt/jwa/wrapper.rb +27 -9
  42. data/lib/jwt/jwa.rb +30 -34
  43. data/lib/jwt/jwk/ec.rb +2 -3
  44. data/lib/jwt/jwk/hmac.rb +2 -3
  45. data/lib/jwt/jwk/key_base.rb +1 -0
  46. data/lib/jwt/jwk/key_finder.rb +1 -0
  47. data/lib/jwt/jwk/kid_as_key_digest.rb +1 -0
  48. data/lib/jwt/jwk/okp_rbnacl.rb +3 -4
  49. data/lib/jwt/jwk/rsa.rb +2 -3
  50. data/lib/jwt/jwk/set.rb +2 -0
  51. data/lib/jwt/jwk.rb +1 -0
  52. data/lib/jwt/token.rb +112 -0
  53. data/lib/jwt/verify.rb +16 -93
  54. data/lib/jwt/version.rb +30 -9
  55. data/lib/jwt.rb +20 -0
  56. data/ruby-jwt.gemspec +1 -0
  57. metadata +36 -7
data/lib/jwt/jwa/hmac.rb CHANGED
@@ -2,35 +2,42 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
- module Hmac
6
- module_function
5
+ # Implementation of the HMAC family of algorithms
6
+ class Hmac
7
+ include JWT::JWA::SigningAlgorithm
7
8
 
8
- MAPPING = {
9
- 'HS256' => OpenSSL::Digest::SHA256,
10
- 'HS384' => OpenSSL::Digest::SHA384,
11
- 'HS512' => OpenSSL::Digest::SHA512
12
- }.freeze
13
-
14
- SUPPORTED = MAPPING.keys
9
+ def self.from_algorithm(algorithm)
10
+ new(algorithm, OpenSSL::Digest.new(algorithm.downcase.gsub('hs', 'sha')))
11
+ end
15
12
 
16
- def sign(algorithm, msg, key)
17
- key ||= ''
13
+ def initialize(alg, digest)
14
+ @alg = alg
15
+ @digest = digest
16
+ end
18
17
 
19
- raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
18
+ def sign(data:, signing_key:)
19
+ signing_key ||= ''
20
+ raise_verify_error!('HMAC key expected to be a String') unless signing_key.is_a?(String)
20
21
 
21
- OpenSSL::HMAC.digest(MAPPING[algorithm].new, key, msg)
22
+ OpenSSL::HMAC.digest(digest.new, signing_key, data)
22
23
  rescue OpenSSL::HMACError => e
23
- if key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure'
24
- raise JWT::DecodeError, 'OpenSSL 3.0 does not support nil or empty hmac_secret'
25
- end
24
+ raise_verify_error!('OpenSSL 3.0 does not support nil or empty hmac_secret') if signing_key == '' && e.message == 'EVP_PKEY_new_mac_key: malloc failure'
26
25
 
27
26
  raise e
28
27
  end
29
28
 
30
- def verify(algorithm, key, signing_input, signature)
31
- SecurityUtils.secure_compare(signature, sign(algorithm, signing_input, key))
29
+ def verify(data:, signature:, verification_key:)
30
+ SecurityUtils.secure_compare(signature, sign(data: data, signing_key: verification_key))
32
31
  end
33
32
 
33
+ register_algorithm(new('HS256', OpenSSL::Digest::SHA256))
34
+ register_algorithm(new('HS384', OpenSSL::Digest::SHA384))
35
+ register_algorithm(new('HS512', OpenSSL::Digest::SHA512))
36
+
37
+ private
38
+
39
+ attr_reader :digest
40
+
34
41
  # Copy of https://github.com/rails/rails/blob/v7.0.3.1/activesupport/lib/active_support/security_utils.rb
35
42
  # rubocop:disable Naming/MethodParameterName, Style/StringLiterals, Style/NumericPredicate
36
43
  module SecurityUtils
@@ -1,49 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
- module Algos
5
- module HmacRbNaCl
6
- MAPPING = { 'HS512256' => ::RbNaCl::HMAC::SHA512256 }.freeze
7
- SUPPORTED = MAPPING.keys
8
- class << self
9
- def sign(algorithm, msg, key)
10
- Deprecations.warning("The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
11
- if (hmac = resolve_algorithm(algorithm))
12
- hmac.auth(key_for_rbnacl(hmac, key).encode('binary'), msg.encode('binary'))
13
- else
14
- Hmac.sign(algorithm, msg, key)
15
- end
16
- end
17
-
18
- def verify(algorithm, key, signing_input, signature)
19
- Deprecations.warning("The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
20
- if (hmac = resolve_algorithm(algorithm))
21
- hmac.verify(key_for_rbnacl(hmac, key).encode('binary'), signature.encode('binary'), signing_input.encode('binary'))
22
- else
23
- Hmac.verify(algorithm, key, signing_input, signature)
24
- end
25
- rescue ::RbNaCl::BadAuthenticatorError, ::RbNaCl::LengthError
26
- false
27
- end
28
-
29
- private
30
-
31
- def key_for_rbnacl(hmac, key)
32
- key ||= ''
33
- raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
34
-
35
- return padded_empty_key(hmac.key_bytes) if key == ''
36
-
37
- key
38
- end
39
-
40
- def resolve_algorithm(algorithm)
41
- MAPPING.fetch(algorithm)
42
- end
43
-
44
- def padded_empty_key(length)
45
- Array.new(length, 0x0).pack('C*').encode('binary')
46
- end
4
+ module JWA
5
+ # Implementation of the HMAC family of algorithms (using RbNaCl)
6
+ class HmacRbNaCl
7
+ include JWT::JWA::SigningAlgorithm
8
+
9
+ def self.from_algorithm(algorithm)
10
+ new(algorithm, ::RbNaCl::HMAC.const_get(algorithm.upcase.gsub('HS', 'SHA')))
11
+ end
12
+
13
+ def initialize(alg, hmac)
14
+ @alg = alg
15
+ @hmac = hmac
16
+ end
17
+
18
+ def sign(data:, signing_key:)
19
+ Deprecations.warning("The use of the algorithm #{alg} is deprecated and will be removed in the next major version of ruby-jwt")
20
+ hmac.auth(key_for_rbnacl(hmac, signing_key).encode('binary'), data.encode('binary'))
21
+ end
22
+
23
+ def verify(data:, signature:, verification_key:)
24
+ Deprecations.warning("The use of the algorithm #{alg} is deprecated and will be removed in the next major version of ruby-jwt")
25
+ hmac.verify(key_for_rbnacl(hmac, verification_key).encode('binary'), signature.encode('binary'), data.encode('binary'))
26
+ rescue ::RbNaCl::BadAuthenticatorError, ::RbNaCl::LengthError
27
+ false
28
+ end
29
+
30
+ register_algorithm(new('HS512256', ::RbNaCl::HMAC::SHA512256))
31
+
32
+ private
33
+
34
+ attr_reader :hmac
35
+
36
+ def key_for_rbnacl(hmac, key)
37
+ key ||= ''
38
+ raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
39
+
40
+ return padded_empty_key(hmac.key_bytes) if key == ''
41
+
42
+ key
43
+ end
44
+
45
+ def padded_empty_key(length)
46
+ Array.new(length, 0x0).pack('C*').encode('binary')
47
47
  end
48
48
  end
49
49
  end
@@ -1,45 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JWT
4
- module Algos
5
- module HmacRbNaClFixed
6
- MAPPING = { 'HS512256' => ::RbNaCl::HMAC::SHA512256 }.freeze
7
- SUPPORTED = MAPPING.keys
8
-
9
- class << self
10
- def sign(algorithm, msg, key)
11
- key ||= ''
12
- Deprecations.warning("The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
13
- raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
14
-
15
- if (hmac = resolve_algorithm(algorithm)) && key.bytesize <= hmac.key_bytes
16
- hmac.auth(padded_key_bytes(key, hmac.key_bytes), msg.encode('binary'))
17
- else
18
- Hmac.sign(algorithm, msg, key)
19
- end
20
- end
21
-
22
- def verify(algorithm, key, signing_input, signature)
23
- key ||= ''
24
- Deprecations.warning("The use of the algorithm #{algorithm} is deprecated and will be removed in the next major version of ruby-jwt")
25
- raise JWT::DecodeError, 'HMAC key expected to be a String' unless key.is_a?(String)
26
-
27
- if (hmac = resolve_algorithm(algorithm)) && key.bytesize <= hmac.key_bytes
28
- hmac.verify(padded_key_bytes(key, hmac.key_bytes), signature.encode('binary'), signing_input.encode('binary'))
29
- else
30
- Hmac.verify(algorithm, key, signing_input, signature)
31
- end
32
- rescue ::RbNaCl::BadAuthenticatorError, ::RbNaCl::LengthError
33
- false
34
- end
35
-
36
- def resolve_algorithm(algorithm)
37
- MAPPING.fetch(algorithm)
38
- end
39
-
40
- def padded_key_bytes(key, bytesize)
41
- key.bytes.fill(0, key.bytesize...bytesize).pack('C*')
42
- end
4
+ module JWA
5
+ # Implementation of the HMAC family of algorithms (using RbNaCl prior to a certain version)
6
+ class HmacRbNaClFixed
7
+ include JWT::JWA::SigningAlgorithm
8
+
9
+ def self.from_algorithm(algorithm)
10
+ new(algorithm, ::RbNaCl::HMAC.const_get(algorithm.upcase.gsub('HS', 'SHA')))
11
+ end
12
+
13
+ def initialize(alg, hmac)
14
+ @alg = alg
15
+ @hmac = hmac
16
+ end
17
+
18
+ def sign(data:, signing_key:)
19
+ signing_key ||= ''
20
+ Deprecations.warning("The use of the algorithm #{alg} is deprecated and will be removed in the next major version of ruby-jwt")
21
+ raise JWT::DecodeError, 'HMAC key expected to be a String' unless signing_key.is_a?(String)
22
+
23
+ hmac.auth(padded_key_bytes(signing_key, hmac.key_bytes), data.encode('binary'))
24
+ end
25
+
26
+ def verify(data:, signature:, verification_key:)
27
+ verification_key ||= ''
28
+ Deprecations.warning("The use of the algorithm #{alg} is deprecated and will be removed in the next major version of ruby-jwt")
29
+ raise JWT::DecodeError, 'HMAC key expected to be a String' unless verification_key.is_a?(String)
30
+
31
+ hmac.verify(padded_key_bytes(verification_key, hmac.key_bytes), signature.encode('binary'), data.encode('binary'))
32
+ rescue ::RbNaCl::BadAuthenticatorError, ::RbNaCl::LengthError
33
+ false
34
+ end
35
+
36
+ register_algorithm(new('HS512256', ::RbNaCl::HMAC::SHA512256))
37
+
38
+ private
39
+
40
+ attr_reader :hmac
41
+
42
+ def padded_key_bytes(key, bytesize)
43
+ key.bytes.fill(0, key.bytesize...bytesize).pack('C*')
43
44
  end
44
45
  end
45
46
  end
data/lib/jwt/jwa/none.rb CHANGED
@@ -2,10 +2,13 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
- module None
6
- module_function
5
+ # Implementation of the none algorithm
6
+ class None
7
+ include JWT::JWA::SigningAlgorithm
7
8
 
8
- SUPPORTED = %w[none].freeze
9
+ def initialize
10
+ @alg = 'none'
11
+ end
9
12
 
10
13
  def sign(*)
11
14
  ''
@@ -14,6 +17,8 @@ module JWT
14
17
  def verify(*)
15
18
  true
16
19
  end
20
+
21
+ register_algorithm(new)
17
22
  end
18
23
  end
19
24
  end
data/lib/jwt/jwa/ps.rb CHANGED
@@ -2,29 +2,34 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
- module Ps
6
- # RSASSA-PSS signing algorithms
5
+ # Implementation of the RSASSA-PSS family of algorithms
6
+ class Ps
7
+ include JWT::JWA::SigningAlgorithm
7
8
 
8
- module_function
9
-
10
- SUPPORTED = %w[PS256 PS384 PS512].freeze
11
-
12
- def sign(algorithm, msg, key)
13
- unless key.is_a?(::OpenSSL::PKey::RSA)
14
- raise EncodeError, "The given key is a #{key_class}. It has to be an OpenSSL::PKey::RSA instance."
15
- end
9
+ def initialize(alg)
10
+ @alg = alg
11
+ @digest_algorithm = alg.sub('PS', 'sha')
12
+ end
16
13
 
17
- translated_algorithm = algorithm.sub('PS', 'sha')
14
+ def sign(data:, signing_key:)
15
+ raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance.") unless signing_key.is_a?(::OpenSSL::PKey::RSA)
18
16
 
19
- key.sign_pss(translated_algorithm, msg, salt_length: :digest, mgf1_hash: translated_algorithm)
17
+ signing_key.sign_pss(digest_algorithm, data, salt_length: :digest, mgf1_hash: digest_algorithm)
20
18
  end
21
19
 
22
- def verify(algorithm, public_key, signing_input, signature)
23
- translated_algorithm = algorithm.sub('PS', 'sha')
24
- public_key.verify_pss(translated_algorithm, signature, signing_input, salt_length: :auto, mgf1_hash: translated_algorithm)
20
+ def verify(data:, signature:, verification_key:)
21
+ verification_key.verify_pss(digest_algorithm, signature, data, salt_length: :auto, mgf1_hash: digest_algorithm)
25
22
  rescue OpenSSL::PKey::PKeyError
26
23
  raise JWT::VerificationError, 'Signature verification raised'
27
24
  end
25
+
26
+ register_algorithm(new('PS256'))
27
+ register_algorithm(new('PS384'))
28
+ register_algorithm(new('PS512'))
29
+
30
+ private
31
+
32
+ attr_reader :digest_algorithm
28
33
  end
29
34
  end
30
35
  end
data/lib/jwt/jwa/rsa.rb CHANGED
@@ -2,24 +2,34 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
- module Rsa
6
- module_function
5
+ # Implementation of the RSA family of algorithms
6
+ class Rsa
7
+ include JWT::JWA::SigningAlgorithm
7
8
 
8
- SUPPORTED = %w[RS256 RS384 RS512].freeze
9
+ def initialize(alg)
10
+ @alg = alg
11
+ @digest = alg.sub('RS', 'SHA')
12
+ end
9
13
 
10
- def sign(algorithm, msg, key)
11
- unless key.is_a?(OpenSSL::PKey::RSA)
12
- raise EncodeError, "The given key is a #{key.class}. It has to be an OpenSSL::PKey::RSA instance"
13
- end
14
+ def sign(data:, signing_key:)
15
+ raise_sign_error!("The given key is a #{signing_key.class}. It has to be an OpenSSL::PKey::RSA instance") unless signing_key.is_a?(OpenSSL::PKey::RSA)
14
16
 
15
- key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
17
+ signing_key.sign(OpenSSL::Digest.new(digest), data)
16
18
  end
17
19
 
18
- def verify(algorithm, public_key, signing_input, signature)
19
- public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input)
20
+ def verify(data:, signature:, verification_key:)
21
+ verification_key.verify(OpenSSL::Digest.new(digest), signature, data)
20
22
  rescue OpenSSL::PKey::PKeyError
21
23
  raise JWT::VerificationError, 'Signature verification raised'
22
24
  end
25
+
26
+ register_algorithm(new('RS256'))
27
+ register_algorithm(new('RS384'))
28
+ register_algorithm(new('RS512'))
29
+
30
+ private
31
+
32
+ attr_reader :digest
23
33
  end
24
34
  end
25
35
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ # JSON Web Algorithms
5
+ module JWA
6
+ # Base functionality for signing algorithms
7
+ module SigningAlgorithm
8
+ # Class methods for the SigningAlgorithm module
9
+ module ClassMethods
10
+ def register_algorithm(algo)
11
+ ::JWT::JWA.register_algorithm(algo)
12
+ end
13
+ end
14
+
15
+ def self.included(klass)
16
+ klass.extend(ClassMethods)
17
+ klass.include(JWT::JWA::Compat)
18
+ end
19
+
20
+ attr_reader :alg
21
+
22
+ def valid_alg?(alg_to_check)
23
+ alg&.casecmp(alg_to_check)&.zero? == true
24
+ end
25
+
26
+ def header(*)
27
+ { 'alg' => alg }
28
+ end
29
+
30
+ def sign(*)
31
+ raise_sign_error!('Algorithm implementation is missing the sign method')
32
+ end
33
+
34
+ def verify(*)
35
+ raise_verify_error!('Algorithm implementation is missing the verify method')
36
+ end
37
+
38
+ def raise_verify_error!(message)
39
+ raise(DecodeError.new(message).tap { |e| e.set_backtrace(caller(1)) })
40
+ end
41
+
42
+ def raise_sign_error!(message)
43
+ raise(EncodeError.new(message).tap { |e| e.set_backtrace(caller(1)) })
44
+ end
45
+ end
46
+
47
+ class << self
48
+ def register_algorithm(algo)
49
+ algorithms[algo.alg.to_s.downcase] = algo
50
+ end
51
+
52
+ def find(algo)
53
+ algorithms.fetch(algo.to_s.downcase, Unsupported)
54
+ end
55
+
56
+ private
57
+
58
+ def algorithms
59
+ @algorithms ||= {}
60
+ end
61
+ end
62
+ end
63
+ end
@@ -2,17 +2,18 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # Represents an unsupported algorithm
5
6
  module Unsupported
6
- module_function
7
+ class << self
8
+ include JWT::JWA::SigningAlgorithm
7
9
 
8
- SUPPORTED = [].freeze
10
+ def sign(*)
11
+ raise_sign_error!('Unsupported signing method')
12
+ end
9
13
 
10
- def sign(*)
11
- raise NotImplementedError, 'Unsupported signing method'
12
- end
13
-
14
- def verify(*)
15
- raise JWT::VerificationError, 'Algorithm not supported'
14
+ def verify(*)
15
+ raise JWT::VerificationError, 'Algorithm not supported'
16
+ end
16
17
  end
17
18
  end
18
19
  end
@@ -2,24 +2,42 @@
2
2
 
3
3
  module JWT
4
4
  module JWA
5
+ # @api private
5
6
  class Wrapper
6
- attr_reader :alg, :cls
7
+ include SigningAlgorithm
7
8
 
8
- def initialize(alg, cls)
9
- @alg = alg
10
- @cls = cls
9
+ def initialize(algorithm)
10
+ @algorithm = algorithm
11
+ end
12
+
13
+ def alg
14
+ return @algorithm.alg if @algorithm.respond_to?(:alg)
15
+
16
+ super
11
17
  end
12
18
 
13
19
  def valid_alg?(alg_to_check)
14
- alg&.casecmp(alg_to_check)&.zero? == true
20
+ return @algorithm.valid_alg?(alg_to_check) if @algorithm.respond_to?(:valid_alg?)
21
+
22
+ super
15
23
  end
16
24
 
17
- def sign(data:, signing_key:)
18
- cls.sign(alg, data, signing_key)
25
+ def header(*args, **kwargs)
26
+ return @algorithm.header(*args, **kwargs) if @algorithm.respond_to?(:header)
27
+
28
+ super
19
29
  end
20
30
 
21
- def verify(data:, signature:, verification_key:)
22
- cls.verify(alg, verification_key, data, signature)
31
+ def sign(*args, **kwargs)
32
+ return @algorithm.sign(*args, **kwargs) if @algorithm.respond_to?(:sign)
33
+
34
+ super
35
+ end
36
+
37
+ def verify(*args, **kwargs)
38
+ return @algorithm.verify(*args, **kwargs) if @algorithm.respond_to?(:verify)
39
+
40
+ super
23
41
  end
24
42
  end
25
43
  end
data/lib/jwt/jwa.rb CHANGED
@@ -8,54 +8,50 @@ rescue LoadError
8
8
  raise if defined?(RbNaCl)
9
9
  end
10
10
 
11
- require_relative 'jwa/hmac'
12
- require_relative 'jwa/eddsa'
11
+ require_relative 'jwa/compat'
12
+ require_relative 'jwa/signing_algorithm'
13
13
  require_relative 'jwa/ecdsa'
14
- require_relative 'jwa/rsa'
15
- require_relative 'jwa/ps'
14
+ require_relative 'jwa/hmac'
16
15
  require_relative 'jwa/none'
16
+ require_relative 'jwa/ps'
17
+ require_relative 'jwa/rsa'
17
18
  require_relative 'jwa/unsupported'
18
19
  require_relative 'jwa/wrapper'
19
20
 
21
+ require_relative 'jwa/eddsa' if JWT.rbnacl?
22
+
23
+ if JWT.rbnacl_6_or_greater?
24
+ require_relative 'jwa/hmac_rbnacl'
25
+ elsif JWT.rbnacl?
26
+ require_relative 'jwa/hmac_rbnacl_fixed'
27
+ end
28
+
20
29
  module JWT
30
+ # The JWA module contains all supported algorithms.
21
31
  module JWA
22
- ALGOS = [Hmac, Ecdsa, Rsa, Eddsa, Ps, None, Unsupported].tap do |l|
23
- if ::JWT.rbnacl_6_or_greater?
24
- require_relative 'jwa/hmac_rbnacl'
25
- l << Algos::HmacRbNaCl
26
- elsif ::JWT.rbnacl?
27
- require_relative 'jwa/hmac_rbnacl_fixed'
28
- l << Algos::HmacRbNaClFixed
29
- end
30
- end.freeze
31
-
32
32
  class << self
33
- def find(algorithm)
34
- indexed[algorithm&.downcase]
35
- end
33
+ # @api private
34
+ def resolve(algorithm)
35
+ return find(algorithm) if algorithm.is_a?(String) || algorithm.is_a?(Symbol)
36
36
 
37
- def create(algorithm)
38
- return algorithm if JWA.implementation?(algorithm)
37
+ unless algorithm.is_a?(SigningAlgorithm)
38
+ Deprecations.warning('Custom algorithms are required to include JWT::JWA::SigningAlgorithm. Custom algorithms that do not include this module may stop working in the next major version of ruby-jwt.')
39
+ return Wrapper.new(algorithm)
40
+ end
39
41
 
40
- Wrapper.new(*find(algorithm))
42
+ algorithm
41
43
  end
42
44
 
43
- def implementation?(algorithm)
44
- (algorithm.respond_to?(:valid_alg?) && algorithm.respond_to?(:verify)) ||
45
- (algorithm.respond_to?(:alg) && algorithm.respond_to?(:sign))
45
+ # @api private
46
+ def resolve_and_sort(algorithms:, preferred_algorithm:)
47
+ algs = Array(algorithms).map { |alg| JWA.resolve(alg) }
48
+ algs.partition { |alg| alg.valid_alg?(preferred_algorithm) }.flatten
46
49
  end
47
50
 
48
- private
49
-
50
- def indexed
51
- @indexed ||= begin
52
- fallback = [nil, Unsupported]
53
- ALGOS.each_with_object(Hash.new(fallback)) do |cls, hash|
54
- cls.const_get(:SUPPORTED).each do |alg|
55
- hash[alg.downcase] = [alg, cls]
56
- end
57
- end
58
- end
51
+ # @deprecated The `::JWT::JWA.create` method is deprecated and will be removed in the next major version of ruby-jwt.
52
+ def create(algorithm)
53
+ Deprecations.warning('The ::JWT::JWA.create method is deprecated and will be removed in the next major version of ruby-jwt.')
54
+ resolve(algorithm)
59
55
  end
60
56
  end
61
57
  end
data/lib/jwt/jwk/ec.rb CHANGED
@@ -4,6 +4,7 @@ require 'forwardable'
4
4
 
5
5
  module JWT
6
6
  module JWK
7
+ # JWK representation for Elliptic Curve (EC) keys
7
8
  class EC < KeyBase # rubocop:disable Metrics/ClassLength
8
9
  KTY = 'EC'
9
10
  KTYS = [KTY, OpenSSL::PKey::EC, JWT::JWK::EC].freeze
@@ -65,9 +66,7 @@ module JWT
65
66
  end
66
67
 
67
68
  def []=(key, value)
68
- if EC_KEY_ELEMENTS.include?(key.to_sym)
69
- raise ArgumentError, 'cannot overwrite cryptographic key attributes'
70
- end
69
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes' if EC_KEY_ELEMENTS.include?(key.to_sym)
71
70
 
72
71
  super(key, value)
73
72
  end
data/lib/jwt/jwk/hmac.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # JWK for HMAC keys
5
6
  class HMAC < KeyBase
6
7
  KTY = 'oct'
7
8
  KTYS = [KTY, String, JWT::JWK::HMAC].freeze
@@ -61,9 +62,7 @@ module JWT
61
62
  end
62
63
 
63
64
  def []=(key, value)
64
- if HMAC_KEY_ELEMENTS.include?(key.to_sym)
65
- raise ArgumentError, 'cannot overwrite cryptographic key attributes'
66
- end
65
+ raise ArgumentError, 'cannot overwrite cryptographic key attributes' if HMAC_KEY_ELEMENTS.include?(key.to_sym)
67
66
 
68
67
  super(key, value)
69
68
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # Base for JWK implementations
5
6
  class KeyBase
6
7
  def self.inherited(klass)
7
8
  super
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # @api private
5
6
  class KeyFinder
6
7
  def initialize(options)
7
8
  @allow_nil_kid = options[:allow_nil_kid]
@@ -2,6 +2,7 @@
2
2
 
3
3
  module JWT
4
4
  module JWK
5
+ # @api private
5
6
  class KidAsKeyDigest
6
7
  def initialize(jwk)
7
8
  @jwk = jwk