jwt 2.0.0 → 2.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c63d3d103ec14f12ea2b51b95ae8f5407dd7ace9
4
- data.tar.gz: f1de3f1e8ddfb79aa690a1f6d44492c70d037942
3
+ metadata.gz: 0fca109273d0c036454af123d30bb3eb75f0de39
4
+ data.tar.gz: 8848296d35465d3411f71d882da73ef05663f6a6
5
5
  SHA512:
6
- metadata.gz: 3b19fcd5018d17e4277a49abc5787cee37ff3991fc8cbcc97dbb00f50c3878fc08062d97e18e07cdaf5f8f2f09cfbf5a8937e11859ae9b44d90a8d5a20caa021
7
- data.tar.gz: f9df1adefd0f0d4525567372c8283e72639b2ee67320a893ef03d470bbbd6afd09a65725d3eb3153f8c68e7d40f693c7da3a5ed138ab766a23aa6ebbfe5c62f6
6
+ metadata.gz: 213d4ea31197a90be8b8cd08ea92dee4659f47b884bc3571440697db979cf98b04e3d1cf487bc94a7a8a8f3f29ee34ebf48d7cc5bd9cfa9f2ca65a092bb2c3d3
7
+ data.tar.gz: 530335d90320cdc5501cc1f67984502f79a390641b904567971ad4858a285128cc4702dbf54d505324bcb1ea3ecdf5675057c942e9709ecf0f17b4099229c04d
data/.ebert.yml CHANGED
@@ -1,4 +1,4 @@
1
- styleguide: plataformatec/linters
1
+ styleguide: excpt/linters
2
2
  engines:
3
3
  reek:
4
4
  enabled: true
@@ -6,6 +6,7 @@ engines:
6
6
  enabled: true
7
7
  rubocop:
8
8
  enabled: true
9
+ channel: rubocop-0-49
9
10
  duplication:
10
11
  config:
11
12
  languages:
@@ -1,5 +1,36 @@
1
1
  # Change Log
2
2
 
