jwt 2.1.0 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +74 -0
  3. data/.gitignore +1 -1
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +15 -16
  6. data/.rubocop_todo.yml +191 -0
  7. data/{.ebert.yml → .sourcelevel.yml} +1 -1
  8. data/AUTHORS +101 -0
  9. data/Appraisals +10 -0
  10. data/CHANGELOG.md +247 -19
  11. data/Gemfile +2 -0
  12. data/README.md +154 -89
  13. data/Rakefile +4 -1
  14. data/lib/jwt.rb +9 -42
  15. data/lib/jwt/algos.rb +44 -0
  16. data/lib/jwt/algos/ecdsa.rb +1 -1
  17. data/lib/jwt/algos/hmac.rb +1 -0
  18. data/lib/jwt/algos/none.rb +15 -0
  19. data/lib/jwt/algos/ps.rb +43 -0
  20. data/lib/jwt/algos/unsupported.rb +5 -4
  21. data/lib/jwt/base64.rb +19 -0
  22. data/lib/jwt/claims_validator.rb +35 -0
  23. data/lib/jwt/decode.rb +85 -25
  24. data/lib/jwt/encode.rb +43 -25
  25. data/lib/jwt/error.rb +4 -0
  26. data/lib/jwt/json.rb +18 -0
  27. data/lib/jwt/jwk.rb +51 -0
  28. data/lib/jwt/jwk/ec.rb +150 -0
  29. data/lib/jwt/jwk/hmac.rb +58 -0
  30. data/lib/jwt/jwk/key_base.rb +18 -0
  31. data/lib/jwt/jwk/key_finder.rb +62 -0
  32. data/lib/jwt/jwk/rsa.rb +115 -0
  33. data/lib/jwt/security_utils.rb +6 -0
  34. data/lib/jwt/signature.rb +9 -20
  35. data/lib/jwt/verify.rb +1 -5
  36. data/lib/jwt/version.rb +2 -2
  37. data/ruby-jwt.gemspec +4 -7
  38. metadata +30 -109
  39. data/.codeclimate.yml +0 -20
  40. data/.reek.yml +0 -40
  41. data/.travis.yml +0 -14
  42. data/Manifest +0 -8
  43. data/spec/fixtures/certs/ec256-private.pem +0 -8
  44. data/spec/fixtures/certs/ec256-public.pem +0 -4
  45. data/spec/fixtures/certs/ec256-wrong-private.pem +0 -8
  46. data/spec/fixtures/certs/ec256-wrong-public.pem +0 -4
  47. data/spec/fixtures/certs/ec384-private.pem +0 -9
  48. data/spec/fixtures/certs/ec384-public.pem +0 -5
  49. data/spec/fixtures/certs/ec384-wrong-private.pem +0 -9
  50. data/spec/fixtures/certs/ec384-wrong-public.pem +0 -5
  51. data/spec/fixtures/certs/ec512-private.pem +0 -10
  52. data/spec/fixtures/certs/ec512-public.pem +0 -6
  53. data/spec/fixtures/certs/ec512-wrong-private.pem +0 -10
  54. data/spec/fixtures/certs/ec512-wrong-public.pem +0 -6
  55. data/spec/fixtures/certs/rsa-1024-private.pem +0 -15
  56. data/spec/fixtures/certs/rsa-1024-public.pem +0 -6
  57. data/spec/fixtures/certs/rsa-2048-private.pem +0 -27
  58. data/spec/fixtures/certs/rsa-2048-public.pem +0 -9
  59. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +0 -27
  60. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +0 -9
  61. data/spec/fixtures/certs/rsa-4096-private.pem +0 -51
  62. data/spec/fixtures/certs/rsa-4096-public.pem +0 -14
  63. data/spec/integration/readme_examples_spec.rb +0 -202
  64. data/spec/jwt/verify_spec.rb +0 -232
  65. data/spec/jwt_spec.rb +0 -315
  66. data/spec/spec_helper.rb +0 -28
