jwt 1.5.6 → 2.7.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 (76) hide show
  1. checksums.yaml +5 -5
  2. data/AUTHORS +119 -0
  3. data/CHANGELOG.md +457 -8
  4. data/CODE_OF_CONDUCT.md +84 -0
  5. data/CONTRIBUTING.md +99 -0
  6. data/README.md +399 -78
  7. data/lib/jwt/algos/algo_wrapper.rb +30 -0
  8. data/lib/jwt/algos/ecdsa.rb +62 -0
  9. data/lib/jwt/algos/eddsa.rb +33 -0
  10. data/lib/jwt/algos/hmac.rb +73 -0
  11. data/lib/jwt/algos/hmac_rbnacl.rb +53 -0
  12. data/lib/jwt/algos/hmac_rbnacl_fixed.rb +52 -0
  13. data/lib/jwt/algos/none.rb +19 -0
  14. data/lib/jwt/algos/ps.rb +41 -0
  15. data/lib/jwt/algos/rsa.rb +21 -0
  16. data/lib/jwt/algos/unsupported.rb +19 -0
  17. data/lib/jwt/algos.rb +67 -0
  18. data/lib/jwt/base64.rb +19 -0
  19. data/lib/jwt/claims_validator.rb +37 -0
  20. data/lib/jwt/configuration/container.rb +21 -0
  21. data/lib/jwt/configuration/decode_configuration.rb +46 -0
  22. data/lib/jwt/configuration/jwk_configuration.rb +27 -0
  23. data/lib/jwt/configuration.rb +15 -0
  24. data/lib/jwt/decode.rb +140 -29
  25. data/lib/jwt/encode.rb +79 -0
  26. data/lib/jwt/error.rb +8 -0
  27. data/lib/jwt/json.rb +10 -9
  28. data/lib/jwt/jwk/ec.rb +236 -0
  29. data/lib/jwt/jwk/hmac.rb +103 -0
  30. data/lib/jwt/jwk/key_base.rb +55 -0
  31. data/lib/jwt/jwk/key_finder.rb +46 -0
  32. data/lib/jwt/jwk/kid_as_key_digest.rb +15 -0
  33. data/lib/jwt/jwk/okp_rbnacl.rb +110 -0
  34. data/lib/jwt/jwk/rsa.rb +203 -0
  35. data/lib/jwt/jwk/set.rb +80 -0
  36. data/lib/jwt/jwk/thumbprint.rb +26 -0
  37. data/lib/jwt/jwk.rb +55 -0
  38. data/lib/jwt/security_utils.rb +32 -0
  39. data/lib/jwt/verify.rb +58 -51
  40. data/lib/jwt/version.rb +24 -4
  41. data/lib/jwt/x5c_key_finder.rb +55 -0
  42. data/lib/jwt.rb +15 -176
  43. data/ruby-jwt.gemspec +19 -10
  44. metadata +51 -101
  45. data/.codeclimate.yml +0 -20
  46. data/.gitignore +0 -11
  47. data/.rspec +0 -1
  48. data/.rubocop.yml +0 -2
  49. data/.travis.yml +0 -13
  50. data/Gemfile +0 -4
  51. data/Manifest +0 -8
  52. data/Rakefile +0 -11
  53. data/spec/fixtures/certs/ec256-private.pem +0 -8
  54. data/spec/fixtures/certs/ec256-public.pem +0 -4
  55. data/spec/fixtures/certs/ec256-wrong-private.pem +0 -8
  56. data/spec/fixtures/certs/ec256-wrong-public.pem +0 -4
  57. data/spec/fixtures/certs/ec384-private.pem +0 -9
  58. data/spec/fixtures/certs/ec384-public.pem +0 -5
  59. data/spec/fixtures/certs/ec384-wrong-private.pem +0 -9
  60. data/spec/fixtures/certs/ec384-wrong-public.pem +0 -5
  61. data/spec/fixtures/certs/ec512-private.pem +0 -10
  62. data/spec/fixtures/certs/ec512-public.pem +0 -6
  63. data/spec/fixtures/certs/ec512-wrong-private.pem +0 -10
  64. data/spec/fixtures/certs/ec512-wrong-public.pem +0 -6
  65. data/spec/fixtures/certs/rsa-1024-private.pem +0 -15
  66. data/spec/fixtures/certs/rsa-1024-public.pem +0 -6
  67. data/spec/fixtures/certs/rsa-2048-private.pem +0 -27
  68. data/spec/fixtures/certs/rsa-2048-public.pem +0 -9
  69. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +0 -27
  70. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +0 -9
  71. data/spec/fixtures/certs/rsa-4096-private.pem +0 -51
  72. data/spec/fixtures/certs/rsa-4096-public.pem +0 -14
  73. data/spec/integration/readme_examples_spec.rb +0 -190
  74. data/spec/jwt/verify_spec.rb +0 -197
  75. data/spec/jwt_spec.rb +0 -240
  76. data/spec/spec_helper.rb +0 -31