3
+ ## [2.1.0](https://github.com/jwt/ruby-jwt/tree/2.1.0) (2017-10-06)
4
+ [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.0.0...2.1.0)
5
+
6
+ **Implemented enhancements:**
7
+
8
+ - Ed25519 support planned? [\#217](https://github.com/jwt/ruby-jwt/issues/217)
9
+ - Verify JTI Proc [\#207](https://github.com/jwt/ruby-jwt/issues/207)
10
+ - Allow a list of algorithms for decode [\#241](https://github.com/jwt/ruby-jwt/pull/241) ([lautis](https://github.com/lautis))
11
+ - verify takes 2 params, second being payload closes: \#207 [\#238](https://github.com/jwt/ruby-jwt/pull/238) ([ab320012](https://github.com/ab320012))
12
+ - simplified logic for keyfinder [\#237](https://github.com/jwt/ruby-jwt/pull/237) ([ab320012](https://github.com/ab320012))
13
+ - Show backtrace if rbnacl-libsodium not loaded [\#231](https://github.com/jwt/ruby-jwt/pull/231) ([buzztaiki](https://github.com/buzztaiki))
14
+ - Support for ED25519 [\#229](https://github.com/jwt/ruby-jwt/pull/229) ([ab320012](https://github.com/ab320012))
15
+
16
+ **Fixed bugs:**
17
+
18
+ - JWT.encode failing on encode for string [\#235](https://github.com/jwt/ruby-jwt/issues/235)
19
+ - The README says it uses an algorithm by default [\#226](https://github.com/jwt/ruby-jwt/issues/226)
20
+ - Fix string payload issue [\#236](https://github.com/jwt/ruby-jwt/pull/236) ([excpt](https://github.com/excpt))
21
+
22
+ **Closed issues:**
23
+
24
+ - Change from 1.5.6 to 2.0.0 and appears a "Completed 401 Unauthorized" [\#240](https://github.com/jwt/ruby-jwt/issues/240)
25
+ - Why doesn't the decode function use a default algorithm? [\#227](https://github.com/jwt/ruby-jwt/issues/227)
26
+
27
+ **Merged pull requests:**
28
+
29
+ - Update README.md [\#242](https://github.com/jwt/ruby-jwt/pull/242) ([excpt](https://github.com/excpt))
30
+ - Update ebert configuration [\#232](https://github.com/jwt/ruby-jwt/pull/232) ([excpt](https://github.com/excpt))
31
+ - added algos/strategy classes + structs for inputs [\#230](https://github.com/jwt/ruby-jwt/pull/230) ([ab320012](https://github.com/ab320012))
32
+ - Add HS256 algorithm to decode default options [\#228](https://github.com/jwt/ruby-jwt/pull/228) ([madkin10](https://github.com/madkin10))
33
+
3
34
  ## [v2.0.0](https://github.com/jwt/ruby-jwt/tree/v2.0.0) (2017-09-03)
4
35
  [Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.0.0.beta1...v2.0.0)
5
36
 
@@ -18,6 +49,7 @@
18
49
 
19
50
  **Merged pull requests:**
20
51
 
52
+ - Release 2.0.0 preparations :\) [\#225](https://github.com/jwt/ruby-jwt/pull/225) ([excpt](https://github.com/excpt))
21
53
  - Skip 'exp' claim validation for array payloads [\#224](https://github.com/jwt/ruby-jwt/pull/224) ([excpt](https://github.com/excpt))
22
54
  - Use a default leeway of 0 [\#223](https://github.com/jwt/ruby-jwt/pull/223) ([travisofthenorth](https://github.com/travisofthenorth))
23
55
  - Fix reported codesmells [\#221](https://github.com/jwt/ruby-jwt/pull/221) ([excpt](https://github.com/excpt))
data/README.md CHANGED
@@ -61,9 +61,9 @@ decoded_token = JWT.decode token, nil, false
61
61
  puts decoded_token
62
62
  ```
63
63
 
64
- **HMAC** (default: HS256)
64
+ **HMAC**
65
65
 
66
- * HS256 - HMAC using SHA-256 hash algorithm (default)
66
+ * HS256 - HMAC using SHA-256 hash algorithm
67
67
  * HS512256 - HMAC using SHA-512-256 hash algorithm (only available with RbNaCl; see note below)
68
68
  * HS384 - HMAC using SHA-384 hash algorithm
69
69
  * HS512 - HMAC using SHA-512 hash algorithm
@@ -144,6 +144,35 @@ decoded_token = JWT.decode token, ecdsa_public, true, { :algorithm => 'ES256' }
144
144
  puts decoded_token
145
145
  ```
146
146
 
147
+ **EDDSA**
148
+
149
+ In order to use this algorithm you need to add the `RbNaCl` gem to you `Gemfile`.
150
+
151
+ ```ruby
152
+ gem 'rbnacl'
153
+ ```
154
+
155
+ For more detailed installation instruction check the official [repository](https://github.com/cryptosphere/rbnacl) on GitHub.
156
+
157
+ * ED25519
158
+
159
+ ```ruby
160
+ private_key = RbNaCl::Signatures::Ed25519::SigningKey.new("abcdefghijklmnopqrstuvwxyzABCDEF")
161
+ public_key = private_key.verify_key
162
+ token = JWT.encode payload, private_key, 'ED25519'
163
+
164
+ # eyJhbGciOiJFRDI1NTE5In0.eyJ0ZXN0IjoiZGF0YSJ9.-Ki0vxVOlsPXovPsYRT_9OXrLSgQd4RDAgCLY_PLmcP4q32RYy-yUUmX82ycegdekR9wo26me1wOzjmSU5nTCQ
165
+ puts token
166
+
167
+ decoded_token = JWT.decode token, public_key, true, {:algorithm => 'ED25519' }
168
+ # Array
169
+ # [
170
+ # {"test"=>"data"}, # payload
171
+ # {"alg"=>"ED25519"} # header
172
+ # ]
173
+
174
+ ```
175
+
147
176
  **RSASSA-PSS**
148
177
 
149
178
  Not implemented.
data/lib/jwt.rb CHANGED
@@ -41,21 +41,23 @@ module JWT
41
41
  def decode_verify_signature(key, header, payload, signature, signing_input, options, &keyfinder)
42
42
  algo, key = signature_algorithm_and_key(header, payload, key, &keyfinder)
43
43
 
44
- raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') unless options[:algorithm]
45
- raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') unless algo == options[:algorithm]
44
+ raise(JWT::IncorrectAlgorithm, 'An algorithm must be specified') if allowed_algorithms(options).empty?
45
+ raise(JWT::IncorrectAlgorithm, 'Expected a different algorithm') unless allowed_algorithms(options).include?(algo)
46
46
 
47
47
  Signature.verify(algo, key, signing_input, signature)
48
48
  end
49
49
 
50
50
  def signature_algorithm_and_key(header, payload, key, &keyfinder)
51
- if keyfinder
52
- key = if keyfinder.arity == 2
53
- yield(header, payload)
54
- else
55
- yield(header)
56
- end
57
- raise JWT::DecodeError, 'No verification key available' unless key
58
- end
51
+ key = (keyfinder.arity == 2 ? yield(header, payload) : yield(header)) if keyfinder
52
+ raise JWT::DecodeError, 'No verification key available' unless key
59
53
  [header['alg'], key]
60
54
  end
55
+
56
+ def allowed_algorithms(options)
57
+ if options.key?(:algorithm)
58
+ [options[:algorithm]]
59
+ else
60
+ options[:algorithms] || []
61
+ end
62
+ end
61
63
  end
@@ -0,0 +1,35 @@
1
+ module JWT
2
+ module Algos
3
+ module Ecdsa
4
+ module_function
5
+
6
+ SUPPORTED = %(ES256 ES384 ES512).freeze
7
+ NAMED_CURVES = {
8
+ 'prime256v1' => 'ES256',
9
+ 'secp384r1' => 'ES384',
10
+ 'secp521r1' => 'ES512'
11
+ }.freeze
12
+
13
+ def sign(to_sign)
14
+ algorithm, msg, key = to_sign.values
15
+ key_algorithm = NAMED_CURVES[key.group.curve_name]
16
+ if algorithm != key_algorithm
17
+ raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided"
18
+ end
19
+
20
+ digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
21
+ SecurityUtils.asn1_to_raw(key.dsa_sign_asn1(digest.digest(msg)), key)
22
+ end
23
+
24
+ def verify(to_verify)
25
+ algorithm, public_key, signing_input, signature = to_verify.values
26
+ key_algorithm = NAMED_CURVES[public_key.group.curve_name]
27
+ if algorithm != key_algorithm
28
+ raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
29
+ end
30
+ digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
31
+ public_key.dsa_verify_asn1(digest.digest(signing_input), SecurityUtils.raw_to_asn1(signature, public_key))
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ module JWT
2
+ module Algos
3
+ module Eddsa
4
+ module_function
5
+
6
+ SUPPORTED = %w[ED25519].freeze
7
+
8
+ def sign(to_sign)
9
+ algorithm, msg, key = to_sign.values
10
+ raise EncodeError, "Key given is a #{key.class} but has to be an RbNaCl::Signatures::Ed25519::SigningKey" if key.class != RbNaCl::Signatures::Ed25519::SigningKey
11
+ raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key.primitive} signing key was provided" if algorithm.downcase.to_sym != key.primitive
12
+ key.sign(msg)
13
+ end
14
+
15
+ def verify(to_verify)
16
+ algorithm, public_key, signing_input, signature = to_verify.values
17
+ raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{public_key.primitive} verification key was provided" if algorithm.downcase.to_sym != public_key.primitive
18
+ 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
19
+ public_key.verify(signature, signing_input)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ module JWT
2
+ module Algos
3
+ module Hmac
4
+ module_function
5
+
6
+ SUPPORTED = %w[HS256 HS512256 HS384 HS512].freeze
7
+
8
+ def sign(to_sign)
9
+ algorithm, msg, key = to_sign.values
10
+ authenticator, padded_key = SecurityUtils.rbnacl_fixup(algorithm, key)
11
+ if authenticator && padded_key
12
+ authenticator.auth(padded_key, msg.encode('binary'))
13
+ else
14
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
15
+ end
16
+ end
17
+
18
+ def verify(to_verify)
19
+ algorithm, public_key, signing_input, signature = to_verify.values
20
+ authenticator, padded_key = SecurityUtils.rbnacl_fixup(algorithm, public_key)
21
+ if authenticator && padded_key
22
+ begin
23
+ authenticator.verify(padded_key, signature.encode('binary'), signing_input.encode('binary'))
24
+ rescue RbNaCl::BadAuthenticatorError
25
+ false
26
+ end
27
+ else
28
+ SecurityUtils.secure_compare(signature, sign(JWT::Signature::ToSign.new(algorithm, signing_input, public_key)))
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module JWT
2
+ module Algos
3
+ module Rsa
4
+ module_function
5
+
6
+ SUPPORTED = %w[RS256 RS384 RS512].freeze
7
+
8
+ def sign(to_sign)
9
+ 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
11
+ key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
12
+ end
13
+
14
+ def verify(to_verify)
15
+ SecurityUtils.verify_rsa(to_verify.algorithm, to_verify.public_key, to_verify.signing_input, to_verify.signature)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ module JWT
2
+ module Algos
3
+ module Unsupported
4
+ module_function
5
+
6
+ SUPPORTED = Object.new.tap { |object| object.define_singleton_method(:include?) { |*| true } }
7
+ def verify(*)
8
+ raise JWT::VerificationError, 'Algorithm not supported'
9
+ end
10
+
11
+ def sign(*)
12
+ raise NotImplementedError, 'Unsupported signing method'
13
+ end
14
+ end
15
+ end
16
+ end
@@ -8,7 +8,8 @@ module JWT
8
8
  verify_jti: false,
9
9
  verify_aud: false,
10
10
  verify_sub: false,
11
- leeway: 0
11
+ leeway: 0,
12
+ algorithms: ['HS256']
12
13
  }.freeze
13
14
  end
14
15
  end
@@ -28,7 +28,7 @@ module JWT
28
28
  end
29
29
 
30
30
  def encoded_payload
31
- raise InvalidPayload, 'exp claim must be an integer' if @payload && !@payload.is_a?(Array) && @payload.key?('exp') && !@payload['exp'].is_a?(Integer)
31
+ raise InvalidPayload, 'exp claim must be an integer' if @payload && @payload.is_a?(Hash) && @payload.key?('exp') && !@payload['exp'].is_a?(Integer)
32
32
  Encode.base64url_encode(JSON.generate(@payload))
33
33
  end
34
34
 
@@ -3,7 +3,6 @@ module JWT
3
3
  #
4
4
  # @see: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/security_utils.rb
5
5
  module SecurityUtils
6
-
7
6
  module_function
8
7
 
9
8
  def secure_compare(left, right)
@@ -2,10 +2,15 @@
2
2
 
3
3
  require 'jwt/security_utils'
4
4
  require 'openssl'
5
+ require 'jwt/algos/hmac'
6
+ require 'jwt/algos/eddsa'
7
+ require 'jwt/algos/ecdsa'
8
+ require 'jwt/algos/rsa'
9
+ require 'jwt/algos/unsupported'
5
10
  begin
6
11
  require 'rbnacl'
7
- rescue LoadError => e
8
- abort(e.message) if defined?(RbNaCl)
12
+ rescue LoadError
13
+ raise if defined?(RbNaCl)
9
14
  end
10
15
 
11
16
  # JWT::Signature module
@@ -13,94 +18,33 @@ module JWT
13
18
  # Signature logic for JWT
14
19
  module Signature
15
20
  extend self
16
-
17
- HMAC_ALGORITHMS = %w[HS256 HS512256 HS384 HS512].freeze
18
- RSA_ALGORITHMS = %w[RS256 RS384 RS512].freeze
19
- ECDSA_ALGORITHMS = %w[ES256 ES384 ES512].freeze
20
-
21
- NAMED_CURVES = {
22
- 'prime256v1' => 'ES256',
23
- 'secp384r1' => 'ES384',
24
- 'secp521r1' => 'ES512'
25
- }.freeze
21
+ ALGOS = [
22
+ Algos::Hmac,
23
+ Algos::Ecdsa,
24
+ Algos::Rsa,
25
+ Algos::Eddsa,
26
+ Algos::Unsupported
27
+ ].freeze
28
+ ToSign = Struct.new(:algorithm, :msg, :key)
29
+ ToVerify = Struct.new(:algorithm, :public_key, :signing_input, :signature)
26
30
 
27
31
  def sign(algorithm, msg, key)
28
- if HMAC_ALGORITHMS.include?(algorithm)
29
- sign_hmac(algorithm, msg, key)
30
- elsif RSA_ALGORITHMS.include?(algorithm)
31
- sign_rsa(algorithm, msg, key)
32
- elsif ECDSA_ALGORITHMS.include?(algorithm)
33
- sign_ecdsa(algorithm, msg, key)
34
- else
35
- raise NotImplementedError, 'Unsupported signing method'
32
+ algo = ALGOS.find do |alg|
33
+ alg.const_get(:SUPPORTED).include? algorithm
36
34
  end
35
+ algo.sign ToSign.new(algorithm, msg, key)
37
36
  end
38
37
 
39
- def verify(algo, key, signing_input, signature)
40
- verified = if HMAC_ALGORITHMS.include?(algo)
41
- verify_hmac(algo, key, signing_input, signature)
42
- elsif RSA_ALGORITHMS.include?(algo)
43
- SecurityUtils.verify_rsa(algo, key, signing_input, signature)
44
- elsif ECDSA_ALGORITHMS.include?(algo)
45
- verify_ecdsa(algo, key, signing_input, signature)
46
- else
47
- raise JWT::VerificationError, 'Algorithm not supported'
38
+ def verify(algorithm, key, signing_input, signature)
39
+ algo = ALGOS.find do |alg|
40
+ alg.const_get(:SUPPORTED).include? algorithm
48
41
  end
49
-
42
+ verified = algo.verify(ToVerify.new(algorithm, key, signing_input, signature))
50
43
  raise(JWT::VerificationError, 'Signature verification raised') unless verified
51
44
  rescue OpenSSL::PKey::PKeyError
52
45
  raise JWT::VerificationError, 'Signature verification raised'
53
46
  ensure
54
47
  OpenSSL.errors.clear
55
48
  end
56
-
57
- private
58
-
59
- def sign_rsa(algorithm, msg, private_key)
60
- raise EncodeError, "The given key is a #{private_key.class}. It has to be an OpenSSL::PKey::RSA instance." if private_key.class == String
61
- private_key.sign(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), msg)
62
- end
63
-
64
- def sign_ecdsa(algorithm, msg, private_key)
65
- key_algorithm = NAMED_CURVES[private_key.group.curve_name]
66
- if algorithm != key_algorithm
67
- raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided"
68
- end
69
-
70
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
71
- SecurityUtils.asn1_to_raw(private_key.dsa_sign_asn1(digest.digest(msg)), private_key)
72
- end
73
-
74
- def sign_hmac(algorithm, msg, key)
75
- authenticator, padded_key = SecurityUtils.rbnacl_fixup(algorithm, key)
76
- if authenticator && padded_key
77
- authenticator.auth(padded_key, msg.encode('binary'))
78
- else
79
- OpenSSL::HMAC.digest(OpenSSL::Digest.new(algorithm.sub('HS', 'sha')), key, msg)
80
- end
81
- end
82
-
83
- def verify_ecdsa(algorithm, public_key, signing_input, signature)
84
- key_algorithm = NAMED_CURVES[public_key.group.curve_name]
85
- if algorithm != key_algorithm
86
- raise IncorrectAlgorithm, "payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided"
87
- end
88
-
89
- digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
90
- public_key.dsa_verify_asn1(digest.digest(signing_input), SecurityUtils.raw_to_asn1(signature, public_key))
91
- end
92
-
93
- def verify_hmac(algorithm, public_key, signing_input, signature)
94
- authenticator, padded_key = SecurityUtils.rbnacl_fixup(algorithm, public_key)
95
- if authenticator && padded_key
96
- begin
97
- authenticator.verify(padded_key, signature.encode('binary'), signing_input.encode('binary'))
98
- rescue RbNaCl::BadAuthenticatorError
99
- false
100
- end
101
- else
102
- SecurityUtils.secure_compare(signature, sign_hmac(algorithm, signing_input, public_key))
103
- end
104
- end
105
49
  end
106
50
  end
@@ -52,9 +52,9 @@ module JWT
52
52
  return unless (options_iss = @options[:iss])
53
53
 
54
54
  iss = @payload['iss']
55
-
55
+
56
56
  return if Array(options_iss).map(&:to_s).include?(iss.to_s)
57
-
57
+
58
58
  raise(JWT::InvalidIssuerError, "Invalid issuer. Expected #{options_iss}, received #{iss || '<none>'}")
59
59
  end
60
60
 
@@ -63,7 +63,8 @@ module JWT
63
63
  jti = @payload['jti']
64
64
 
65
65
  if options_verify_jti.respond_to?(:call)
66
- raise(JWT::InvalidJtiError, 'Invalid jti') unless options_verify_jti.call(jti)
66
+ verified = options_verify_jti.arity == 2 ? options_verify_jti.call(jti, @payload) : options_verify_jti.call(jti)
67
+ raise(JWT::InvalidJtiError, 'Invalid jti') unless verified
67
68
  elsif jti.to_s.strip.empty?
68
69
  raise(JWT::InvalidJtiError, 'Missing jti')
69
70
  end
@@ -12,7 +12,7 @@ module JWT
12
12
  # major version
13
13
  MAJOR = 2
14
14
  # minor version
15
- MINOR = 0
15
+ MINOR = 1
16
16
  # tiny version
17
17
  TINY = 0
18
18
  # alpha, beta, etc. tag
@@ -182,6 +182,19 @@ module JWT
182
182
  it 'true proc should not raise JWT::InvalidJtiError' do
183
183
  Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { true }))
184
184
  end
185
+
186
+ it 'it should not throw arguement error with 2 args' do
187
+ expect do
188
+ Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti, pl) {
189
+ true
190
+ }))
191
+ end.to_not raise_error
192
+ end
193
+ it 'should have payload as second param in proc' do
194
+ Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti, pl) {
195
+ expect(pl).to eq(payload)
196
+ }))
197
+ end
185
198
  end
186
199
 
187
200
  context '.verify_not_before(payload, options)' do
@@ -19,6 +19,8 @@ describe JWT do
19
19
  'ES384_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-public.pem'))),
20
20
  'ES512_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-private.pem'))),
21
21
  'ES512_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-public.pem'))),