@@ -1,232 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
- require 'jwt/verify'
5
-
6
- module JWT
7
- RSpec.describe Verify do
8
- let(:base_payload) { { 'user_id' => 'some@user.tld' } }
9
- let(:options) { { leeway: 0 } }
10
-
11
- context '.verify_aud(payload, options)' do
12
- let(:scalar_aud) { 'ruby-jwt-aud' }
13
- let(:array_aud) { %w[ruby-jwt-aud test-aud ruby-ruby-ruby] }
14
- let(:scalar_payload) { base_payload.merge('aud' => scalar_aud) }
15
- let(:array_payload) { base_payload.merge('aud' => array_aud) }
16
-
17
- it 'must raise JWT::InvalidAudError when the singular audience does not match' do
18
- expect do
19
- Verify.verify_aud(scalar_payload, options.merge(aud: 'no-match'))
20
- end.to raise_error JWT::InvalidAudError
21
- end
22
-
23
- it 'must raise JWT::InvalidAudError when the payload has an array and none match the supplied value' do
24
- expect do
25
- Verify.verify_aud(array_payload, options.merge(aud: 'no-match'))
26
- end.to raise_error JWT::InvalidAudError
27
- end
28
-
29
- it 'must allow a matching singular audience to pass' do
30
- Verify.verify_aud(scalar_payload, options.merge(aud: scalar_aud))
31
- end
32
-
33
- it 'must allow an array with any value matching the one in the options' do
34
- Verify.verify_aud(array_payload, options.merge(aud: array_aud.first))
35
- end
36
-
37
- it 'must allow an array with any value matching any value in the options array' do
38
- Verify.verify_aud(array_payload, options.merge(aud: array_aud))
39
- end
40
-
41
- it 'must allow a singular audience payload matching any value in the options array' do
42
- Verify.verify_aud(scalar_payload, options.merge(aud: array_aud))
43
- end
44
- end
45
-
46
- context '.verify_expiration(payload, options)' do
47
- let(:payload) { base_payload.merge('exp' => (Time.now.to_i - 5)) }
48
-
49
- it 'must raise JWT::ExpiredSignature when the token has expired' do
50
- expect do
51
- Verify.verify_expiration(payload, options)
52
- end.to raise_error JWT::ExpiredSignature
53
- end
54
-
55
- it 'must allow some leeway in the expiration when global leeway is configured' do
56
- Verify.verify_expiration(payload, options.merge(leeway: 10))
57
- end
58
-
59
- it 'must allow some leeway in the expiration when exp_leeway is configured' do
60
- Verify.verify_expiration(payload, options.merge(exp_leeway: 10))
61
- end
62
-
63
- it 'must be expired if the exp claim equals the current time' do
64
- payload['exp'] = Time.now.to_i
65
-
66
- expect do
67
- Verify.verify_expiration(payload, options)
68
- end.to raise_error JWT::ExpiredSignature
69
- end
70
-
71
- context 'when leeway is not specified' do
72
- let(:options) { {} }
73
-
74
- it 'used a default leeway of 0' do
75
- expect do
76
- Verify.verify_expiration(payload, options)
77
- end.to raise_error JWT::ExpiredSignature
78
- end
79
- end
80
- end
81
-
82
- context '.verify_iat(payload, options)' do
83
- let(:iat) { Time.now.to_f }
84
- let(:payload) { base_payload.merge('iat' => iat) }
85
-
86
- it 'must allow a valid iat' do
87
- Verify.verify_iat(payload, options)
88
- end
89
-
90
- it 'must allow configured leeway' do
91
- Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(leeway: 70))
92
- end
93
-
94
- it 'must allow configured iat_leeway' do
95
- Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(iat_leeway: 70))
96
- end
97
-
98
- it 'must properly handle integer times' do
99
- Verify.verify_iat(payload.merge('iat' => Time.now.to_i), options)
100
- end
101
-
102
- it 'must raise JWT::InvalidIatError when the iat value is not Numeric' do
103
- expect do
104
- Verify.verify_iat(payload.merge('iat' => 'not a number'), options)
105
- end.to raise_error JWT::InvalidIatError
106
- end
107
-
108
- it 'must raise JWT::InvalidIatError when the iat value is in the future' do
109
- expect do
110
- Verify.verify_iat(payload.merge('iat' => (iat + 120)), options)
111
- end.to raise_error JWT::InvalidIatError
112
- end
113
- end
114
-
115
- context '.verify_iss(payload, options)' do
116
- let(:iss) { 'ruby-jwt-gem' }
117
- let(:payload) { base_payload.merge('iss' => iss) }
118
-
119
- let(:invalid_token) { JWT.encode base_payload, payload[:secret] }
120
-
121
- context 'when iss is a String' do
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
- context 'when iss is an Array' do
139
- it 'must raise JWT::InvalidIssuerError when no matching issuers in array' do
140
- expect do
141
- Verify.verify_iss(payload, options.merge(iss: %w[first second]))
142
- end.to raise_error JWT::InvalidIssuerError
143
- end
144
-
145
- it 'must raise JWT::InvalidIssuerError when the payload does not include an issuer' do
146
- expect do
147
- Verify.verify_iss(base_payload, options.merge(iss: %w[first second]))
148
- end.to raise_error(JWT::InvalidIssuerError, /received <none>/)
149
- end
150
-
151
- it 'must allow an array with matching issuer to pass' do
152
- Verify.verify_iss(payload, options.merge(iss: ['first', iss, 'third']))
153
- end
154
- end
155
- end
156
-
157
- context '.verify_jti(payload, options)' do
158
- let(:payload) { base_payload.merge('jti' => 'some-random-uuid-or-whatever') }
159
-
160
- it 'must allow any jti when the verfy_jti key in the options is truthy but not a proc' do
161
- Verify.verify_jti(payload, options.merge(verify_jti: true))
162
- end
163
-
164
- it 'must raise JWT::InvalidJtiError when the jti is missing' do
165
- expect do
166
- Verify.verify_jti(base_payload, options)
167
- end.to raise_error JWT::InvalidJtiError, /missing/i
168
- end
169
-
170
- it 'must raise JWT::InvalidJtiError when the jti is an empty string' do
171
- expect do
172
- Verify.verify_jti(base_payload.merge('jti' => ' '), options)
173
- end.to raise_error JWT::InvalidJtiError, /missing/i
174
- end
175
-
176
- it 'must raise JWT::InvalidJtiError when verify_jti proc returns false' do
177
- expect do
178
- Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { false }))
179
- end.to raise_error JWT::InvalidJtiError, /invalid/i
180
- end
181
-
182
- it 'true proc should not raise JWT::InvalidJtiError' do
183
- Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { true }))
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
198
- end
199
-
200
- context '.verify_not_before(payload, options)' do
201
- let(:payload) { base_payload.merge('nbf' => (Time.now.to_i + 5)) }
202
-
203
- it 'must raise JWT::ImmatureSignature when the nbf in the payload is in the future' do
204
- expect do
205
- Verify.verify_not_before(payload, options)
206
- end.to raise_error JWT::ImmatureSignature
207
- end
208
-
209
- it 'must allow some leeway in the token age when global leeway is configured' do
210
- Verify.verify_not_before(payload, options.merge(leeway: 10))
211
- end
212
-
213
- it 'must allow some leeway in the token age when nbf_leeway is configured' do
214
- Verify.verify_not_before(payload, options.merge(nbf_leeway: 10))
215
- end
216
- end
217
-
218
- context '.verify_sub(payload, options)' do
219
- let(:sub) { 'ruby jwt subject' }
220
-
221
- it 'must raise JWT::InvalidSubError when the subjects do not match' do
222
- expect do
223
- Verify.verify_sub(base_payload.merge('sub' => 'not-a-match'), options.merge(sub: sub))
224
- end.to raise_error JWT::InvalidSubError
225
- end
226
-
227
- it 'must allow a matching sub' do
228
- Verify.verify_sub(base_payload.merge('sub' => sub), options.merge(sub: sub))
229
- end
230
- end
231
- end
232
- end
data/spec/jwt_spec.rb DELETED
@@ -1,315 +0,0 @@
1
- require 'spec_helper'
2
- require 'jwt'
3
- require 'jwt/encode'
4
- require 'jwt/decode'
5
-
6
- describe JWT do
7
- let(:payload) { { 'user_id' => 'some@user.tld' } }
8
-
9
- let :data do
10
- {
11
- :secret => 'My$ecretK3y',
12
- :rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-private.pem'))),
13
- :rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-public.pem'))),
14
- :wrong_rsa_private => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))),
15
- :wrong_rsa_public => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))),
16
- 'ES256_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-private.pem'))),
17
- 'ES256_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-public.pem'))),
18
- 'ES384_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-private.pem'))),
19
- 'ES384_public' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec384-public.pem'))),
20
- 'ES512_private' => OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec512-private.pem'))),
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,
24
- 'NONE' => 'eyJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.',
25
- 'HS256' => 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.kWOVtIOpWcG7JnyJG0qOkTDbOy636XrrQhMm_8JrRQ8',
26
- 'HS512256' => 'eyJhbGciOiJIUzUxMjI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Ds_4ibvf7z4QOBoKntEjDfthy3WJ-3rKMspTEcHE2bA',
27
- 'HS384' => 'eyJhbGciOiJIUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.VuV4j4A1HKhWxCNzEcwc9qVF3frrEu-BRLzvYPkbWO0LENRGy5dOiBQ34remM3XH',
28
- 'HS512' => 'eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.8zNtCBTJIZTHpZ-BkhR-6sZY1K85Nm5YCKqV3AxRdsBJDt_RR-REH2db4T3Y0uQwNknhrCnZGvhNHrvhDwV1kA',
29
- 'RS256' => 'eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.eSXvWP4GViiwUALj_-qTxU68I1oM0XjgDsCZBBUri2Ghh9d75QkVDoZ_v872GaqunN5A5xcnBK0-cOq-CR6OwibgJWfOt69GNzw5RrOfQ2mz3QI3NYEq080nF69h8BeqkiaXhI24Q51joEgfa9aj5Y-oitLAmtDPYTm7vTcdGufd6AwD3_3jajKBwkh0LPSeMtbe_5EyS94nFoEF9OQuhJYjUmp7agsBVa8FFEjVw5jEgVqkvERSj5hSY4nEiCAomdVxIKBfykyi0d12cgjhI7mBFwWkPku8XIPGZ7N8vpiSLdM68BnUqIK5qR7NAhtvT7iyLFgOqhZNUQ6Ret5VpQ',
30
- 'RS384' => 'eyJhbGciOiJSUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Sfgk56moPghtsjaP4so6tOy3I553mgwX-5gByMC6dX8lpeWgsxSeAd_K8IyO7u4lwYOL0DSftnqO1HEOuN1AKyBbDvaTXz3u2xNA2x4NYLdW4AZA6ritbYcKLO5BHTXw5ueMbtA1jjGXP0zI_aK2iJTMBmB8SCF88RYBUH01Tyf4PlLj98pGL-v3prZd6kZkIeRJ3326h04hslcB5HQKmgeBk24QNLIoIC-CD329HPjJ7TtGx01lj-ehTBnwVbBGzYFAyoalV5KgvL_MDOfWPr1OYHnR5s_Fm6_3Vg4u6lBljvHOrmv4Nfx7d8HLgbo8CwH4qn1wm6VQCtuDd-uhRg',
31
- 'RS512' => 'eyJhbGciOiJSUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.LIIAUEuCkGNdpYguOO5LoW4rZ7ED2POJrB0pmEAAchyTdIK4HKh1jcLxc6KyGwZv40njCgub3y72q6vcQTn7oD0zWFCVQRIDW1911Ii2hRNHuigiPUnrnZh1OQ6z65VZRU6GKs8omoBGU9vrClBU0ODqYE16KxYmE_0n4Xw2h3D_L1LF0IAOtDWKBRDa3QHwZRM9sHsHNsBuD5ye9KzDYN1YALXj64LBfA-DoCKfpVAm9NkRPOyzjR2X2C3TomOSJgqWIVHJucudKDDAZyEbO4RA5pI-UFYy1370p9bRajvtDyoBuLDCzoSkMyQ4L2DnLhx5CbWcnD7Cd3GUmnjjTA',
32
- 'ES256' => '',
33
- 'ES384' => '',
34
- 'ES512' => ''
35
- }
36
- end
37
-
38
- after(:each) do
39
- expect(OpenSSL.errors).to be_empty
40
- end
41
-
42
- context 'alg: NONE' do
43
- let(:alg) { 'none' }
44
-
45
- it 'should generate a valid token' do
46
- token = JWT.encode payload, nil, alg
47
-
48
- expect(token).to eq data['NONE']
49
- end
50
-
51
- it 'should decode a valid token' do
52
- jwt_payload, header = JWT.decode data['NONE'], nil, false
53
-
54
- expect(header['alg']).to eq alg
55
- expect(jwt_payload).to eq payload
56
- end
57
-
58
- it 'should display a better error message if payload exp is_a?(Time)' do
59
- payload['exp'] = Time.now
60
-
61
- expect do
62
- JWT.encode payload, nil, alg
63
- end.to raise_error JWT::InvalidPayload
64
- end
65
-
66
- it 'should display a better error message if payload exp is not an Integer' do
67
- payload['exp'] = Time.now.to_i.to_s
68
-
69
- expect do
70
- JWT.encode payload, nil, alg
71
- end.to raise_error JWT::InvalidPayload
72
- end
73
- end
74
-
75
- %w[HS256 HS512256 HS384 HS512].each do |alg|
76
- context "alg: #{alg}" do
77
- it 'should generate a valid token' do
78
- token = JWT.encode payload, data[:secret], alg
79
-
80
- expect(token).to eq data[alg]
81
- end
82
-
83
- it 'should decode a valid token' do
84
- jwt_payload, header = JWT.decode data[alg], data[:secret], true, algorithm: alg
85
-
86
- expect(header['alg']).to eq alg
87
- expect(jwt_payload).to eq payload
88
- end
89
-
90
- it 'wrong secret should raise JWT::DecodeError' do
91
- expect do
92
- JWT.decode data[alg], 'wrong_secret', true, algorithm: alg
93
- end.to raise_error JWT::VerificationError
94
- end
95
-
96
- it 'wrong secret and verify = false should not raise JWT::DecodeError' do
97
- expect do
98
- JWT.decode data[alg], 'wrong_secret', false
99
- end.not_to raise_error
100
- end
101
- end
102
- end
103
-
104
- %w[RS256 RS384 RS512].each do |alg|
105
- context "alg: #{alg}" do
106
- it 'should generate a valid token' do
107
- token = JWT.encode payload, data[:rsa_private], alg
108
-
109
- expect(token).to eq data[alg]
110
- end
111
-
112
- it 'should decode a valid token' do
113
- jwt_payload, header = JWT.decode data[alg], data[:rsa_public], true, algorithm: alg
114
-
115
- expect(header['alg']).to eq alg
116
- expect(jwt_payload).to eq payload
117
- end
118
-
119
- it 'wrong key should raise JWT::DecodeError' do
120
- key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))
121
-
122
- expect do
123
- JWT.decode data[alg], key, true, algorithm: alg
124
- end.to raise_error JWT::DecodeError
125
- end
126
-
127
- it 'wrong key and verify = false should not raise JWT::DecodeError' do
128
- key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))
129
-
130
- expect do
131
- JWT.decode data[alg], key, false
132
- end.not_to raise_error
133
- end
134
- end
135
- end
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
172
- %w[ES256 ES384 ES512].each do |alg|
173
- context "alg: #{alg}" do
174
- before(:each) do
175
- data[alg] = JWT.encode payload, data["#{alg}_private"], alg
176
- end
177
-
178
- let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) }
179
-
180
- it 'should generate a valid token' do
181
- jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
182
-
183
- expect(header['alg']).to eq alg
184
- expect(jwt_payload).to eq payload
185
- end
186
-
187
- it 'should decode a valid token' do
188
- jwt_payload, header = JWT.decode data[alg], data["#{alg}_public"], true, algorithm: alg
189
-
190
- expect(header['alg']).to eq alg
191
- expect(jwt_payload).to eq payload
192
- end
193
-
194
- it 'wrong key should raise JWT::DecodeError' do
195
- expect do
196
- JWT.decode data[alg], wrong_key
197
- end.to raise_error JWT::DecodeError
198
- end
199
-
200
- it 'wrong key and verify = false should not raise JWT::DecodeError' do
201
- expect do
202
- JWT.decode data[alg], wrong_key, false
203
- end.not_to raise_error
204
- end
205
- end
206
- end
207
-
208
- context 'Invalid' do
209
- it 'algorithm should raise NotImplementedError' do
210
- expect do
211
- JWT.encode payload, 'secret', 'HS255'
212
- end.to raise_error NotImplementedError
213
- end
214
-
215
- it 'ECDSA curve_name should raise JWT::IncorrectAlgorithm' do
216
- key = OpenSSL::PKey::EC.new 'secp256k1'
217
- key.generate_key
218
-
219
- expect do
220
- JWT.encode payload, key, 'ES256'
221
- end.to raise_error JWT::IncorrectAlgorithm
222
-
223
- token = JWT.encode payload, data['ES256_private'], 'ES256'
224
- key.private_key = nil
225
-
226
- expect do
227
- JWT.decode token, key
228
- end.to raise_error JWT::IncorrectAlgorithm
229
- end
230
- end
231
-
232
- context 'Verify' do
233
- context 'algorithm' do
234
- it 'should raise JWT::IncorrectAlgorithm on mismatch' do
235
- token = JWT.encode payload, data[:secret], 'HS256'
236
-
237
- expect do
238
- JWT.decode token, data[:secret], true, algorithm: 'HS384'
239
- end.to raise_error JWT::IncorrectAlgorithm
240
-
241
- expect do
242
- JWT.decode token, data[:secret], true, algorithm: 'HS256'
243
- end.not_to raise_error
244
- end
245
-
246
- it 'should raise JWT::IncorrectAlgorithm when algorithms array does not contain algorithm' do
247
- token = JWT.encode payload, data[:secret], 'HS512'
248
-
249
- expect do
250
- JWT.decode token, data[:secret], true, algorithms: ['HS384']
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
267
- end
268
- end
269
-
270
- context 'issuer claim' do
271
- let(:iss) { 'ruby-jwt-gem' }
272
- let(:invalid_token) { JWT.encode payload, data[:secret] }
273
-
274
- let :token do
275
- iss_payload = payload.merge(iss: iss)
276
- JWT.encode iss_payload, data[:secret]
277
- end
278
-
279
- it 'if verify_iss is set to false (default option) should not raise JWT::InvalidIssuerError' do
280
- expect do
281
- JWT.decode token, data[:secret], true, iss: iss, algorithm: 'HS256'
282
- end.not_to raise_error
283
- end
284
- end
285
- end
286
-
287
- context 'Base64' do
288
- it 'urlsafe replace + / with - _' do
289
- allow(Base64).to receive(:encode64) { 'string+with/non+url-safe/characters_' }
290
- expect(JWT::Encode.base64url_encode('foo')).to eq('string-with_non-url-safe_characters_')
291
- end
292
- end
293
-
294
- it 'should not verify token even if the payload has claims' do
295
- head = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9'
296
- load = 'eyJ1c2VyX2lkIjo1NCwiZXhwIjoxNTA0MzkwODA0fQ'
297
- sign = 'Skpi6FfYMbZ-DwW9ocyRIosNMdPMAIWRLYxRO68GTQk'
298
-
299
- expect do
300
- JWT.decode([head, load, sign].join('.'), '', false)
301
- end.not_to raise_error
302
- end
303
-
304
- it 'should not raise InvalidPayload exception if payload is an array' do
305
- expect do
306
- JWT.encode(['my', 'payload'], 'secret')
307
- end.not_to raise_error
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
315
- end