jwt 2.1.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +5 -5
  2. data/AUTHORS +119 -0
  3. data/CHANGELOG.md +355 -19
  4. data/CODE_OF_CONDUCT.md +84 -0
  5. data/CONTRIBUTING.md +99 -0
  6. data/README.md +331 -102
  7. data/lib/jwt/algos/algo_wrapper.rb +30 -0
  8. data/lib/jwt/algos/ecdsa.rb +39 -12
  9. data/lib/jwt/algos/eddsa.rb +18 -8
  10. data/lib/jwt/algos/hmac.rb +57 -17
  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 +7 -5
  16. data/lib/jwt/algos/unsupported.rb +7 -4
  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 +143 -24
  25. data/lib/jwt/encode.rb +54 -26
  26. data/lib/jwt/error.rb +6 -0
  27. data/lib/jwt/json.rb +18 -0
  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 +8 -27
  39. data/lib/jwt/verify.rb +19 -8
  40. data/lib/jwt/version.rb +22 -2
  41. data/lib/jwt/x5c_key_finder.rb +55 -0
  42. data/lib/jwt.rb +12 -44
  43. data/ruby-jwt.gemspec +18 -10
  44. metadata +45 -118
  45. data/.codeclimate.yml +0 -20
  46. data/.ebert.yml +0 -18
  47. data/.gitignore +0 -11
  48. data/.reek.yml +0 -40
  49. data/.rspec +0 -1
  50. data/.rubocop.yml +0 -98
  51. data/.travis.yml +0 -14
  52. data/Gemfile +0 -3
  53. data/Manifest +0 -8
  54. data/Rakefile +0 -11
  55. data/lib/jwt/default_options.rb +0 -15
  56. data/lib/jwt/signature.rb +0 -50
  57. data/spec/fixtures/certs/ec256-private.pem +0 -8
  58. data/spec/fixtures/certs/ec256-public.pem +0 -4
  59. data/spec/fixtures/certs/ec256-wrong-private.pem +0 -8
  60. data/spec/fixtures/certs/ec256-wrong-public.pem +0 -4
  61. data/spec/fixtures/certs/ec384-private.pem +0 -9
  62. data/spec/fixtures/certs/ec384-public.pem +0 -5
  63. data/spec/fixtures/certs/ec384-wrong-private.pem +0 -9
  64. data/spec/fixtures/certs/ec384-wrong-public.pem +0 -5
  65. data/spec/fixtures/certs/ec512-private.pem +0 -10
  66. data/spec/fixtures/certs/ec512-public.pem +0 -6
  67. data/spec/fixtures/certs/ec512-wrong-private.pem +0 -10
  68. data/spec/fixtures/certs/ec512-wrong-public.pem +0 -6
  69. data/spec/fixtures/certs/rsa-1024-private.pem +0 -15
  70. data/spec/fixtures/certs/rsa-1024-public.pem +0 -6
  71. data/spec/fixtures/certs/rsa-2048-private.pem +0 -27
  72. data/spec/fixtures/certs/rsa-2048-public.pem +0 -9
  73. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +0 -27
  74. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +0 -9
  75. data/spec/fixtures/certs/rsa-4096-private.pem +0 -51
  76. data/spec/fixtures/certs/rsa-4096-public.pem +0 -14
  77. data/spec/integration/readme_examples_spec.rb +0 -202
  78. data/spec/jwt/verify_spec.rb +0 -232
  79. data/spec/jwt_spec.rb +0 -315
  80. data/spec/spec_helper.rb +0 -28
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
data/spec/spec_helper.rb DELETED
@@ -1,28 +0,0 @@
1
- require 'rspec'
2
- require 'simplecov'
3
- require 'simplecov-json'
4
- require 'codeclimate-test-reporter'
5
- require 'codacy-coverage'
6
-
7
- Codacy::Reporter.start
8
-
9
- SimpleCov.configure do
10
- root File.join(File.dirname(__FILE__), '..')
11
- project_name 'Ruby JWT - Ruby JSON Web Token implementation'
12
- add_filter 'spec'
13
- end
14
-
15
- SimpleCov.start if ENV['COVERAGE']
16
-
17
- CERT_PATH = File.join(File.dirname(__FILE__), 'fixtures', 'certs')
18
-
19
- RSpec.configure do |config|
20
- config.expect_with :rspec do |c|
21
- c.syntax = %i[should expect]
22
- end
23
-
24
- config.run_all_when_everything_filtered = true
25
- config.filter_run :focus
26
-
27
- config.order = 'random'
28
- end