22
+ 'ED25519_private' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF'),
23
+ 'ED25519_public' => RbNaCl::Signatures::Ed25519::SigningKey.new('abcdefghijklmnopqrstuvwxyzABCDEF').verify_key,
22
24
  'NONE' => 'eyJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.',
23
25
  'HS256' => 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.kWOVtIOpWcG7JnyJG0qOkTDbOy636XrrQhMm_8JrRQ8',
24
26
  'HS512256' => 'eyJhbGciOiJIUzUxMjI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Ds_4ibvf7z4QOBoKntEjDfthy3WJ-3rKMspTEcHE2bA',
@@ -132,6 +134,41 @@ describe JWT do
132
134
  end
133
135
  end
134
136
 
137
+ %w[ED25519].each do |alg|
138
+ context "alg: #{alg}" do
139
+ before(:each) do
140
+ data[alg] = JWT.encode payload, data["#{alg}_private"], alg
141
+ end
142
+
143
+ let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) }
144
+
145
+ it 'should generate a valid token' do
146
+ jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
147
+
148
+ expect(header['alg']).to eq alg
149
+ expect(jwt_payload).to eq payload
150
+ end
151
+
152
+ it 'should decode a valid token' do
153
+ jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
154
+
155
+ expect(header['alg']).to eq alg
156
+ expect(jwt_payload).to eq payload
157
+ end
158
+
159
+ it 'wrong key should raise JWT::DecodeError' do
160
+ expect do
161
+ JWT.decode data[alg], wrong_key
162
+ end.to raise_error JWT::DecodeError
163
+ end
164
+
165
+ it 'wrong key and verify = false should not raise JWT::DecodeError' do
166
+ expect do
167
+ JWT.decode data[alg], wrong_key, false
168
+ end.not_to raise_error
169
+ end
170
+ end
171
+ end
135
172
  %w[ES256 ES384 ES512].each do |alg|
