json-jwt 1.3.1 → 1.4.0
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.
- 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
|