json-jwt 1.10.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.

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