136
173
  context "alg: #{alg}" do
137
174
  before(:each) do
@@ -194,24 +231,39 @@ describe JWT do
194
231
 
195
232
  context 'Verify' do
196
233
  context 'algorithm' do
197
- it 'should raise JWT::IncorrectAlgorithm on missmatch' do
198
- token = JWT.encode payload, data[:secret], 'HS512'
234
+ it 'should raise JWT::IncorrectAlgorithm on mismatch' do
235
+ token = JWT.encode payload, data[:secret], 'HS256'
199
236
 
200
237
  expect do
201
238
  JWT.decode token, data[:secret], true, algorithm: 'HS384'
202
239
  end.to raise_error JWT::IncorrectAlgorithm
203
240
 
204
241
  expect do
205
- JWT.decode token, data[:secret], true, algorithm: 'HS512'
242
+ JWT.decode token, data[:secret], true, algorithm: 'HS256'
206
243
  end.not_to raise_error
207
244
  end
208
245
 
209
- it 'should raise JWT::IncorrectAlgorithm if no algorithm is provided' do
210
- token = JWT.encode payload, data[:rsa_public].to_s, 'HS256'
246
+ it 'should raise JWT::IncorrectAlgorithm when algorithms array does not contain algorithm' do
247
+ token = JWT.encode payload, data[:secret], 'HS512'
211
248
 