@@ -1,190 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative '../spec_helper'
3
- require 'jwt'
4
-
5
- describe 'README.md code test' do
6
- context 'algorithm usage' do
7
- let(:payload) { { data: 'test' } }
8
-
9
- it 'NONE' do
10
- token = JWT.encode payload, nil, 'none'
11
- decoded_token = JWT.decode token, nil, false
12
-
13
- expect(token).to eq 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJkYXRhIjoidGVzdCJ9.'
14
- expect(decoded_token).to eq [
15
- { 'data' => 'test' },
16
- { 'typ' => 'JWT', 'alg' => 'none' }
17
- ]
18
- end
19
-
20
- it 'HMAC' do
21
- token = JWT.encode payload, 'my$ecretK3y', 'HS256'
22
- decoded_token = JWT.decode token, 'my$ecretK3y', false
23
-
24
- expect(token).to eq 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.ZxW8go9hz3ETCSfxFxpwSkYg_602gOPKearsf6DsxgY'
25
- expect(decoded_token).to eq [
26
- { 'data' => 'test' },
27
- { 'typ' => 'JWT', 'alg' => 'HS256' }
28
- ]
29
- end
30
-
31
- it 'RSA' do
32
- rsa_private = OpenSSL::PKey::RSA.generate 2048
33
- rsa_public = rsa_private.public_key
34
-
35
- token = JWT.encode payload, rsa_private, 'RS256'
36
- decoded_token = JWT.decode token, rsa_public, true, algorithm: 'RS256'
37
-
38
- expect(decoded_token).to eq [
39
- { 'data' => 'test' },
40
- { 'typ' => 'JWT', 'alg' => 'RS256' }
41
- ]
42
- end
43
-
44
- it 'ECDSA' do
45
- ecdsa_key = OpenSSL::PKey::EC.new 'prime256v1'
46
- ecdsa_key.generate_key
47
- ecdsa_public = OpenSSL::PKey::EC.new ecdsa_key
48
- ecdsa_public.private_key = nil
49
-
50
- token = JWT.encode payload, ecdsa_key, 'ES256'
51
- decoded_token = JWT.decode token, ecdsa_public, true, algorithm: 'ES256'
52
-
53
- expect(decoded_token).to eq [
54
- { 'data' => 'test' },
55
- { 'typ' => 'JWT', 'alg' => 'ES256' }
56
- ]
57
- end
58
- end
59
-
60
- context 'claims' do
61
- let(:hmac_secret) { 'MyP4ssW0rD' }
62
-
63
- context 'exp' do
64
- it 'without leeway' do
65
- exp = Time.now.to_i + 4 * 3600
66
- exp_payload = { data: 'data', exp: exp }
67
-
68
- token = JWT.encode exp_payload, hmac_secret, 'HS256'
69
-
70
- expect do
71
- JWT.decode token, hmac_secret, true, algorithm: 'HS256'
72
- end.not_to raise_error
73
- end
74
-
75
- it 'with leeway' do
76
- exp = Time.now.to_i - 10
77
- leeway = 30 # seconds
78
-
79
- exp_payload = { data: 'data', exp: exp }
80
-
81
- token = JWT.encode exp_payload, hmac_secret, 'HS256'
82
-
83
- expect do
84
- JWT.decode token, hmac_secret, true, leeway: leeway, algorithm: 'HS256'
85
- end.not_to raise_error
86
- end
87
- end
88
-
89
- context 'nbf' do
90
- it 'without leeway' do
91
- nbf = Time.now.to_i - 3600
92
- nbf_payload = { data: 'data', nbf: nbf }
93
- token = JWT.encode nbf_payload, hmac_secret, 'HS256'
94
-
95
- expect do
96
- JWT.decode token, hmac_secret, true, algorithm: 'HS256'
97
- end.not_to raise_error
98
- end
99
-
100
- it 'with leeway' do
101
- nbf = Time.now.to_i + 10
102
- leeway = 30
103
- nbf_payload = { data: 'data', nbf: nbf }
104
- token = JWT.encode nbf_payload, hmac_secret, 'HS256'
105
-
106
- expect do
107
- JWT.decode token, hmac_secret, true, leeway: leeway, algorithm: 'HS256'
108
- end.not_to raise_error
109
- end
110
- end
111
-
112
- it 'iss' do
113
- iss = 'My Awesome Company Inc. or https://my.awesome.website/'
114
- iss_payload = { data: 'data', iss: iss }
115
-
116
- token = JWT.encode iss_payload, hmac_secret, 'HS256'
117
-
118
- expect do
119
- JWT.decode token, hmac_secret, true, iss: iss, algorithm: 'HS256'
120
- end.not_to raise_error
121
- end
122
-
123
- context 'aud' do
124
- it 'array' do
125
- aud = %w(Young Old)
126
- aud_payload = { data: 'data', aud: aud }
127
-
128
- token = JWT.encode aud_payload, hmac_secret, 'HS256'
129
-
130
- expect do
131
- JWT.decode token, hmac_secret, true, aud: %w(Old Young), verify_aud: true, algorithm: 'HS256'
132
- end.not_to raise_error
133
- end
134
-
135
- it 'string' do
136
- expect do
137
- end.not_to raise_error
138
- end
139
- end
140
-
141
- it 'jti' do
142
- iat = Time.now.to_i
143
- hmac_secret = 'test'
144
- jti_raw = [hmac_secret, iat].join(':').to_s
145
- jti = Digest::MD5.hexdigest(jti_raw)
146
- jti_payload = { data: 'data', iat: iat, jti: jti }
147
-
148
- token = JWT.encode jti_payload, hmac_secret, 'HS256'
149
-
150
- expect do
151
- JWT.decode token, hmac_secret, true, verify_jti: true, algorithm: 'HS256'
152
- end.not_to raise_error
153
- end
154
-
155
- context 'iat' do
156
- it 'without leeway' do
157
- iat = Time.now.to_i
158
- iat_payload = { data: 'data', iat: iat }
159
-
160
- token = JWT.encode iat_payload, hmac_secret, 'HS256'
161
-
162
- expect do
163
- JWT.decode token, hmac_secret, true, verify_iat: true, algorithm: 'HS256'
164
- end.not_to raise_error
165
- end
166
-
167
- it 'with leeway' do
168
- iat = Time.now.to_i - 7
169
- iat_payload = { data: 'data', iat: iat, leeway: 10 }
170
-
171
- token = JWT.encode iat_payload, hmac_secret, 'HS256'
172
-
173
- expect do
174
- JWT.decode token, hmac_secret, true, verify_iat: true, algorithm: 'HS256'
175
- end.not_to raise_error
176
- end
177
- end
178
-
179
- it 'sub' do
180
- sub = 'Subject'
181
- sub_payload = { data: 'data', sub: sub }
182
-
183
- token = JWT.encode sub_payload, hmac_secret, 'HS256'
184
-
185
- expect do
186
- JWT.decode token, hmac_secret, true, 'sub' => sub, :verify_sub => true, :algorithm => 'HS256'
187
- end.not_to raise_error
188
- end
189
- end
190
- end
@@ -1,197 +0,0 @@
1
- # frozen_string_literal: true
2
- require 'spec_helper'
3
- require 'jwt/verify'
4
-
5
- module JWT
6
- RSpec.describe Verify do
7
- let(:base_payload) { { 'user_id' => 'some@user.tld' } }
8
- let(:options) { { leeway: 0 } }
9
-
10
- context '.verify_aud(payload, options)' do
11
- let(:scalar_aud) { 'ruby-jwt-audience' }
12
- let(:array_aud) { %w(ruby-jwt-aud test-aud ruby-ruby-ruby) }
13
- let(:scalar_payload) { base_payload.merge('aud' => scalar_aud) }
14
- let(:array_payload) { base_payload.merge('aud' => array_aud) }
15
-
16
- it 'must raise JWT::InvalidAudError when the singular audience does not match' do
17
- expect do
18
- Verify.verify_aud(scalar_payload, options.merge(aud: 'no-match'))
19
- end.to raise_error JWT::InvalidAudError
20
- end
21
-
22
- it 'must raise JWT::InvalidAudError when the payload has an array and none match the supplied value' do
23
- expect do
24
- Verify.verify_aud(array_payload, options.merge(aud: 'no-match'))
25
- end.to raise_error JWT::InvalidAudError
26
- end
27
-
28
- it 'must raise JWT::InvalidAudError when the singular audience does not match and the options aud key is a string' do
29
- expect do
30
- Verify.verify_aud(scalar_payload, options.merge('aud' => 'no-match'))
31
- end.to raise_error JWT::InvalidAudError
32
- end
33
-
34
- it 'must allow a matching singular audience to pass' do
35
- Verify.verify_aud(scalar_payload, options.merge(aud: scalar_aud))
36
- end
37
-
38
- it 'must allow a matching audence to pass when the options key is a string' do
39
- Verify.verify_aud(scalar_payload, options.merge('aud' => scalar_aud))
40
- end
41
-
42
- it 'must allow an array with any value matching the one in the options' do
43
- Verify.verify_aud(array_payload, options.merge(aud: array_aud.first))
44
- end
45
-
46
- it 'must allow an array with any value matching the one in the options with a string options key' do
47
- Verify.verify_aud(array_payload, options.merge('aud' => array_aud.first))
48
- end
49
-
50
- it 'should allow strings or symbolds in options array' do
51
- options['aud'] = [
52
- 'ruby-jwt-aud',
53
- 'test-aud',
54
- 'ruby-ruby-ruby',
55
- :test
56
- ]
57
-
58
- array_payload['aud'].push('test')
59
-
60
- Verify.verify_aud(array_payload, options)
61
- end
62
- end
63
-
64
- context '.verify_expiration(payload, options)' do
65
- let(:leeway) { 10 }
66
- let(:payload) { base_payload.merge('exp' => (Time.now.to_i - 5)) }
67
-
68
- it 'must raise JWT::ExpiredSignature when the token has expired' do
69
- expect do
70
- Verify.verify_expiration(payload, options)
71
- end.to raise_error JWT::ExpiredSignature
72
- end
73
-
74
- it 'must allow some leeway in the expiration when configured' do
75
- Verify.verify_expiration(payload, options.merge(leeway: 10))
76
- end
77
-
78
- it 'must be expired if the exp claim equals the current time' do
79
- payload['exp'] = Time.now.to_i
80
-
81
- expect do
82
- Verify.verify_expiration(payload, options)
83
- end.to raise_error JWT::ExpiredSignature
84
- end
85
- end
86
-
87
- context '.verify_iat(payload, options)' do
88
- let(:iat) { Time.now.to_f }
89
- let(:payload) { base_payload.merge('iat' => iat) }
90
-
91
- it 'must allow a valid iat' do
92
- Verify.verify_iat(payload, options)
93
- end
94
-
95
- it 'must allow configured leeway' do
96
- Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(leeway: 70))
97
- end
98
-
99
- it 'must properly handle integer times' do
100
- Verify.verify_iat(payload.merge('iat' => Time.now.to_i), options)
101
- end
102
-
103
- it 'must raise JWT::InvalidIatError when the iat value is not Numeric' do
104
- expect do
105
- Verify.verify_iat(payload.merge('iat' => 'not a number'), options)
106
- end.to raise_error JWT::InvalidIatError
107
- end
108
-
109
- it 'must raise JWT::InvalidIatError when the iat value is in the future' do
110
- expect do
111
- Verify.verify_iat(payload.merge('iat' => (iat + 120)), options)
112
- end.to raise_error JWT::InvalidIatError
113
- end
114
- end
115
-
116
- context '.verify_iss(payload, options)' do
117
- let(:iss) { 'ruby-jwt-gem' }
118
- let(:payload) { base_payload.merge('iss' => iss) }
119
-
120
- let(:invalid_token) { JWT.encode base_payload, payload[:secret] }
121
-
122
- it 'must raise JWT::InvalidIssuerError when the configured issuer does not match the payload issuer' do
123
- expect do
124
- Verify.verify_iss(payload, options.merge(iss: 'mismatched-issuer'))
125
- end.to raise_error JWT::InvalidIssuerError
126
- end
127
-
128
- it 'must raise JWT::InvalidIssuerError when the payload does not include an issuer' do
129
- expect do
130
- Verify.verify_iss(base_payload, options.merge(iss: iss))
131
- end.to raise_error(JWT::InvalidIssuerError, /received <none>/)
132
- end
133
-
134
- it 'must allow a matching issuer to pass' do
135
- Verify.verify_iss(payload, options.merge(iss: iss))
136
- end
137
- end
138
-
139
- context '.verify_jti(payload, options)' do
140
- let(:payload) { base_payload.merge('jti' => 'some-random-uuid-or-whatever') }
141
-
142
- it 'must allow any jti when the verfy_jti key in the options is truthy but not a proc' do
143
- Verify.verify_jti(payload, options.merge(verify_jti: true))
144
- end
145
-
146
- it 'must raise JWT::InvalidJtiError when the jti is missing' do
147
- expect do
148
- Verify.verify_jti(base_payload, options)
149
- end.to raise_error JWT::InvalidJtiError, /missing/i
150
- end
151
-
152
- it 'must raise JWT::InvalidJtiError when the jti is an empty string' do
153
- expect do
154
- Verify.verify_jti(base_payload.merge('jti' => ' '), options)
155
- end.to raise_error JWT::InvalidJtiError, /missing/i
156
- end
157
-
158
- it 'must raise JWT::InvalidJtiError when verify_jti proc returns false' do
159
- expect do
160
- Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { false }))
161
- end.to raise_error JWT::InvalidJtiError, /invalid/i
162
- end
163
-
164
- it 'true proc should not raise JWT::InvalidJtiError' do
165
- Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { true }))
166
- end
167
- end
168
-
169
- context '.verify_not_before(payload, options)' do
170
- let(:payload) { base_payload.merge('nbf' => (Time.now.to_i + 5)) }
171
-
172
- it 'must raise JWT::ImmatureSignature when the nbf in the payload is in the future' do
173
- expect do
174
- Verify.verify_not_before(payload, options)
175
- end.to raise_error JWT::ImmatureSignature
176
- end
177
-
178
- it 'must allow some leeway in the token age when configured' do
179
- Verify.verify_not_before(payload, options.merge(leeway: 10))
180
- end
181
- end
182
-
183
- context '.verify_sub(payload, options)' do
184
- let(:sub) { 'ruby jwt subject' }
185
-
186
- it 'must raise JWT::InvalidSubError when the subjects do not match' do
187
- expect do
188
- Verify.verify_sub(base_payload.merge('sub' => 'not-a-match'), options.merge(sub: sub))
189
- end.to raise_error JWT::InvalidSubError
190
- end
191
-
192
- it 'must allow a matching sub' do
193
- Verify.verify_sub(base_payload.merge('sub' => sub), options.merge(sub: sub))
194
- end
195
- end
196
- end
197
- end
data/spec/jwt_spec.rb DELETED
@@ -1,240 +0,0 @@
1
- require 'spec_helper'
2
- require 'jwt'
3
- require 'jwt/decode'
4
-
5
- describe JWT do
6
- let(:payload) { { 'user_id' => 'some@user.tld' } }
7
-
8
- let :data do
9
- {
10
- :secret => 'My$ecretK3y',
11
- :rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-private.pem'))),
12
- :rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-public.pem'))),
13
- :wrong_rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))),
14
- :wrong_rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))),
15
- 'ES256_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-private.pem'))),
16
- 'ES256_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-public.pem'))),
17
- 'ES384_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-private.pem'))),
18
- 'ES384_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-public.pem'))),
19
- 'ES512_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-private.pem'))),
20
- 'ES512_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-public.pem'))),
21
- 'NONE' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.',
22
- 'HS256' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.tCGvlClld0lbQ3NZaH8y53n5RSBr3zlS4Oy5bXqvzZQ',
23
- 'HS384' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.sj1gc01SawlJSrPZgmveifJ8CzZRYAWjejWm4FRaGaAISESJ9Ncf12fCz2vHrITm',
24
- 'HS512' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.isjhsWMZpRQOWw6LKtlY4L6tMDNkLr0qZ3bQe_xRFXWhzVvJlkclTbLVa1J6Dlj2WyZ_I1jEobTaFMDoXPzwWg',
25
- 'RS256' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.u82QrhjZTtwve5akvfWS_4LPywbkb1Yp0nUwZJWtTW0ID7dY9rRiQF5KGj2UDLZotqRlUjyNQgE_hB5BBzICDQdCjQHQoYWE5n_D2wV4PMu7Qg3FVKoBFbf8ee6irodu10fgYxpUIZtvbWw52_6k6A9IoSLSzx_lCcxoVGdW90dUuKhBcZkDtY5WNuQg7MiDthupSL1-V4Y1jmT_7o8tLNGFiocyZfGNw4yGpEOGNvD5WePNit0xsnbj6dEquovUvSFKsMaQXp2PVDEkLOiLMcyk0RrHqrHw2eNSCquWTH8PhX5Up-CVmjQM5zF9ibkaiq8NyPtsy-7rgtbyVMqXBQ',
26
- 'RS384' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.2_jPwOsUWJ-3r6lXMdJGPdhLNJQSSEmY2mrDXCwNJk-2YhMIqKAzJJCbyso_A1hS7BVkXmHt54RCcNJXroZBOgmGavCcYTPMaT6sCvVVvJJ_wn7jzKHNAJfL5nWeynTQIBWmL-m_v9QpZAgPALdeqjPRv4JHePZm23kvrUgQOxef2ldXv1l6IB3zfF72uEbk9T5pKBvgeeeQ46xm_HtkpXqMdqcTHawUXeXhuiWxuWfy9pAvhm8ivxwJhiQ15-sQNBlS9lG1_gQz1xaZ_Ou_n1nhNfGwpK5HeS0AgmqsqyCOvaGHeAuAOPZ_dSC3cFKu2AP7kc6_AKBgwJzh4agkXg',
27
- 'RS512' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.abwof7BqTvuLkN69OhEuFTP7vjGzfvAvooQdwIRne_a88MsjCq31n4UPvyIlY9_8u69rpU79RbMsrq_UZ6L85zP83EcyYI-HOfFZgYDAL3DJ7biBD99JTzyOsH_2i_E6yCkevjEX6uL_Am_C7jpWyePJQkYzTFni6mW4W1T9UobiVGA1tIZ-XOJDPHHxZkGu6W8lKW0UCsr9Ge2SCSlTs_LDSOa34gqMC5GP89unhLqSMqEMJ_Nm6Rj0rnmk87wBZM-b04LLteWuEU59QDNa4nMTjfXW74U4hX9n5EECDPQdQMecgxlUbFunAfZaoNzP4m7H4vux2FzYkjkXhdqnnw',
28
- 'ES256' => '',
29
- 'ES384' => '',
30
- 'ES512' => ''
31
- }
32
- end
33
-
34
- after(:each) do
35
- expect(OpenSSL.errors).to be_empty
36
- end
37
-
38
- context 'alg: NONE' do
39
- let(:alg) { 'none' }
40
-
41
- it 'should generate a valid token' do
42
- token = JWT.encode payload, nil, alg
43
-
44
- expect(token).to eq data['NONE']
45
- end
46
-
47
- it 'should decode a valid token' do
48
- jwt_payload, header = JWT.decode data['NONE'], nil, false
49
-
50
- expect(header['alg']).to eq alg
51
- expect(jwt_payload).to eq payload
52
- end
53
-
54
- it 'should display a better error message if payload exp is_a?(Time)' do
55
- payload['exp'] = Time.now
56
-
57
- expect do
58
- JWT.encode payload, nil, alg
59
- end.to raise_error JWT::InvalidPayload
60
- end
61
- end
62
-
63
- %w(HS256 HS384 HS512).each do |alg|
64
- context "alg: #{alg}" do
65
- it 'should generate a valid token' do
66
- token = JWT.encode payload, data[:secret], alg
67
-
68
- expect(token).to eq data[alg]
69
- end
70
-
71
- it 'should decode a valid token' do
72
- jwt_payload, header = JWT.decode data[alg], data[:secret]
73
-
74
- expect(header['alg']).to eq alg
75
- expect(jwt_payload).to eq payload
76
- end
77
-
78
- it 'wrong secret should raise JWT::DecodeError' do
79
- expect do
80
- JWT.decode data[alg], 'wrong_secret'
81
- end.to raise_error JWT::DecodeError
82
- end
83
-
84
- it 'wrong secret and verify = false should not raise JWT::DecodeError' do
85
- expect do
86
- JWT.decode data[alg], 'wrong_secret', false
87
- end.not_to raise_error
88
- end
89
- end
90
- end
91
-
92
- %w(RS256 RS384 RS512).each do |alg|
93
- context "alg: #{alg}" do
94
- it 'should generate a valid token' do
95
- token = JWT.encode payload, data[:rsa_private], alg
96
-
97
- expect(token).to eq data[alg]
98
- end
99
-
100
- it 'should decode a valid token' do
101
- jwt_payload, header = JWT.decode data[alg], data[:rsa_public]
102
-
103
- expect(header['alg']).to eq alg
104
- expect(jwt_payload).to eq payload
105
- end
106
-
107
- it 'wrong key should raise JWT::DecodeError' do
108
- key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))
109
-
110
- expect do
111
- JWT.decode data[alg], key
112
- end.to raise_error JWT::DecodeError
113
- end
114
-
115
- it 'wrong key and verify = false should not raise JWT::DecodeError' do
116
- key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))
117
-
118
- expect do
119
- JWT.decode data[alg], key, false
120
- end.not_to raise_error
121
- end
122
- end
123
- end
124
-
125
- %w(ES256 ES384 ES512).each do |alg|
126
- context "alg: #{alg}" do
127
- before(:each) do
128
- data[alg] = JWT.encode payload, data["#{alg}_private"], alg
129
- end
130
-
131
- let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) }
132
-
133
- it 'should generate a valid token' do
134
- jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"]
135
-
136
- expect(header['alg']).to eq alg
137
- expect(jwt_payload).to eq payload
138
- end
139
-
140
- it 'should decode a valid token' do
141
- jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"]
142
-
143
- expect(header['alg']).to eq alg
144
- expect(jwt_payload).to eq payload
145
- end
146
-
147
- it 'wrong key should raise JWT::DecodeError' do
148
- expect do
149
- JWT.decode data[alg], wrong_key
150
- end.to raise_error JWT::DecodeError
151
- end
152
-
153
- it 'wrong key and verify = false should not raise JWT::DecodeError' do
154
- expect do
155
- JWT.decode data[alg], wrong_key, false
156
- end.not_to raise_error
157
- end
158
- end
159
- end
160
-
161
- context 'Invalid' do
162
- it 'algorithm should raise NotImplementedError' do
163
- expect do
164
- JWT.encode payload, 'secret', 'HS255'
165
- end.to raise_error NotImplementedError
166
- end
167
-
168
- it 'ECDSA curve_name should raise JWT::IncorrectAlgorithm' do
169
- key = OpenSSL::PKey::EC.new 'secp256k1'
170
- key.generate_key
171
-
172
- expect do
173
- JWT.encode payload, key, 'ES256'
174
- end.to raise_error JWT::IncorrectAlgorithm
175
-
176
- token = JWT.encode payload, data['ES256_private'], 'ES256'
177
- key.private_key = nil
178
-
179
- expect do
180
- JWT.decode token, key
181
- end.to raise_error JWT::IncorrectAlgorithm
182
- end
183
- end
184
-
185
- context 'Verify' do
186
- context 'algorithm' do
187
- it 'should raise JWT::IncorrectAlgorithm on missmatch' do
188
- token = JWT.encode payload, data[:secret], 'HS512'
189
-
190
- expect do
191
- JWT.decode token, data[:secret], true, algorithm: 'HS384'
192
- end.to raise_error JWT::IncorrectAlgorithm
193
-
194
- expect do
195
- JWT.decode token, data[:secret], true, algorithm: 'HS512'
196
- end.not_to raise_error
197
- end
198
- end
199
-
200
- context 'issuer claim' do
201
- let(:iss) { 'ruby-jwt-gem' }
202
- let(:invalid_token) { JWT.encode payload, data[:secret] }
203
-
204
- let :token do
205
- iss_payload = payload.merge(iss: iss)
206
- JWT.encode iss_payload, data[:secret]
207
- end
208
-
209
- it 'if verify_iss is set to false (default option) should not raise JWT::InvalidIssuerError' do
210
- expect do
211
- JWT.decode token, data[:secret], true, iss: iss
212
- end.not_to raise_error
213
- end
214
- end
215
- end
216
-
217
- context 'Base64' do
218
- it 'urlsafe replace + / with - _' do
219
- allow(Base64).to receive(:encode64) { 'string+with/non+url-safe/characters_' }
220
- expect(JWT.base64url_encode('foo')).to eq('string-with_non-url-safe_characters_')
221
- end
222
- end
223
-
224
- describe 'secure comparison' do
225
- it 'returns true if strings are equal' do
226
- expect(JWT.secure_compare('Foo', 'Foo')).to eq true
227
- end
228
-
229
- it 'returns false if either input is nil or empty' do
230
- [nil, ''].each do |bad|
231
- expect(JWT.secure_compare(bad, 'Foo')).to eq false
232
- expect(JWT.secure_compare('Foo', bad)).to eq false
233
- end
234
- end
235
-
236
- it 'retuns false if the strings are different' do
237
- expect(JWT.secure_compare('Foo', 'Bar')).to eq false
238
- end
239
- end
240
- end
data/spec/spec_helper.rb DELETED
@@ -1,31 +0,0 @@
1
- require 'rspec'
2
- require 'simplecov'
3
- require 'simplecov-json'
4
- require 'codeclimate-test-reporter'
5
-
6
- SimpleCov.configure do
7
- root File.join(File.dirname(__FILE__), '..')
8
- project_name 'Ruby JWT - Ruby JSON Web Token implementation'
9
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
10
- SimpleCov::Formatter::HTMLFormatter,
11
- SimpleCov::Formatter::JSONFormatter
12
- ])
13
-
14
- add_filter 'spec'
15
- end
16
-
17
- SimpleCov.start if ENV['COVERAGE']
18
- CodeClimate::TestReporter.start if ENV['CODECLIMATE_REPO_TOKEN']
19
-
20
- CERT_PATH = File.join(File.dirname(__FILE__), 'fixtures', 'certs')
21
-
22
- RSpec.configure do |config|
23
- config.expect_with :rspec do |c|
24
- c.syntax = [:should, :expect]
25
- end
26
-
27
- config.run_all_when_everything_filtered = true
28
- config.filter_run :focus
29
-
30
- config.order = 'random'
31
- end