json-jwt 1.10.0 → 1.13.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.

Potentially problematic release.


This version of json-jwt might be problematic. Click here for more details.

@@ -1,523 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe JSON::JWT do
4
- let(:jwt) { JSON::JWT.new claims }
5
- let(:jws) do
6
- jwt.alg = :HS256
7
- jws = JSON::JWS.new jwt
8
- jws.signature = 'signature'
9
- jws
10
- end
11
- let(:claims) do
12
- {
13
- iss: 'joe',
14
- exp: 1300819380,
15
- 'http://example.com/is_root' => true
16
- }.with_indifferent_access
17
- end
18
- let(:no_signed) do
19
- 'eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.'
20
- end
21
-
22
- context 'when not signed nor encrypted' do
23
- it do
24
- jwt.to_s.should == no_signed
25
- end
26
- end
27
-
28
- describe '#content_type' do
29
- it do
30
- jwt.content_type.should == 'application/jwt'
31
- end
32
- end
33
-
34
- describe '#sign' do
35
- [:HS256, :HS384, :HS512].each do |algorithm|
36
- context algorithm do
37
- it do
38
- jwt.sign(shared_secret, algorithm).should be_a JSON::JWS
39
- end
40
- end
41
- end
42
-
43
- [:RS256, :RS384, :RS512].each do |algorithm|
44
- context algorithm do
45
- it do
46
- jwt.sign(private_key, algorithm).should be_a JSON::JWS
47
- end
48
- end
49
- end
50
-
51
- context 'when no algirithm specified' do
52
- subject { jwt.sign(key) }
53
-
54
- context 'when key is String' do
55
- let(:key) { shared_secret }
56
- its(:alg) { should == :HS256 }
57
- end
58
-
59
- context 'when key is RSA key' do
60
- let(:key) { private_key }
61
- its(:alg) { should == :RS256 }
62
- end
63
-
64
- context 'when key is EC key' do
65
- context 'when prime256v1' do
66
- let(:key) { private_key(:ecdsa) }
67
- its(:alg) { should == :ES256 }
68
- end
69
-
70
- context 'when secp384r1' do
71
- let(:key) { private_key(:ecdsa, digest_length: 384) }
72
- its(:alg) { should == :ES384 }
73
- end
74
-
75
- context 'when secp521r1' do
76
- let(:key) { private_key(:ecdsa, digest_length: 512) }
77
- its(:alg) { should == :ES512 }
78
- end
79
- end
80
-
81
- context 'when key is JWK with kty=okt' do
82
- let(:key) { JSON::JWK.new shared_secret }
83
- its(:alg) { should == :HS256 }
84
- end
85
-
86
- context 'when key is JWK with kty=RSA' do
87
- let(:key) { JSON::JWK.new private_key }
88
- its(:alg) { should == :RS256 }
89
- end
90
-
91
- context 'when key is JWK with kty=EC' do
92
- context 'when prime256v1' do
93
- let(:key) { JSON::JWK.new private_key(:ecdsa) }
94
- its(:alg) { should == :ES256 }
95
- end
96
-
97
- context 'when secp384r1' do
98
- let(:key) { JSON::JWK.new private_key(:ecdsa, digest_length: 384) }
99
- its(:alg) { should == :ES384 }
100
- end
101
-
102
- context 'when secp521r1' do
103
- let(:key) { JSON::JWK.new private_key(:ecdsa, digest_length: 512) }
104
- its(:alg) { should == :ES512 }
105
- end
106
- end
107
- end
108
-
109
- context 'when non-JWK key is given' do
110
- let(:key) { private_key }
111
- it 'should not set kid header automatically' do
112
- jws = jwt.sign(key, :RS256)
113
- jws.kid.should be_blank
114
- end
115
- end
116
-
117
- context 'when JWK is given' do
118
- let(:key) { JSON::JWK.new private_key }
119
- it 'should set kid header automatically' do
120
- jws = jwt.sign(key, :RS256)
121
- jwt.kid.should be_blank
122
- jws.kid.should == key[:kid]
123
- end
124
- end
125
-
126
- describe 'object copy behaviour' do
127
- before do
128
- @jwt = JSON::JWT.new(obj: {foo: :bar})
129
- @jws = @jwt.sign('secret')
130
- end
131
-
132
- context 'when original JWT is modified' do
133
- before do
134
- @jwt.header[:x] = :x
135
- @jwt[:obj][:x] = :x
136
- end
137
-
138
- describe 'copied JWS' do
139
- it 'should be affected as shallow copy, but not as a simple reference' do
140
- @jws.header.should_not include :x
141
- @jws[:obj].should include :x
142
- end
143
- end
144
- end
145
-
146
- context 'when copied JWS is modified' do
147
- before do
148
- @jws.header[:x] = :x
149
- @jws[:obj][:x] = :x
150
- end
151
-
152
- describe 'original JWT' do
153
- it 'should be affected as shallow copy, but not as a simple reference' do
154
- @jwt.header.should_not include :x
155
- @jwt[:obj].should include :x
156
- end
157
- end
158
- end
159
- end
160
- end
161
-
162
- describe '#encrypt' do
163
- let(:shared_key) { SecureRandom.hex 16 } # default shared key is too short
164
-
165
- it 'should encryptable without signing' do
166
- jwt.encrypt(public_key).should be_a JSON::JWE
167
- end
168
-
169
- it 'should encryptable after signed' do
170
- jwt.sign(shared_key).encrypt(public_key).should be_a JSON::JWE
171
- end
172
-
173
- it 'should accept optional algorithm' do
174
- jwt.encrypt(shared_key, :dir).should be_a JSON::JWE
175
- end
176
-
177
- it 'should accept optional algorithm and encryption method' do
178
- jwt.encrypt(SecureRandom.hex(32), :dir, :'A256CBC-HS512').should be_a JSON::JWE
179
- end
180
-
181
- context 'when non-JWK key is given' do
182
- let(:key) { shared_key }
183
- it 'should not set kid header automatically' do
184
- jwe = jwt.encrypt(key, :dir)
185
- jwe.kid.should be_blank
186
- end
187
- end
188
-
189
- context 'when JWK is given' do
190
- let(:key) { JSON::JWK.new shared_key }
191
- it 'should set kid header automatically' do
192
- jwe = jwt.encrypt(key, :dir)
193
- jwt.kid.should be_blank
194
- jwe.kid.should == key[:kid]
195
- end
196
- end
197
- end
198
-
199
- describe '.decode' do
200
- context 'when not signed nor encrypted' do
201
- context 'no signature given' do
202
- it do
203
- JSON::JWT.decode(no_signed).should == jwt
204
- end
205
- end
206
- end
207
-
208
- context 'when signed' do
209
- context 'when no secret/key given' do
210
- it 'should do verification' do
211
- expect do
212
- JSON::JWT.decode jws.to_s
213
- end.to raise_error JSON::JWT::VerificationFailed
214
- end
215
- end
216
-
217
- context 'when secret/key given' do
218
- it 'should do verification' do
219
- expect do
220
- JSON::JWT.decode jws.to_s, 'secret'
221
- end.to raise_error JSON::JWT::VerificationFailed
222
- end
223
- end
224
-
225
- context 'when alg header malformed' do
226
- context 'from alg=HS256' do
227
- context 'to alg=none' do
228
- let(:malformed_jwt_string) do
229
- header, payload, signature = jws.to_s.split('.')
230
- malformed_header = {alg: :none}.to_json
231
- [
232
- Base64.urlsafe_encode64(malformed_header, padding: false),
233
- payload,
234
- ''
235
- ].join('.')
236
- end
237
-
238
- it do
239
- expect do
240
- JSON::JWT.decode malformed_jwt_string, 'secret'
241
- end.to raise_error JSON::JWT::VerificationFailed
242
- end
243
- end
244
- end
245
-
246
- context 'from alg=RS256' do
247
- let(:jws) do
248
- jwt.sign private_key, :RS256
249
- end
250
-
251
- context 'to alg=none' do
252
- let(:malformed_jwt_string) do
253
- header, payload, signature = jws.to_s.split('.')
254
- malformed_header = {alg: :none}.to_json
255
- [
256
- Base64.urlsafe_encode64(malformed_header, padding: false),
257
- payload,
258
- ''
259
- ].join('.')
260
- end
261
-
262
- it do
263
- expect do
264
- JSON::JWT.decode malformed_jwt_string, public_key
265
- end.to raise_error JSON::JWT::UnexpectedAlgorithm
266
- end
267
- end
268
-
269
- context 'to alg=HS256' do
270
- let(:malformed_jwt_string) do
271
- header, payload, signature = jws.to_s.split('.')
272
- malformed_header = {alg: :HS256}.to_json
273
- malformed_signature = OpenSSL::HMAC.digest(
274
- OpenSSL::Digest.new('SHA256'),
275
- public_key.to_s,
276
- [Base64.urlsafe_encode64(malformed_header, padding: false), payload].join('.')
277
- )
278
- [
279
- Base64.urlsafe_encode64(malformed_header, padding: false),
280
- payload,
281
- Base64.urlsafe_encode64(malformed_signature, padding: false)
282
- ].join('.')
283
- end
284
-
285
- it do
286
- expect do
287
- JSON::JWT.decode malformed_jwt_string, public_key
288
- end.to raise_error JSON::JWS::UnexpectedAlgorithm
289
- end
290
- end
291
- end
292
-
293
- context 'from alg=PS512' do
294
- let(:jws) do
295
- jwt.sign private_key, :PS512
296
- end
297
-
298
- if pss_supported?
299
- context 'to alg=PS256' do
300
- let(:malformed_jwt_string) do
301
- header, payload, signature = jws.to_s.split('.')
302
- malformed_header = {alg: :PS256}.to_json
303
- digest = OpenSSL::Digest.new('SHA256')
304
- malformed_signature = private_key.sign_pss(
305
- digest,
306
- [Base64.urlsafe_encode64(malformed_header, padding: false), payload].join('.'),
307
- salt_length: :digest,
308
- mgf1_hash: digest
309
- )
310
- [
311
- Base64.urlsafe_encode64(malformed_header, padding: false),
312
- payload,
313
- Base64.urlsafe_encode64(malformed_signature, padding: false)
314
- ].join('.')
315
- end
316
-
317
- context 'when verification algorithm is specified' do
318
- it do
319
- expect do
320
- JSON::JWT.decode malformed_jwt_string, public_key, :PS512
321
- end.to raise_error JSON::JWS::UnexpectedAlgorithm, 'Unexpected alg header'
322
- end
323
- end
324
-
325
- context 'otherwise' do
326
- it do
327
- expect do
328
- JSON::JWT.decode malformed_jwt_string, public_key
329
- end.not_to raise_error
330
- end
331
- end
332
- end
333
-
334
- context 'to alg=RS516' do
335
- let(:malformed_jwt_string) do
336
- header, payload, signature = jws.to_s.split('.')
337
- malformed_header = {alg: :RS512}.to_json
338
- malformed_signature = private_key.sign(
339
- OpenSSL::Digest.new('SHA512'),
340
- [Base64.urlsafe_encode64(malformed_header, padding: false), payload].join('.')
341
- )
342
- [
343
- Base64.urlsafe_encode64(malformed_header, padding: false),
344
- payload,
345
- Base64.urlsafe_encode64(malformed_signature, padding: false)
346
- ].join('.')
347
- end
348
-
349
- context 'when verification algorithm is specified' do
350
- it do
351
- expect do
352
- JSON::JWT.decode malformed_jwt_string, public_key, :PS512
353
- end.to raise_error JSON::JWS::UnexpectedAlgorithm, 'Unexpected alg header'
354
- end
355
- end
356
-
357
- context 'otherwise' do
358
- it do
359
- expect do
360
- JSON::JWT.decode malformed_jwt_string, public_key
361
- end.not_to raise_error
362
- end
363
- end
364
- end
365
- else
366
- skip 'RSA PSS not supported'
367
- it do
368
- expect { jws }.to raise_error 'PS512 isn\'t supported. OpenSSL gem v2.1.0+ is required to use PS512.'
369
- end
370
- end
371
- end
372
- end
373
-
374
- context 'when :skip_verification given as secret/key' do
375
- it 'should skip verification' do
376
- expect do
377
- jwt = JSON::JWT.decode jws.to_s, :skip_verification
378
- jwt.header.should == {'alg' => 'HS256', 'typ' => 'JWT'}
379
- end.not_to raise_error
380
- end
381
- end
382
-
383
- context 'when JSON Serialization given' do
384
- let(:signed) { JSON::JWT.new(claims).sign('secret') }
385
-
386
- shared_examples_for :json_serialization_parser do
387
- context 'when proper secret given' do
388
- it { JSON::JWT.decode(serialized, 'secret').should == signed }
389
- end
390
-
391
- context 'when verification skipped' do
392
- it { JSON::JWT.decode(serialized, :skip_verification).should == signed }
393
- end
394
-
395
- context 'when wrong secret given' do
396
- it do
397
- expect do
398
- JSON::JWT.decode serialized, 'wrong'
399
- end.to raise_error JSON::JWT::VerificationFailed
400
- end
401
- end
402
- end
403
-
404
- context 'when general' do
405
- let(:serialized) do
406
- {
407
- payload: Base64.urlsafe_encode64(claims.to_json, padding: false),
408
- signatures: [{
409
- protected: Base64.urlsafe_encode64(signed.header.to_json, padding: false),
410
- signature: Base64.urlsafe_encode64(signed.signature, padding: false)
411
- }]
412
- }
413
- end
414
- it_behaves_like :json_serialization_parser
415
- end
416
-
417
- context 'when flattened' do
418
- let(:serialized) do
419
- {
420
- protected: Base64.urlsafe_encode64(signed.header.to_json, padding: false),
421
- payload: Base64.urlsafe_encode64(claims.to_json, padding: false),
422
- signature: Base64.urlsafe_encode64(signed.signature, padding: false)
423
- }
424
- end
425
- it_behaves_like :json_serialization_parser
426
- end
427
- end
428
- end
429
-
430
- context 'when encrypted' do
431
- let(:input) { jwt.encrypt(public_key).to_s }
432
- let(:shared_key) { SecureRandom.hex 16 } # default shared key is too short
433
-
434
- it 'should decryptable' do
435
- JSON::JWT.decode(input, private_key).should be_instance_of JSON::JWE
436
- end
437
-
438
- context 'when :skip_decryption given as secret/key' do
439
- it 'should skip verification' do
440
- expect do
441
- jwe = JSON::JWT.decode input, :skip_decryption
442
- jwe.should be_instance_of JSON::JWE
443
- jwe.header.should == {'alg' => 'RSA1_5', 'enc' => 'A128CBC-HS256'}
444
- end.not_to raise_error
445
- end
446
- end
447
-
448
- context 'when alg & enc is specified' do
449
- context 'when expected' do
450
- it do
451
- expect do
452
- JSON::JWT.decode(input, private_key, 'RSA1_5', 'A128CBC-HS256')
453
- end.not_to raise_error
454
- end
455
- end
456
-
457
- context 'when alg is unexpected' do
458
- it do
459
- expect do
460
- JSON::JWT.decode(input, private_key, 'dir', 'A128CBC-HS256')
461
- end.to raise_error JSON::JWE::UnexpectedAlgorithm, 'Unexpected alg header'
462
- end
463
- end
464
-
465
- context 'when enc is unexpected' do
466
- it do
467
- expect do
468
- JSON::JWT.decode(input, private_key, 'RSA1_5', 'A128GCM')
469
- end.to raise_error JSON::JWE::UnexpectedAlgorithm, 'Unexpected enc header'
470
- end
471
- end
472
- end
473
- end
474
-
475
- context 'when JSON parse failed' do
476
- it do
477
- expect do
478
- JSON::JWT.decode('header.payload.signature')
479
- end.to raise_error JSON::JWT::InvalidFormat
480
- end
481
- end
482
-
483
- context 'when unexpected format' do
484
- context 'when too few dots' do
485
- it do
486
- expect do
487
- JSON::JWT.decode 'header'
488
- end.to raise_error JSON::JWT::InvalidFormat
489
- end
490
- end
491
-
492
- context 'when too many dots' do
493
- it do
494
- expect do
495
- JSON::JWT.decode 'header.payload.signature.too.many.dots'
496
- end.to raise_error JSON::JWT::InvalidFormat
497
- end
498
- end
499
- end
500
- end
501
-
502
- describe '.pretty_generate' do
503
- subject { JSON::JWT.pretty_generate jws.to_s }
504
- its(:size) { should == 2 }
505
- its(:first) do
506
- should == <<~HEADER.chop
507
- {
508
- "typ": "JWT",
509
- "alg": "HS256"
510
- }
511
- HEADER
512
- end
513
- its(:last) do
514
- should == <<~HEADER.chop
515
- {
516
- "iss": "joe",
517
- "exp": 1300819380,
518
- "http://example.com/is_root": true
519
- }
520
- HEADER
521
- end
522
- end
523
- end