jwtb 2.0.0.beta2.bsk1
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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +20 -0
- data/.gitignore +11 -0
- data/.rspec +1 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +411 -0
- data/Gemfile +4 -0
- data/LICENSE +7 -0
- data/Manifest +8 -0
- data/README.md +443 -0
- data/Rakefile +11 -0
- data/jwtb.gemspec +31 -0
- data/lib/jwtb.rb +67 -0
- data/lib/jwtb/decode.rb +45 -0
- data/lib/jwtb/default_options.rb +14 -0
- data/lib/jwtb/encode.rb +51 -0
- data/lib/jwtb/error.rb +15 -0
- data/lib/jwtb/signature.rb +146 -0
- data/lib/jwtb/verify.rb +84 -0
- data/lib/jwtb/version.rb +24 -0
- data/spec/fixtures/certs/ec256-private.pem +8 -0
- data/spec/fixtures/certs/ec256-public.pem +4 -0
- data/spec/fixtures/certs/ec256-wrong-private.pem +8 -0
- data/spec/fixtures/certs/ec256-wrong-public.pem +4 -0
- data/spec/fixtures/certs/ec384-private.pem +9 -0
- data/spec/fixtures/certs/ec384-public.pem +5 -0
- data/spec/fixtures/certs/ec384-wrong-private.pem +9 -0
- data/spec/fixtures/certs/ec384-wrong-public.pem +5 -0
- data/spec/fixtures/certs/ec512-private.pem +10 -0
- data/spec/fixtures/certs/ec512-public.pem +6 -0
- data/spec/fixtures/certs/ec512-wrong-private.pem +10 -0
- data/spec/fixtures/certs/ec512-wrong-public.pem +6 -0
- data/spec/fixtures/certs/rsa-1024-private.pem +15 -0
- data/spec/fixtures/certs/rsa-1024-public.pem +6 -0
- data/spec/fixtures/certs/rsa-2048-private.pem +27 -0
- data/spec/fixtures/certs/rsa-2048-public.pem +9 -0
- data/spec/fixtures/certs/rsa-2048-wrong-private.pem +27 -0
- data/spec/fixtures/certs/rsa-2048-wrong-public.pem +9 -0
- data/spec/fixtures/certs/rsa-4096-private.pem +51 -0
- data/spec/fixtures/certs/rsa-4096-public.pem +14 -0
- data/spec/integration/readme_examples_spec.rb +216 -0
- data/spec/jwtb/verify_spec.rb +190 -0
- data/spec/jwtb_spec.rb +233 -0
- data/spec/spec_helper.rb +28 -0
- metadata +225 -0
@@ -0,0 +1,190 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'jwtb/verify'
|
4
|
+
|
5
|
+
module JWTB
|
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-aud' }
|
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 JWTB::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 JWTB::InvalidAudError
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'must raise JWTB::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 JWTB::InvalidAudError
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'must allow a matching singular audience to pass' do
|
29
|
+
Verify.verify_aud(scalar_payload, options.merge(aud: scalar_aud))
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'must allow an array with any value matching the one in the options' do
|
33
|
+
Verify.verify_aud(array_payload, options.merge(aud: array_aud.first))
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'must allow an array with any value matching any value in the options array' do
|
37
|
+
Verify.verify_aud(array_payload, options.merge(aud: array_aud))
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'must allow a singular audience payload matching any value in the options array' do
|
41
|
+
Verify.verify_aud(scalar_payload, options.merge(aud: array_aud))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context '.verify_expiration(payload, options)' do
|
46
|
+
let(:leeway) { 10 }
|
47
|
+
let(:payload) { base_payload.merge('exp' => (Time.now.to_i - 5)) }
|
48
|
+
|
49
|
+
it 'must raise JWTB::ExpiredSignature when the token has expired' do
|
50
|
+
expect do
|
51
|
+
Verify.verify_expiration(payload, options)
|
52
|
+
end.to raise_error JWTB::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 JWTB::ExpiredSignature
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context '.verify_iat(payload, options)' do
|
73
|
+
let(:iat) { Time.now.to_f }
|
74
|
+
let(:payload) { base_payload.merge('iat' => iat) }
|
75
|
+
|
76
|
+
it 'must allow a valid iat' do
|
77
|
+
Verify.verify_iat(payload, options)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'must allow configured leeway' do
|
81
|
+
Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(leeway: 70))
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'must allow configured iat_leeway' do
|
85
|
+
Verify.verify_iat(payload.merge('iat' => (iat + 60)), options.merge(iat_leeway: 70))
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'must properly handle integer times' do
|
89
|
+
Verify.verify_iat(payload.merge('iat' => Time.now.to_i), options)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'must raise JWTB::InvalidIatError when the iat value is not Numeric' do
|
93
|
+
expect do
|
94
|
+
Verify.verify_iat(payload.merge('iat' => 'not a number'), options)
|
95
|
+
end.to raise_error JWTB::InvalidIatError
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'must raise JWTB::InvalidIatError when the iat value is in the future' do
|
99
|
+
expect do
|
100
|
+
Verify.verify_iat(payload.merge('iat' => (iat + 120)), options)
|
101
|
+
end.to raise_error JWTB::InvalidIatError
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context '.verify_iss(payload, options)' do
|
106
|
+
let(:iss) { 'ruby-jwt-gem' }
|
107
|
+
let(:payload) { base_payload.merge('iss' => iss) }
|
108
|
+
|
109
|
+
let(:invalid_token) { JWTB.encode base_payload, payload[:secret] }
|
110
|
+
|
111
|
+
it 'must raise JWTB::InvalidIssuerError when the configured issuer does not match the payload issuer' do
|
112
|
+
expect do
|
113
|
+
Verify.verify_iss(payload, options.merge(iss: 'mismatched-issuer'))
|
114
|
+
end.to raise_error JWTB::InvalidIssuerError
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'must raise JWTB::InvalidIssuerError when the payload does not include an issuer' do
|
118
|
+
expect do
|
119
|
+
Verify.verify_iss(base_payload, options.merge(iss: iss))
|
120
|
+
end.to raise_error(JWTB::InvalidIssuerError, /received <none>/)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'must allow a matching issuer to pass' do
|
124
|
+
Verify.verify_iss(payload, options.merge(iss: iss))
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context '.verify_jti(payload, options)' do
|
129
|
+
let(:payload) { base_payload.merge('jti' => 'some-random-uuid-or-whatever') }
|
130
|
+
|
131
|
+
it 'must allow any jti when the verfy_jti key in the options is truthy but not a proc' do
|
132
|
+
Verify.verify_jti(payload, options.merge(verify_jti: true))
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'must raise JWTB::InvalidJtiError when the jti is missing' do
|
136
|
+
expect do
|
137
|
+
Verify.verify_jti(base_payload, options)
|
138
|
+
end.to raise_error JWTB::InvalidJtiError, /missing/i
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'must raise JWTB::InvalidJtiError when the jti is an empty string' do
|
142
|
+
expect do
|
143
|
+
Verify.verify_jti(base_payload.merge('jti' => ' '), options)
|
144
|
+
end.to raise_error JWTB::InvalidJtiError, /missing/i
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'must raise JWTB::InvalidJtiError when verify_jti proc returns false' do
|
148
|
+
expect do
|
149
|
+
Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { false }))
|
150
|
+
end.to raise_error JWTB::InvalidJtiError, /invalid/i
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'true proc should not raise JWTB::InvalidJtiError' do
|
154
|
+
Verify.verify_jti(payload, options.merge(verify_jti: ->(_jti) { true }))
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context '.verify_not_before(payload, options)' do
|
159
|
+
let(:payload) { base_payload.merge('nbf' => (Time.now.to_i + 5)) }
|
160
|
+
|
161
|
+
it 'must raise JWTB::ImmatureSignature when the nbf in the payload is in the future' do
|
162
|
+
expect do
|
163
|
+
Verify.verify_not_before(payload, options)
|
164
|
+
end.to raise_error JWTB::ImmatureSignature
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'must allow some leeway in the token age when global leeway is configured' do
|
168
|
+
Verify.verify_not_before(payload, options.merge(leeway: 10))
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'must allow some leeway in the token age when nbf_leeway is configured' do
|
172
|
+
Verify.verify_not_before(payload, options.merge(nbf_leeway: 10))
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context '.verify_sub(payload, options)' do
|
177
|
+
let(:sub) { 'ruby jwt subject' }
|
178
|
+
|
179
|
+
it 'must raise JWTB::InvalidSubError when the subjects do not match' do
|
180
|
+
expect do
|
181
|
+
Verify.verify_sub(base_payload.merge('sub' => 'not-a-match'), options.merge(sub: sub))
|
182
|
+
end.to raise_error JWTB::InvalidSubError
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'must allow a matching sub' do
|
186
|
+
Verify.verify_sub(base_payload.merge('sub' => sub), options.merge(sub: sub))
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
data/spec/jwtb_spec.rb
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'jwtb'
|
3
|
+
require 'jwtb/encode'
|
4
|
+
require 'jwtb/decode'
|
5
|
+
|
6
|
+
describe JWTB 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
|
+
'NONE' => 'eyJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.',
|
23
|
+
'HS256' => 'eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.kWOVtIOpWcG7JnyJG0qOkTDbOy636XrrQhMm_8JrRQ8',
|
24
|
+
'HS512256' => 'eyJhbGciOiJIUzUxMjI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Ds_4ibvf7z4QOBoKntEjDfthy3WJ-3rKMspTEcHE2bA',
|
25
|
+
'HS384' => 'eyJhbGciOiJIUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.VuV4j4A1HKhWxCNzEcwc9qVF3frrEu-BRLzvYPkbWO0LENRGy5dOiBQ34remM3XH',
|
26
|
+
'HS512' => 'eyJhbGciOiJIUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.8zNtCBTJIZTHpZ-BkhR-6sZY1K85Nm5YCKqV3AxRdsBJDt_RR-REH2db4T3Y0uQwNknhrCnZGvhNHrvhDwV1kA',
|
27
|
+
'RS256' => 'eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.eSXvWP4GViiwUALj_-qTxU68I1oM0XjgDsCZBBUri2Ghh9d75QkVDoZ_v872GaqunN5A5xcnBK0-cOq-CR6OwibgJWfOt69GNzw5RrOfQ2mz3QI3NYEq080nF69h8BeqkiaXhI24Q51joEgfa9aj5Y-oitLAmtDPYTm7vTcdGufd6AwD3_3jajKBwkh0LPSeMtbe_5EyS94nFoEF9OQuhJYjUmp7agsBVa8FFEjVw5jEgVqkvERSj5hSY4nEiCAomdVxIKBfykyi0d12cgjhI7mBFwWkPku8XIPGZ7N8vpiSLdM68BnUqIK5qR7NAhtvT7iyLFgOqhZNUQ6Ret5VpQ',
|
28
|
+
'RS384' => 'eyJhbGciOiJSUzM4NCJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.Sfgk56moPghtsjaP4so6tOy3I553mgwX-5gByMC6dX8lpeWgsxSeAd_K8IyO7u4lwYOL0DSftnqO1HEOuN1AKyBbDvaTXz3u2xNA2x4NYLdW4AZA6ritbYcKLO5BHTXw5ueMbtA1jjGXP0zI_aK2iJTMBmB8SCF88RYBUH01Tyf4PlLj98pGL-v3prZd6kZkIeRJ3326h04hslcB5HQKmgeBk24QNLIoIC-CD329HPjJ7TtGx01lj-ehTBnwVbBGzYFAyoalV5KgvL_MDOfWPr1OYHnR5s_Fm6_3Vg4u6lBljvHOrmv4Nfx7d8HLgbo8CwH4qn1wm6VQCtuDd-uhRg',
|
29
|
+
'RS512' => 'eyJhbGciOiJSUzUxMiJ9.eyJ1c2VyX2lkIjoic29tZUB1c2VyLnRsZCJ9.LIIAUEuCkGNdpYguOO5LoW4rZ7ED2POJrB0pmEAAchyTdIK4HKh1jcLxc6KyGwZv40njCgub3y72q6vcQTn7oD0zWFCVQRIDW1911Ii2hRNHuigiPUnrnZh1OQ6z65VZRU6GKs8omoBGU9vrClBU0ODqYE16KxYmE_0n4Xw2h3D_L1LF0IAOtDWKBRDa3QHwZRM9sHsHNsBuD5ye9KzDYN1YALXj64LBfA-DoCKfpVAm9NkRPOyzjR2X2C3TomOSJgqWIVHJucudKDDAZyEbO4RA5pI-UFYy1370p9bRajvtDyoBuLDCzoSkMyQ4L2DnLhx5CbWcnD7Cd3GUmnjjTA',
|
30
|
+
'ES256' => '',
|
31
|
+
'ES384' => '',
|
32
|
+
'ES512' => ''
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
after(:each) do
|
37
|
+
expect(OpenSSL.errors).to be_empty
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'alg: NONE' do
|
41
|
+
let(:alg) { 'none' }
|
42
|
+
|
43
|
+
it 'should generate a valid token' do
|
44
|
+
token = JWTB.encode payload, nil, alg
|
45
|
+
|
46
|
+
expect(token).to eq data['NONE']
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should decode a valid token' do
|
50
|
+
jwt_payload, header = JWTB.decode data['NONE'], nil, false
|
51
|
+
|
52
|
+
expect(header['alg']).to eq alg
|
53
|
+
expect(jwt_payload).to eq payload
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should display a better error message if payload exp is_a?(Time)' do
|
57
|
+
payload['exp'] = Time.now
|
58
|
+
|
59
|
+
expect do
|
60
|
+
JWTB.encode payload, nil, alg
|
61
|
+
end.to raise_error JWTB::InvalidPayload
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
%w(HS256 HS512256 HS384 HS512).each do |alg|
|
66
|
+
context "alg: #{alg}" do
|
67
|
+
it 'should generate a valid token' do
|
68
|
+
token = JWTB.encode payload, data[:secret], alg
|
69
|
+
|
70
|
+
expect(token).to eq data[alg]
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should decode a valid token' do
|
74
|
+
jwt_payload, header = JWTB.decode data[alg], data[:secret], true, algorithm: alg
|
75
|
+
|
76
|
+
expect(header['alg']).to eq alg
|
77
|
+
expect(jwt_payload).to eq payload
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'wrong secret should raise JWTB::DecodeError' do
|
81
|
+
expect do
|
82
|
+
JWTB.decode data[alg], 'wrong_secret', true, algorithm: alg
|
83
|
+
end.to raise_error JWTB::VerificationError
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'wrong secret and verify = false should not raise JWTB::DecodeError' do
|
87
|
+
expect do
|
88
|
+
JWTB.decode data[alg], 'wrong_secret', false
|
89
|
+
end.not_to raise_error
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
%w(RS256 RS384 RS512).each do |alg|
|
95
|
+
context "alg: #{alg}" do
|
96
|
+
it 'should generate a valid token' do
|
97
|
+
token = JWTB.encode payload, data[:rsa_private], alg
|
98
|
+
|
99
|
+
expect(token).to eq data[alg]
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should decode a valid token' do
|
103
|
+
jwt_payload, header = JWTB.decode data[alg], data[:rsa_public], true, algorithm: alg
|
104
|
+
|
105
|
+
expect(header['alg']).to eq alg
|
106
|
+
expect(jwt_payload).to eq payload
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'wrong key should raise JWTB::DecodeError' do
|
110
|
+
key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))
|
111
|
+
|
112
|
+
expect do
|
113
|
+
JWTB.decode data[alg], key, true, algorithm: alg
|
114
|
+
end.to raise_error JWTB::DecodeError
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'wrong key and verify = false should not raise JWTB::DecodeError' do
|
118
|
+
key = OpenSSL::PKey.read File.read(File.join(CERT_PATH, 'rsa-2048-wrong-public.pem'))
|
119
|
+
|
120
|
+
expect do
|
121
|
+
JWTB.decode data[alg], key, false
|
122
|
+
end.not_to raise_error
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
%w(ES256 ES384 ES512).each do |alg|
|
128
|
+
context "alg: #{alg}" do
|
129
|
+
before(:each) do
|
130
|
+
data[alg] = JWTB.encode payload, data["#{alg}_private"], alg
|
131
|
+
end
|
132
|
+
|
133
|
+
let(:wrong_key) { OpenSSL::PKey.read(File.read(File.join(CERT_PATH, 'ec256-wrong-public.pem'))) }
|
134
|
+
|
135
|
+
it 'should generate a valid token' do
|
136
|
+
jwt_payload, header = JWTB.decode data[alg], data["#{alg}_public"], true, algorithm: alg
|
137
|
+
|
138
|
+
expect(header['alg']).to eq alg
|
139
|
+
expect(jwt_payload).to eq payload
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should decode a valid token' do
|
143
|
+
jwt_payload, header = JWTB.decode data[alg], data["#{alg}_public"], true, algorithm: alg
|
144
|
+
|
145
|
+
expect(header['alg']).to eq alg
|
146
|
+
expect(jwt_payload).to eq payload
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'wrong key should raise JWTB::DecodeError' do
|
150
|
+
expect do
|
151
|
+
JWTB.decode data[alg], wrong_key
|
152
|
+
end.to raise_error JWTB::DecodeError
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'wrong key and verify = false should not raise JWTB::DecodeError' do
|
156
|
+
expect do
|
157
|
+
JWTB.decode data[alg], wrong_key, false
|
158
|
+
end.not_to raise_error
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'Invalid' do
|
164
|
+
it 'algorithm should raise NotImplementedError' do
|
165
|
+
expect do
|
166
|
+
JWTB.encode payload, 'secret', 'HS255'
|
167
|
+
end.to raise_error NotImplementedError
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'ECDSA curve_name should raise JWTB::IncorrectAlgorithm' do
|
171
|
+
key = OpenSSL::PKey::EC.new 'secp256k1'
|
172
|
+
key.generate_key
|
173
|
+
|
174
|
+
expect do
|
175
|
+
JWTB.encode payload, key, 'ES256'
|
176
|
+
end.to raise_error JWTB::IncorrectAlgorithm
|
177
|
+
|
178
|
+
token = JWTB.encode payload, data['ES256_private'], 'ES256'
|
179
|
+
key.private_key = nil
|
180
|
+
|
181
|
+
expect do
|
182
|
+
JWTB.decode token, key
|
183
|
+
end.to raise_error JWTB::IncorrectAlgorithm
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'Verify' do
|
188
|
+
context 'algorithm' do
|
189
|
+
it 'should raise JWTB::IncorrectAlgorithm on missmatch' do
|
190
|
+
token = JWTB.encode payload, data[:secret], 'HS512'
|
191
|
+
|
192
|
+
expect do
|
193
|
+
JWTB.decode token, data[:secret], true, algorithm: 'HS384'
|
194
|
+
end.to raise_error JWTB::IncorrectAlgorithm
|
195
|
+
|
196
|
+
expect do
|
197
|
+
JWTB.decode token, data[:secret], true, algorithm: 'HS512'
|
198
|
+
end.not_to raise_error
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'should raise JWTB::IncorrectAlgorithm if no algorithm is provided' do
|
202
|
+
token = JWTB.encode payload, data[:rsa_public].to_s, 'HS256'
|
203
|
+
|
204
|
+
expect do
|
205
|
+
JWTB.decode token, data[:rsa_public], true
|
206
|
+
end.to raise_error JWTB::IncorrectAlgorithm
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
context 'issuer claim' do
|
211
|
+
let(:iss) { 'ruby-jwt-gem' }
|
212
|
+
let(:invalid_token) { JWTB.encode payload, data[:secret] }
|
213
|
+
|
214
|
+
let :token do
|
215
|
+
iss_payload = payload.merge(iss: iss)
|
216
|
+
JWTB.encode iss_payload, data[:secret]
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'if verify_iss is set to false (default option) should not raise JWTB::InvalidIssuerError' do
|
220
|
+
expect do
|
221
|
+
JWTB.decode token, data[:secret], true, iss: iss, algorithm: 'HS256'
|
222
|
+
end.not_to raise_error
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context 'Base64' do
|
228
|
+
it 'urlsafe replace + / with - _' do
|
229
|
+
allow(Base64).to receive(:encode64) { 'string+with/non+url-safe/characters_' }
|
230
|
+
expect(JWTB::Encode.base64url_encode('foo')).to eq('string-with_non-url-safe_characters_')
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
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 = [: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
|