json-jwt 1.3.1 → 1.4.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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/json/jwe.rb +72 -33
- data/lib/json/jws.rb +52 -7
- data/lib/json/jwt.rb +14 -50
- data/spec/json/jwe_spec.rb +4 -15
- data/spec/json/jwk/set_spec.rb +14 -0
- data/spec/json/jws_spec.rb +2 -2
- data/spec/json/jwt_spec.rb +80 -18
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6817c45c39a6ae6f9240df8b7edb8d407ef79744
|
4
|
+
data.tar.gz: 8f97ad80b2d8fda2732b8cbbf8166b9ca8bca404
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cc01ddbca74f1dd13cc054e5b3e2d1d9242191309526a29c1c1e75e5c5f08d70cb79c208dd4afb1b7dc948bed2b85adef25f5c8a9314ec0f5ff256a9cbdd0b2
|
7
|
+
data.tar.gz: 17b0980e989fd63dcf0ee5ee48dd8cc44d38ead751ecf6523e2ea4ed7d820b520be0502d0fb9265d73c330bf0aebd8c7794b610d69373526bfc3d14a4803fe4a
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0
|
data/lib/json/jwe.rb
CHANGED
@@ -10,16 +10,16 @@ module JSON
|
|
10
10
|
NUM_OF_SEGMENTS = 5
|
11
11
|
|
12
12
|
attr_accessor(
|
13
|
-
:public_key_or_secret, :private_key_or_secret,
|
14
|
-
:
|
13
|
+
:public_key_or_secret, :private_key_or_secret,
|
14
|
+
:plain_text, :cipher_text, :authentication_tag, :iv, :auth_data,
|
15
15
|
:content_encryption_key, :jwe_encrypted_key, :encryption_key, :mac_key
|
16
16
|
)
|
17
17
|
|
18
18
|
register_header_keys :enc, :epk, :zip, :apu, :apv
|
19
19
|
alias_method :encryption_method, :enc
|
20
20
|
|
21
|
-
def initialize(input)
|
22
|
-
self.
|
21
|
+
def initialize(input = nil)
|
22
|
+
self.plain_text = input.to_s
|
23
23
|
end
|
24
24
|
|
25
25
|
def content_type
|
@@ -27,8 +27,6 @@ module JSON
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def encrypt!(public_key_or_secret)
|
30
|
-
self.mode = :encryption
|
31
|
-
self.plain_text = input
|
32
30
|
self.public_key_or_secret = public_key_or_secret
|
33
31
|
cipher.encrypt
|
34
32
|
generate_cipher_keys!
|
@@ -37,9 +35,7 @@ module JSON
|
|
37
35
|
end
|
38
36
|
|
39
37
|
def decrypt!(private_key_or_secret)
|
40
|
-
self.mode = :decryption
|
41
38
|
self.private_key_or_secret = private_key_or_secret
|
42
|
-
decode_segments!
|
43
39
|
cipher.decrypt
|
44
40
|
restore_cipher_keys!
|
45
41
|
self.plain_text = cipher.update(cipher_text) + cipher.final
|
@@ -48,18 +44,39 @@ module JSON
|
|
48
44
|
end
|
49
45
|
|
50
46
|
def to_s
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
47
|
+
[
|
48
|
+
header.to_json,
|
49
|
+
jwe_encrypted_key,
|
50
|
+
iv,
|
51
|
+
cipher_text,
|
52
|
+
authentication_tag
|
53
|
+
].collect do |segment|
|
54
|
+
UrlSafeBase64.encode64 segment.to_s
|
55
|
+
end.join('.')
|
56
|
+
end
|
57
|
+
|
58
|
+
def as_json(options = {})
|
59
|
+
case options[:syntax]
|
60
|
+
when :general
|
61
|
+
{
|
62
|
+
protected: UrlSafeBase64.encode64(header.to_json),
|
63
|
+
recipients: [{
|
64
|
+
encrypted_key: UrlSafeBase64.encode64(jwe_encrypted_key)
|
65
|
+
}],
|
66
|
+
iv: UrlSafeBase64.encode64(iv),
|
67
|
+
ciphertext: UrlSafeBase64.encode64(cipher_text),
|
68
|
+
tag: UrlSafeBase64.encode64(authentication_tag)
|
69
|
+
}
|
70
|
+
when :flattened
|
71
|
+
{
|
72
|
+
protected: UrlSafeBase64.encode64(header.to_json),
|
73
|
+
encrypted_key: UrlSafeBase64.encode64(jwe_encrypted_key),
|
74
|
+
iv: UrlSafeBase64.encode64(iv),
|
75
|
+
ciphertext: UrlSafeBase64.encode64(cipher_text),
|
76
|
+
tag: UrlSafeBase64.encode64(authentication_tag)
|
77
|
+
}
|
61
78
|
else
|
62
|
-
|
79
|
+
super
|
63
80
|
end
|
64
81
|
end
|
65
82
|
|
@@ -166,8 +183,9 @@ module JSON
|
|
166
183
|
end
|
167
184
|
cipher.key = encryption_key
|
168
185
|
self.iv = cipher.random_iv
|
186
|
+
self.auth_data = UrlSafeBase64.encode64 header.to_json
|
169
187
|
if gcm?
|
170
|
-
cipher.auth_data =
|
188
|
+
cipher.auth_data = self.auth_data
|
171
189
|
end
|
172
190
|
self
|
173
191
|
end
|
@@ -197,7 +215,6 @@ module JSON
|
|
197
215
|
when gcm?
|
198
216
|
cipher.auth_tag
|
199
217
|
when cbc?
|
200
|
-
auth_data = UrlSafeBase64.encode64 header.to_json
|
201
218
|
secured_input = [
|
202
219
|
auth_data,
|
203
220
|
iv,
|
@@ -212,16 +229,6 @@ module JSON
|
|
212
229
|
|
213
230
|
# decryption
|
214
231
|
|
215
|
-
def decode_segments!
|
216
|
-
unless input.count('.') + 1 == NUM_OF_SEGMENTS
|
217
|
-
raise InvalidFormat.new("Invalid JWE Format. JWE should include #{NUM_OF_SEGMENTS} segments.")
|
218
|
-
end
|
219
|
-
_header_json_, self.jwe_encrypted_key, self.iv, self.cipher_text, self.authentication_tag = input.split('.').collect do |segment|
|
220
|
-
UrlSafeBase64.decode64 segment
|
221
|
-
end
|
222
|
-
self
|
223
|
-
end
|
224
|
-
|
225
232
|
def decrypt_content_encryption_key
|
226
233
|
case algorithm.try(:to_sym)
|
227
234
|
when :RSA1_5
|
@@ -257,12 +264,11 @@ module JSON
|
|
257
264
|
cipher.iv = iv # NOTE: 'iv' has to be set after 'key' for GCM
|
258
265
|
if gcm?
|
259
266
|
cipher.auth_tag = authentication_tag
|
260
|
-
cipher.auth_data =
|
267
|
+
cipher.auth_data = auth_data
|
261
268
|
end
|
262
269
|
end
|
263
270
|
|
264
271
|
def verify_cbc_authentication_tag!
|
265
|
-
auth_data = input.split('.').first
|
266
272
|
secured_input = [
|
267
273
|
auth_data,
|
268
274
|
iv,
|
@@ -276,5 +282,38 @@ module JSON
|
|
276
282
|
raise DecryptionFailed.new('Invalid authentication tag')
|
277
283
|
end
|
278
284
|
end
|
285
|
+
|
286
|
+
class << self
|
287
|
+
def decode_compact_serialized(input, private_key_or_secret)
|
288
|
+
unless input.count('.') + 1 == NUM_OF_SEGMENTS
|
289
|
+
raise InvalidFormat.new("Invalid JWE Format. JWE should include #{NUM_OF_SEGMENTS} segments.")
|
290
|
+
end
|
291
|
+
jwe = new
|
292
|
+
_header_json_, jwe.jwe_encrypted_key, jwe.iv, jwe.cipher_text, jwe.authentication_tag = input.split('.').collect do |segment|
|
293
|
+
UrlSafeBase64.decode64 segment
|
294
|
+
end
|
295
|
+
jwe.auth_data = input.split('.').first
|
296
|
+
jwe.header = MultiJson.load(_header_json_).with_indifferent_access
|
297
|
+
jwe.decrypt! private_key_or_secret unless private_key_or_secret == :skip_decryption
|
298
|
+
jwe
|
299
|
+
end
|
300
|
+
|
301
|
+
def decode_json_serialized(input, private_key_or_secret)
|
302
|
+
input = input.with_indifferent_access
|
303
|
+
jwe_encrypted_key = if input[:recipients].present?
|
304
|
+
input[:recipients].first[:encrypted_key]
|
305
|
+
else
|
306
|
+
input[:encrypted_key]
|
307
|
+
end
|
308
|
+
compact_serialized = [
|
309
|
+
input[:protected],
|
310
|
+
jwe_encrypted_key,
|
311
|
+
input[:iv],
|
312
|
+
input[:ciphertext],
|
313
|
+
input[:tag]
|
314
|
+
].join('.')
|
315
|
+
decode_compact_serialized compact_serialized, private_key_or_secret
|
316
|
+
end
|
317
|
+
end
|
279
318
|
end
|
280
319
|
end
|
data/lib/json/jws.rb
CHANGED
@@ -6,9 +6,10 @@ module JSON
|
|
6
6
|
|
7
7
|
NUM_OF_SEGMENTS = 3
|
8
8
|
|
9
|
+
attr_accessor :signature_base_string
|
10
|
+
|
9
11
|
def initialize(jwt)
|
10
12
|
update jwt
|
11
|
-
raise InvalidFormat.new('Signature Algorithm Required') unless algorithm
|
12
13
|
end
|
13
14
|
|
14
15
|
def sign!(private_key_or_secret)
|
@@ -16,9 +17,14 @@ module JSON
|
|
16
17
|
self
|
17
18
|
end
|
18
19
|
|
19
|
-
def verify(
|
20
|
-
|
21
|
-
|
20
|
+
def verify!(public_key_or_secret)
|
21
|
+
if alg.try(:to_sym) == :none
|
22
|
+
raise UnexpectedAlgorithm if public_key_or_secret
|
23
|
+
signature == '' or raise VerificationFailed
|
24
|
+
else
|
25
|
+
public_key_or_secret && valid?(public_key_or_secret) or
|
26
|
+
raise VerificationFailed
|
27
|
+
end
|
22
28
|
end
|
23
29
|
|
24
30
|
def update_with_jose_attributes(hash_or_jwt)
|
@@ -50,7 +56,7 @@ module JSON
|
|
50
56
|
end
|
51
57
|
|
52
58
|
def signature_base_string
|
53
|
-
[
|
59
|
+
@signature_base_string ||= [
|
54
60
|
header.to_json,
|
55
61
|
self.to_json
|
56
62
|
].collect do |segment|
|
@@ -79,7 +85,7 @@ module JSON
|
|
79
85
|
end
|
80
86
|
end
|
81
87
|
|
82
|
-
def valid?(
|
88
|
+
def valid?(public_key_or_secret)
|
83
89
|
public_key_or_secret = with_jwk_support public_key_or_secret
|
84
90
|
case
|
85
91
|
when hmac?
|
@@ -107,7 +113,7 @@ module JSON
|
|
107
113
|
key.to_key
|
108
114
|
when JSON::JWK::Set
|
109
115
|
key.detect do |jwk|
|
110
|
-
jwk[:kid] && jwk[:kid] ==
|
116
|
+
jwk[:kid] && jwk[:kid] == kid
|
111
117
|
end.try(:to_key) or raise JWK::Set::KidNotFound
|
112
118
|
else
|
113
119
|
key
|
@@ -138,5 +144,44 @@ module JSON
|
|
138
144
|
byte_size = (private_key.group.degree + 7) / 8
|
139
145
|
OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
|
140
146
|
end
|
147
|
+
|
148
|
+
class << self
|
149
|
+
def decode_compact_serialized(input, public_key_or_secret)
|
150
|
+
unless input.count('.') + 1 == NUM_OF_SEGMENTS
|
151
|
+
raise InvalidFormat.new("Invalid JWS Format. JWS should include #{NUM_OF_SEGMENTS} segments.")
|
152
|
+
end
|
153
|
+
header, claims, signature = input.split('.', JWS::NUM_OF_SEGMENTS).collect do |segment|
|
154
|
+
UrlSafeBase64.decode64 segment.to_s
|
155
|
+
end
|
156
|
+
header, claims = [header, claims].collect do |json|
|
157
|
+
MultiJson.load(json).with_indifferent_access
|
158
|
+
end
|
159
|
+
jws = new claims
|
160
|
+
jws.header = header
|
161
|
+
jws.signature = signature
|
162
|
+
jws.signature_base_string = input.split('.')[0, JWS::NUM_OF_SEGMENTS - 1].join('.')
|
163
|
+
jws.verify! public_key_or_secret unless public_key_or_secret == :skip_verification
|
164
|
+
jws
|
165
|
+
end
|
166
|
+
|
167
|
+
def decode_json_serialized(input, public_key_or_secret)
|
168
|
+
input = input.with_indifferent_access
|
169
|
+
header, payload, signature = if input[:signatures].present?
|
170
|
+
[
|
171
|
+
input[:signatures].first[:protected],
|
172
|
+
input[:payload],
|
173
|
+
input[:signatures].first[:signature]
|
174
|
+
].collect do |segment|
|
175
|
+
segment
|
176
|
+
end
|
177
|
+
else
|
178
|
+
[:protected, :payload, :signature].collect do |key|
|
179
|
+
input[key]
|
180
|
+
end
|
181
|
+
end
|
182
|
+
compact_serialized = [header, payload, signature].join('.')
|
183
|
+
decode_compact_serialized compact_serialized, public_key_or_secret
|
184
|
+
end
|
185
|
+
end
|
141
186
|
end
|
142
187
|
end
|
data/lib/json/jwt.rb
CHANGED
@@ -51,13 +51,11 @@ module JSON
|
|
51
51
|
jws.sign! private_key_or_secret
|
52
52
|
end
|
53
53
|
|
54
|
+
# NOTE: keeping for backward compatibility
|
54
55
|
def verify(signature_base_string, public_key_or_secret = nil)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
else
|
59
|
-
JWS.new(self).verify(signature_base_string, public_key_or_secret)
|
60
|
-
end
|
56
|
+
jws = JWS.new self
|
57
|
+
jws.signature_base_string = signature_base_string
|
58
|
+
jws.verify! public_key_or_secret
|
61
59
|
end
|
62
60
|
|
63
61
|
def encrypt(public_key_or_secret, algorithm = :RSA1_5, encryption_method = :'A128CBC-HS256')
|
@@ -105,64 +103,30 @@ module JSON
|
|
105
103
|
else
|
106
104
|
decode_compact_serialized input, key_or_secret
|
107
105
|
end
|
106
|
+
rescue MultiJson::DecodeError
|
107
|
+
raise InvalidFormat.new("Invalid JSON Format")
|
108
108
|
end
|
109
109
|
|
110
|
-
private
|
111
|
-
|
112
110
|
def decode_compact_serialized(jwt_string, key_or_secret)
|
113
111
|
case jwt_string.count('.') + 1
|
114
|
-
when JWS::NUM_OF_SEGMENTS
|
115
|
-
|
116
|
-
UrlSafeBase64.decode64 segment.to_s
|
117
|
-
end
|
118
|
-
header, claims = [header, claims].collect do |json|
|
119
|
-
MultiJson.load(json).with_indifferent_access
|
120
|
-
end
|
121
|
-
signature_base_string = jwt_string.split('.')[0, JWS::NUM_OF_SEGMENTS - 1].join('.')
|
122
|
-
jwt = new claims
|
123
|
-
jwt.header = header
|
124
|
-
jwt.signature = signature
|
125
|
-
|
126
|
-
# NOTE:
|
127
|
-
# Some JSON libraries generates wrong format of JSON (spaces between keys and values etc.)
|
128
|
-
# So we need to use raw base64 strings for signature verification.
|
129
|
-
jwt.verify signature_base_string, key_or_secret unless key_or_secret == :skip_verification
|
130
|
-
jwt
|
112
|
+
when JWS::NUM_OF_SEGMENTS
|
113
|
+
JWS.decode_compact_serialized jwt_string, key_or_secret
|
131
114
|
when JWE::NUM_OF_SEGMENTS
|
132
|
-
|
133
|
-
jwe.header = MultiJson.load(
|
134
|
-
UrlSafeBase64.decode64 jwt_string.split('.').first
|
135
|
-
).with_indifferent_access
|
136
|
-
if key_or_secret == :skip_decryption
|
137
|
-
jwe
|
138
|
-
else
|
139
|
-
jwe.decrypt! key_or_secret
|
140
|
-
JSON::JWT.decode jwe.plain_text, :skip_verification
|
141
|
-
end
|
115
|
+
JWE.decode_compact_serialized jwt_string, key_or_secret
|
142
116
|
else
|
143
117
|
raise InvalidFormat.new("Invalid JWT Format. JWT should include #{JWS::NUM_OF_SEGMENTS} or #{JWE::NUM_OF_SEGMENTS} segments.")
|
144
118
|
end
|
145
|
-
rescue MultiJson::DecodeError
|
146
|
-
raise InvalidFormat.new("Invalid JSON Format")
|
147
119
|
end
|
148
120
|
|
149
121
|
def decode_json_serialized(input, key_or_secret)
|
150
122
|
input = input.with_indifferent_access
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
input[:signatures].first[:signature]
|
156
|
-
].collect do |segment|
|
157
|
-
segment
|
158
|
-
end
|
123
|
+
if (input[:signatures] || input[:signature]).present?
|
124
|
+
JWS.decode_json_serialized input, key_or_secret
|
125
|
+
elsif input[:ciphertext].present?
|
126
|
+
JWE.decode_json_serialized input, key_or_secret
|
159
127
|
else
|
160
|
-
|
161
|
-
input[key]
|
162
|
-
end
|
128
|
+
raise InvalidFormat.new("Unexpected JOSE JSON Serialization Format.")
|
163
129
|
end
|
164
|
-
jwt_string = [header, payload, signature].join('.')
|
165
|
-
decode_compact_serialized jwt_string, key_or_secret
|
166
130
|
end
|
167
131
|
end
|
168
132
|
end
|
data/spec/json/jwe_spec.rb
CHANGED
@@ -120,14 +120,14 @@ describe JSON::JWE do
|
|
120
120
|
|
121
121
|
describe 'decrypt!' do
|
122
122
|
let(:plain_text) { 'Hello World' }
|
123
|
-
let(:
|
123
|
+
let(:jwe_string) do
|
124
124
|
_jwe_ = JSON::JWE.new plain_text
|
125
125
|
_jwe_.alg, _jwe_.enc = alg, enc
|
126
126
|
_jwe_.encrypt! key
|
127
127
|
_jwe_.to_s
|
128
128
|
end
|
129
129
|
let(:jwe) do
|
130
|
-
_jwe_ = JSON::JWE.
|
130
|
+
_jwe_ = JSON::JWE.decode jwe_string, :skip_decryption
|
131
131
|
_jwe_.alg, _jwe_.enc = alg, enc
|
132
132
|
_jwe_
|
133
133
|
end
|
@@ -135,7 +135,7 @@ describe JSON::JWE do
|
|
135
135
|
shared_examples_for :decryptable do
|
136
136
|
it do
|
137
137
|
jwe.decrypt! key
|
138
|
-
jwe.
|
138
|
+
jwe.plain_text.should == plain_text
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
@@ -148,7 +148,7 @@ describe JSON::JWE do
|
|
148
148
|
end
|
149
149
|
|
150
150
|
shared_examples_for :verify_cbc_authentication_tag do
|
151
|
-
let(:
|
151
|
+
let(:jwe_string) do
|
152
152
|
_jwe_ = JSON::JWE.new plain_text
|
153
153
|
_jwe_.alg, _jwe_.enc = alg, enc
|
154
154
|
_jwe_.encrypt! key
|
@@ -275,16 +275,5 @@ describe JSON::JWE do
|
|
275
275
|
end
|
276
276
|
end
|
277
277
|
end
|
278
|
-
|
279
|
-
context 'when invalid format of input given' do
|
280
|
-
let(:input) { 'header.payload.signature' }
|
281
|
-
let(:alg) { :RSA1_5 }
|
282
|
-
let(:enc) { :'A128CBC-HS256' }
|
283
|
-
it do
|
284
|
-
expect do
|
285
|
-
jwe.decrypt! public_key
|
286
|
-
end.to raise_error JSON::JWE::InvalidFormat
|
287
|
-
end
|
288
|
-
end
|
289
278
|
end
|
290
279
|
end
|
data/spec/json/jwk/set_spec.rb
CHANGED
@@ -45,6 +45,20 @@ describe JSON::JWK::Set do
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
context 'when pure Hash with :keys key given' do
|
49
|
+
subject do
|
50
|
+
JSON::JWK::Set.new(
|
51
|
+
keys: jwk.as_json
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should convert into JSON::JWK' do
|
56
|
+
subject.each do |jwk|
|
57
|
+
jwk.should be_instance_of JSON::JWK
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
48
62
|
describe '#as_json' do
|
49
63
|
it 'should become proper JWK set format' do
|
50
64
|
json = set.as_json
|
data/spec/json/jws_spec.rb
CHANGED
@@ -131,7 +131,7 @@ describe JSON::JWS do
|
|
131
131
|
let(:signed) { jws.sign!(jwks) }
|
132
132
|
|
133
133
|
context 'when jwk is found by given kid' do
|
134
|
-
before { jws.
|
134
|
+
before { jws.kid = kid }
|
135
135
|
it { should == jws.sign!('secret') }
|
136
136
|
end
|
137
137
|
|
@@ -242,7 +242,7 @@ describe JSON::JWS do
|
|
242
242
|
let(:signed) { jws.sign!(jwks) }
|
243
243
|
|
244
244
|
context 'when jwk is found by given kid' do
|
245
|
-
before { jws.
|
245
|
+
before { jws.kid = kid }
|
246
246
|
it { should == signed }
|
247
247
|
end
|
248
248
|
|
data/spec/json/jwt_spec.rb
CHANGED
@@ -92,7 +92,7 @@ describe JSON::JWT do
|
|
92
92
|
|
93
93
|
context 'when signed' do
|
94
94
|
it 'should delegate verification to JWS' do
|
95
|
-
expect(jws).to receive(:verify)
|
95
|
+
expect(jws).to receive(:verify!)
|
96
96
|
expect(JSON::JWS).to receive(:new).and_return(jws)
|
97
97
|
jwt.verify 'shared_secret'
|
98
98
|
end
|
@@ -148,16 +148,19 @@ describe JSON::JWT do
|
|
148
148
|
context 'when alg header malformed' do
|
149
149
|
context 'from alg=HS256' do
|
150
150
|
context 'to alg=none' do
|
151
|
-
let(:
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
151
|
+
let(:malformed_jwt_string) do
|
152
|
+
header, payload, signature = jws.to_s.split('.')
|
153
|
+
malformed_header = {alg: :none}.to_json
|
154
|
+
[
|
155
|
+
UrlSafeBase64.encode64(malformed_header),
|
156
|
+
payload,
|
157
|
+
''
|
158
|
+
].join('.')
|
156
159
|
end
|
157
160
|
|
158
161
|
it 'should do verification' do
|
159
162
|
expect do
|
160
|
-
JSON::JWT.decode
|
163
|
+
JSON::JWT.decode malformed_jwt_string, 'secret'
|
161
164
|
end.to raise_error JSON::JWT::VerificationFailed
|
162
165
|
end
|
163
166
|
end
|
@@ -169,29 +172,42 @@ describe JSON::JWT do
|
|
169
172
|
end
|
170
173
|
|
171
174
|
context 'to alg=none' do
|
172
|
-
let(:
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
175
|
+
let(:malformed_jwt_string) do
|
176
|
+
header, payload, signature = jws.to_s.split('.')
|
177
|
+
malformed_header = {alg: :none}.to_json
|
178
|
+
[
|
179
|
+
UrlSafeBase64.encode64(malformed_header),
|
180
|
+
payload,
|
181
|
+
''
|
182
|
+
].join('.')
|
177
183
|
end
|
178
184
|
|
179
185
|
it 'should fail verification' do
|
180
186
|
expect do
|
181
|
-
JSON::JWT.decode
|
187
|
+
JSON::JWT.decode malformed_jwt_string, public_key
|
182
188
|
end.to raise_error JSON::JWT::UnexpectedAlgorithm
|
183
189
|
end
|
184
190
|
end
|
185
191
|
|
186
192
|
context 'to alg=HS256' do
|
187
|
-
let(:
|
188
|
-
|
189
|
-
|
193
|
+
let(:malformed_jwt_string) do
|
194
|
+
header, payload, signature = jws.to_s.split('.')
|
195
|
+
malformed_header = {alg: :HS256}.to_json
|
196
|
+
malformed_signature = OpenSSL::HMAC.digest(
|
197
|
+
OpenSSL::Digest.new('SHA256'),
|
198
|
+
public_key.to_s,
|
199
|
+
[malformed_header, payload].join('.')
|
200
|
+
)
|
201
|
+
[
|
202
|
+
UrlSafeBase64.encode64(malformed_header),
|
203
|
+
payload,
|
204
|
+
UrlSafeBase64.encode64(malformed_signature)
|
205
|
+
].join('.')
|
190
206
|
end
|
191
207
|
|
192
208
|
it 'should fail verification' do
|
193
209
|
expect do
|
194
|
-
JSON::JWT.decode
|
210
|
+
JSON::JWT.decode malformed_jwt_string, public_key
|
195
211
|
end.to raise_error JSON::JWS::UnexpectedAlgorithm
|
196
212
|
end
|
197
213
|
end
|
@@ -206,6 +222,52 @@ describe JSON::JWT do
|
|
206
222
|
end.not_to raise_error
|
207
223
|
end
|
208
224
|
end
|
225
|
+
|
226
|
+
context 'when JSON Serialization given' do
|
227
|
+
let(:signed) { JSON::JWT.new(claims).sign('secret') }
|
228
|
+
|
229
|
+
shared_examples_for :json_serialization_parser do
|
230
|
+
context 'when proper secret given' do
|
231
|
+
it { JSON::JWT.decode(serialized, 'secret').should == signed }
|
232
|
+
end
|
233
|
+
|
234
|
+
context 'when verification skipped' do
|
235
|
+
it { JSON::JWT.decode(serialized, :skip_verification).should == signed }
|
236
|
+
end
|
237
|
+
|
238
|
+
context 'when wrong secret given' do
|
239
|
+
it do
|
240
|
+
expect do
|
241
|
+
JSON::JWT.decode serialized, 'wrong'
|
242
|
+
end.to raise_error JSON::JWT::VerificationFailed
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
context 'when general' do
|
248
|
+
let(:serialized) do
|
249
|
+
{
|
250
|
+
payload: UrlSafeBase64.encode64(claims.to_json),
|
251
|
+
signatures: [{
|
252
|
+
protected: UrlSafeBase64.encode64(signed.header.to_json),
|
253
|
+
signature: UrlSafeBase64.encode64(signed.signature)
|
254
|
+
}]
|
255
|
+
}
|
256
|
+
end
|
257
|
+
it_behaves_like :json_serialization_parser
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'when flattened' do
|
261
|
+
let(:serialized) do
|
262
|
+
{
|
263
|
+
protected: UrlSafeBase64.encode64(signed.header.to_json),
|
264
|
+
payload: UrlSafeBase64.encode64(claims.to_json),
|
265
|
+
signature: UrlSafeBase64.encode64(signed.signature)
|
266
|
+
}
|
267
|
+
end
|
268
|
+
it_behaves_like :json_serialization_parser
|
269
|
+
end
|
270
|
+
end
|
209
271
|
end
|
210
272
|
|
211
273
|
context 'when encrypted' do
|
@@ -213,7 +275,7 @@ describe JSON::JWT do
|
|
213
275
|
let(:shared_key) { SecureRandom.hex 16 } # default shared key is too short
|
214
276
|
|
215
277
|
it 'should decryptable' do
|
216
|
-
JSON::JWT.decode(input, private_key).should be_instance_of JSON::
|
278
|
+
JSON::JWT.decode(input, private_key).should be_instance_of JSON::JWE
|
217
279
|
end
|
218
280
|
|
219
281
|
context 'when :skip_decryption given as secret/key' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-jwt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nov matake
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08
|
11
|
+
date: 2015-09-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: multi_json
|