212
249
  expect do
213
- JWT.decode token, data[:rsa_public], true
250
+ JWT.decode token, data[:secret], true, algorithms: ['HS384']
214
251
  end.to raise_error JWT::IncorrectAlgorithm
252
+
253
+ expect do
254
+ JWT.decode token, data[:secret], true, algorithms: ['HS512', 'HS384']
255
+ end.not_to raise_error
256
+ end
257
+
258
+ context 'no algorithm provided' do
259
+ it 'should use the default decode algorithm' do
260
+ token = JWT.encode payload, data[:rsa_public].to_s
261
+
262
+ jwt_payload, header = JWT.decode token, data[:rsa_public].to_s
263
+
264
+ expect(header['alg']).to eq 'HS256'
265
+ expect(jwt_payload).to eq payload
266
+ end
215
267
  end
216
268
  end
217
269
 
@@ -254,4 +306,10 @@ describe JWT do
254
306
  JWT.encode(['my', 'payload'], 'secret')
255
307
  end.not_to raise_error
256
308
  end
309
+
310
+ it 'should encode string payloads' do
311
+ expect do
312
+ JWT.encode 'Hello World', 'secret'
313
+ end.not_to raise_error
314
+ end
257
315
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Rudat
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-03 00:00:00.000000000 Z
11
+ date: 2017-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -143,6 +143,11 @@ files:
143
143
  - README.md
144
144
  - Rakefile
145
145
  - lib/jwt.rb
146
+ - lib/jwt/algos/ecdsa.rb
147
+ - lib/jwt/algos/eddsa.rb
148
+ - lib/jwt/algos/hmac.rb
149
+ - lib/jwt/algos/rsa.rb
150
+ - lib/jwt/algos/unsupported.rb
146
151
  - lib/jwt/decode.rb
147
152
  - lib/jwt/default_options.rb
148
153
  - lib/jwt/encode.rb