jwt 1.5.0 → 1.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee5f493cb3c4ed9c97a60b59f7377f410b280218
4
- data.tar.gz: f86ae6f76dbdd064ff4a7a83370b1ba343981d90
3
+ metadata.gz: 20bef3dbabb4260b05cd6119dc1b552d630bd3e1
4
+ data.tar.gz: bb02d4a2bb19011a8eb531020d4780f31d44af7b
5
5
  SHA512:
6
- metadata.gz: 79802a75028b87314162658551582a1c4ace40439ac718bc8ac82ed57ccaa9b5d0ac695cf4daa318bcc89616ddc8e93bf3ff79d7cb4c47903c03aee51e5bb8a1
7
- data.tar.gz: c14849f306b4952c7eba478d8fbc11c0a5045f38b931b563c67fef6367d9a8e89a66b78cccd9c8e4fbc546645e221b9b70437cde4aed18ca584269a95e94e9b6
6
+ metadata.gz: b8a0290f1b20390efb50c613da54a37072ebceee5dc11a9cec82cf67fa9e4002f3974bb35bd503b4dd7fdaacaed47c46f6f611aa8a66200cf44fbe40eaae8a2c
7
+ data.tar.gz: c9bb1d911b9d3cbabe362d69c6a556c8596f1dcd2485635875d02a74e93768b56fae8c5ee683ba03c5223b8696acda8080bbe408ea580ace5052ff48dfb7cb7b
data/Rakefile CHANGED
@@ -1,8 +1,9 @@
1
+ # encoding: utf-8
1
2
  require 'rubygems'
2
3
  require 'rake'
3
4
  require 'echoe'
4
5
 
5
- Echoe.new('jwt', '1.5.0') do |p|
6
+ Echoe.new('jwt', '1.5.1') do |p|
6
7
  p.description = 'JSON Web Token implementation in Ruby'
7
8
  p.url = 'http://github.com/progrium/ruby-jwt'
8
9
  p.author = 'Jeff Lindsay'
data/jwt.gemspec CHANGED
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: jwt 1.5.0 ruby lib
2
+ # stub: jwt 1.5.1 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "jwt"
6
- s.version = "1.5.0"
6
+ s.version = "1.5.1"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib"]
10
10
  s.authors = ["Jeff Lindsay"]
11
- s.date = "2015-05-09"
11
+ s.date = "2015-06-22"
12
12
  s.description = "JSON Web Token implementation in Ruby"
13
13
  s.email = "progrium@gmail.com"
14
14
  s.extra_rdoc_files = ["lib/jwt.rb", "lib/jwt/json.rb"]
data/lib/jwt.rb CHANGED
@@ -1,13 +1,13 @@
1
- #
2
- # JSON Web Token implementation
3
- #
4
- # Should be up to date with the latest spec:
5
- # http://self-issued.info/docs/draft-jones-json-web-token-06.html
1
+ # encoding: utf-8
6
2
 
7
3
  require 'base64'
8
4
  require 'openssl'
9
5
  require 'jwt/json'
10
6
 
7
+ # JSON Web Token implementation
8
+ #
9
+ # Should be up to date with the latest spec:
10
+ # http://self-issued.info/docs/draft-jones-json-web-token-06.html
11
11
  module JWT
12
12
  class DecodeError < StandardError; end
13
13
  class VerificationError < DecodeError; end
@@ -24,7 +24,7 @@ module JWT
24
24
  NAMED_CURVES = {
25
25
  'prime256v1' => 'ES256',
26
26
  'secp384r1' => 'ES384',
27
- 'secp521r1' => 'ES512',
27
+ 'secp521r1' => 'ES512'
28
28
  }
29
29
 
30
30
  module_function
@@ -37,7 +37,7 @@ module JWT
37
37
  elsif ['ES256', 'ES384', 'ES512'].include?(algorithm)
38
38
  sign_ecdsa(algorithm, msg, key)
39
39
  else
40
- raise NotImplementedError.new('Unsupported signing method')
40
+ fail NotImplementedError.new('Unsupported signing method')
41
41
  end
42
42
  end
43
43
 
@@ -48,11 +48,11 @@ module JWT
48
48
  def sign_ecdsa(algorithm, msg, private_key)
49
49
  key_algorithm = NAMED_CURVES[private_key.group.curve_name]
50
50
  if algorithm != key_algorithm
51
- raise IncorrectAlgorithm.new("payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided")
51
+ fail IncorrectAlgorithm.new("payload algorithm is #{algorithm} but #{key_algorithm} signing key was provided")
52
52
  end
53
53
 
54
54
  digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
55
- private_key.dsa_sign_asn1(digest.digest(msg))
55
+ asn1_to_raw(private_key.dsa_sign_asn1(digest.digest(msg)), private_key)
56
56
  end
57
57
 
58
58
  def verify_rsa(algorithm, public_key, signing_input, signature)
@@ -62,11 +62,11 @@ module JWT
62
62
  def verify_ecdsa(algorithm, public_key, signing_input, signature)
63
63
  key_algorithm = NAMED_CURVES[public_key.group.curve_name]
64
64
  if algorithm != key_algorithm
65
- raise IncorrectAlgorithm.new("payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided")
65
+ fail IncorrectAlgorithm.new("payload algorithm is #{algorithm} but #{key_algorithm} verification key was provided")
66
66
  end
67
67
 
68
68
  digest = OpenSSL::Digest.new(algorithm.sub('ES', 'sha'))
69
- public_key.dsa_verify_asn1(digest.digest(signing_input), signature)
69
+ public_key.dsa_verify_asn1(digest.digest(signing_input), raw_to_asn1(signature, public_key))
70
70
  end
71
71
 
72
72
  def sign_hmac(algorithm, msg, key)
@@ -83,7 +83,7 @@ module JWT
83
83
  end
84
84
 
85
85
  def encoded_header(algorithm='HS256', header_fields={})
86
- header = {'typ' => 'JWT', 'alg' => algorithm}.merge(header_fields)
86
+ header = { 'typ' => 'JWT', 'alg' => algorithm }.merge(header_fields)
87
87
  base64url_encode(encode_json(header))
88
88
  end
89
89
 
@@ -111,8 +111,8 @@ module JWT
111
111
 
112
112
  def raw_segments(jwt, verify=true)
113
113
  segments = jwt.split('.')
114
- required_num_segments = verify ? [3] : [2,3]
115
- raise JWT::DecodeError.new('Not enough or too many segments') unless required_num_segments.include? segments.length
114
+ required_num_segments = verify ? [3] : [2, 3]
115
+ fail JWT::DecodeError.new('Not enough or too many segments') unless required_num_segments.include? segments.length
116
116
  segments
117
117
  end
118
118
 
@@ -131,10 +131,10 @@ module JWT
131
131
  end
132
132
 
133
133
  def decode(jwt, key=nil, verify=true, options={}, &keyfinder)
134
- raise JWT::DecodeError.new('Nil JSON web token') unless jwt
134
+ fail JWT::DecodeError.new('Nil JSON web token') unless jwt
135
135
 
136
136
  header, payload, signature, signing_input = decoded_segments(jwt, verify)
137
- raise JWT::DecodeError.new('Not enough or too many segments') unless header && payload
137
+ fail JWT::DecodeError.new('Not enough or too many segments') unless header && payload
138
138
 
139
139
  default_options = {
140
140
  :verify_expiration => true,
@@ -152,64 +152,60 @@ module JWT
152
152
  if verify
153
153
  algo, key = signature_algorithm_and_key(header, key, &keyfinder)
154
154
  if options[:algorithm] && algo != options[:algorithm]
155
- raise JWT::IncorrectAlgorithm.new('Expected a different algorithm')
155
+ fail JWT::IncorrectAlgorithm.new('Expected a different algorithm')
156
156
  end
157
157
  verify_signature(algo, key, signing_input, signature)
158
158
  end
159
159
 
160
160
  if options[:verify_expiration] && payload.include?('exp')
161
- raise JWT::ExpiredSignature.new('Signature has expired') unless payload['exp'].to_i > (Time.now.to_i - options[:leeway])
161
+ fail JWT::ExpiredSignature.new('Signature has expired') unless payload['exp'].to_i > (Time.now.to_i - options[:leeway])
162
162
  end
163
163
  if options[:verify_not_before] && payload.include?('nbf')
164
- raise JWT::ImmatureSignature.new('Signature nbf has not been reached') unless payload['nbf'].to_i < (Time.now.to_i + options[:leeway])
164
+ fail JWT::ImmatureSignature.new('Signature nbf has not been reached') unless payload['nbf'].to_i < (Time.now.to_i + options[:leeway])
165
165
  end
166
- if options[:verify_iss] && payload.include?('iss')
167
- raise JWT::InvalidIssuerError.new("Invalid issuer. Expected #{options['iss']}, received #{payload['iss']}") unless payload['iss'].to_s == options['iss'].to_s
166
+ if options[:verify_iss] && options['iss']
167
+ fail JWT::InvalidIssuerError.new("Invalid issuer. Expected #{options['iss']}, received #{payload['iss'] || '<none>'}") unless payload['iss'].to_s == options['iss'].to_s
168
168
  end
169
169
  if options[:verify_iat] && payload.include?('iat')
170
- raise JWT::InvalidIatError.new('Invalid iat') unless (payload['iat'].is_a?(Integer) and payload['iat'].to_i <= Time.now.to_i)
170
+ fail JWT::InvalidIatError.new('Invalid iat') unless payload['iat'].is_a?(Integer) && payload['iat'].to_i <= Time.now.to_i
171
171
  end
172
- if options[:verify_aud] && payload.include?('aud')
172
+ if options[:verify_aud] && options['aud']
173
173
  if payload['aud'].is_a?(Array)
174
- raise JWT::InvalidAudError.new('Invalid audience') unless payload['aud'].include?(options['aud'])
174
+ fail JWT::InvalidAudError.new('Invalid audience') unless payload['aud'].include?(options['aud'].to_s)
175
175
  else
176
- raise JWT::InvalidAudError.new("Invalid audience. Expected #{options['aud']}, received #{payload['aud']}") unless payload['aud'].to_s == options['aud'].to_s
176
+ fail JWT::InvalidAudError.new("Invalid audience. Expected #{options['aud']}, received #{payload['aud'] || '<none>'}") unless payload['aud'].to_s == options['aud'].to_s
177
177
  end
178
178
  end
179
179
  if options[:verify_sub] && payload.include?('sub')
180
- raise JWT::InvalidSubError.new("Invalid subject. Expected #{options['sub']}, received #{payload['sub']}") unless payload['sub'].to_s == options['sub'].to_s
180
+ fail JWT::InvalidSubError.new("Invalid subject. Expected #{options['sub']}, received #{payload['sub']}") unless payload['sub'].to_s == options['sub'].to_s
181
181
  end
182
182
  if options[:verify_jti] && payload.include?('jti')
183
- raise JWT::InvalidJtiError.new('need iat for verify jwt id') unless payload.include?('iat')
184
- raise JWT::InvalidJtiError.new('Not a uniq jwt id') unless options['jti'].to_s == Digest::MD5.hexdigest("#{key}:#{payload['iat']}")
183
+ fail JWT::InvalidJtiError.new('need iat for verify jwt id') unless payload.include?('iat')
184
+ fail JWT::InvalidJtiError.new('Not a uniq jwt id') unless options['jti'].to_s == Digest::MD5.hexdigest("#{key}:#{payload['iat']}")
185
185
  end
186
186
 
187
- return payload,header
187
+ [payload, header]
188
188
  end
189
189
 
190
190
  def signature_algorithm_and_key(header, key, &keyfinder)
191
- if keyfinder
192
- key = keyfinder.call(header)
193
- end
191
+ key = keyfinder.call(header) if keyfinder
194
192
  [header['alg'], key]
195
193
  end
196
194
 
197
195
  def verify_signature(algo, key, signing_input, signature)
198
- begin
199
- if ['HS256', 'HS384', 'HS512'].include?(algo)
200
- raise JWT::VerificationError.new('Signature verification failed') unless secure_compare(signature, sign_hmac(algo, signing_input, key))
201
- elsif ['RS256', 'RS384', 'RS512'].include?(algo)
202
- raise JWT::VerificationError.new('Signature verification failed') unless verify_rsa(algo, key, signing_input, signature)
203
- elsif ['ES256', 'ES384', 'ES512'].include?(algo)
204
- raise JWT::VerificationError.new('Signature verification failed') unless verify_ecdsa(algo, key, signing_input, signature)
205
- else
206
- raise JWT::VerificationError.new('Algorithm not supported')
207
- end
208
- rescue OpenSSL::PKey::PKeyError
209
- raise JWT::VerificationError.new('Signature verification failed')
210
- ensure
211
- OpenSSL.errors.clear
196
+ if ['HS256', 'HS384', 'HS512'].include?(algo)
197
+ fail JWT::VerificationError.new('Signature verification failed') unless secure_compare(signature, sign_hmac(algo, signing_input, key))
198
+ elsif ['RS256', 'RS384', 'RS512'].include?(algo)
199
+ fail JWT::VerificationError.new('Signature verification failed') unless verify_rsa(algo, key, signing_input, signature)
200
+ elsif ['ES256', 'ES384', 'ES512'].include?(algo)
201
+ fail JWT::VerificationError.new('Signature verification failed') unless verify_ecdsa(algo, key, signing_input, signature)
202
+ else
203
+ fail JWT::VerificationError.new('Algorithm not supported')
212
204
  end
205
+ rescue OpenSSL::PKey::PKeyError
206
+ raise JWT::VerificationError.new('Signature verification failed')
207
+ ensure
208
+ OpenSSL.errors.clear
213
209
  end
214
210
 
215
211
  # From devise
@@ -223,4 +219,15 @@ module JWT
223
219
  res == 0
224
220
  end
225
221
 
222
+ def raw_to_asn1(signature, private_key)
223
+ byte_size = (private_key.group.degree + 7) / 8
224
+ r = signature[0..(byte_size - 1)]
225
+ s = signature[byte_size..-1]
226
+ OpenSSL::ASN1::Sequence.new([r, s].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
227
+ end
228
+
229
+ def asn1_to_raw(signature, public_key)
230
+ byte_size = (public_key.group.degree + 7) / 8
231
+ OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
232
+ end
226
233
  end
data/lib/jwt/json.rb CHANGED
@@ -1,4 +1,6 @@
1
+ # encoding: utf-8
1
2
  module JWT
3
+ # JSON fallback implementation or ruby 1.8.x
2
4
  module Json
3
5
  if RUBY_VERSION >= '1.9' && !defined?(MultiJson)
4
6
  require 'json'
data/spec/helper.rb CHANGED
@@ -1,2 +1,19 @@
1
+ # encoding: utf-8
1
2
  require 'rspec'
3
+ require 'simplecov'
4
+ require 'simplecov-json'
5
+
6
+ SimpleCov.configure do
7
+ root File.join(File.dirname(__FILE__), '..')
8
+ project_name 'Ruby JWT - Ruby JSON Web Token implementation'
9
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
10
+ SimpleCov::Formatter::HTMLFormatter,
11
+ SimpleCov::Formatter::JSONFormatter
12
+ ]
13
+
14
+ add_filter 'spec'
15
+ end
16
+
17
+ SimpleCov.start if ENV['COVERAGE']
18
+
2
19
  require "#{File.dirname(__FILE__)}/../lib/jwt.rb"
data/spec/jwt_spec.rb CHANGED
@@ -1,8 +1,9 @@
1
+ # encoding: utf-8
1
2
  require 'helper'
2
3
 
3
4
  describe JWT do
4
5
  before do
5
- @payload = {'foo' => 'bar', 'exp' => Time.now.to_i + 1, 'nbf' => Time.now.to_i - 1 }
6
+ @payload = { 'foo' => 'bar', 'exp' => Time.now.to_i + 1, 'nbf' => Time.now.to_i - 1 }
6
7
  end
7
8
 
8
9
  it 'encodes and decodes JWTs' do
@@ -51,7 +52,7 @@ describe JWT do
51
52
 
52
53
  it 'encodes and decodes JWTs with custom header fields' do
53
54
  private_key = OpenSSL::PKey::RSA.generate(512)
54
- jwt = JWT.encode(@payload, private_key, 'RS256', {'kid' => 'default'})
55
+ jwt = JWT.encode(@payload, private_key, 'RS256', 'kid' => 'default')
55
56
  decoded_payload = JWT.decode(jwt) do |header|
56
57
  expect(header['kid']).to eq('default')
57
58
  private_key.public_key
@@ -68,40 +69,65 @@ describe JWT do
68
69
  end
69
70
 
70
71
  it 'decodes valid JWTs' do
71
- example_payload = {'hello' => 'world'}
72
+ example_payload = { 'hello' => 'world' }
72
73
  example_secret = 'secret'
73
74
  example_jwt = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8'
74
75
  decoded_payload = JWT.decode(example_jwt, example_secret)
75
76
  expect(decoded_payload).to include(example_payload)
76
77
  end
77
78
 
79
+ it 'decodes valid ES512 JWTs' do
80
+ example_payload = { 'hello' => 'world' }
81
+ example_jwt = 'eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9.eyJoZWxsbyI6IndvcmxkIn0.AQx1MqdTni6KuzfOoedg2-7NUiwe-b88SWbdmviz40GTwrM0Mybp1i1tVtmTSQ91oEXGXBdtwsN6yalzP9J-sp2YATX_Tv4h-BednbdSvYxZsYnUoZ--ZUdL10t7g8Yt3y9hdY_diOjIptcha6ajX8yzkDGYG42iSe3f5LywSuD6FO5c'
82
+ pubkey_pem = "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAcpkss6wI7PPlxj3t7A1RqMH3nvL4\nL5Tzxze/XeeYZnHqxiX+gle70DlGRMqqOq+PJ6RYX7vK0PJFdiAIXlyPQq0B3KaU\ne86IvFeQSFrJdCc0K8NfiH2G1loIk3fiR+YLqlXk6FAeKtpXJKxR1pCQCAM+vBCs\nmZudf1zCUZ8/4eodlHU=\n-----END PUBLIC KEY-----"
83
+ pubkey = OpenSSL::PKey::EC.new pubkey_pem
84
+ decoded_payload = JWT.decode(example_jwt, pubkey)
85
+ expect(decoded_payload).to include(example_payload)
86
+ end
87
+
78
88
  it 'decodes valid JWTs with iss' do
79
- example_payload = {'hello' => 'world', 'iss' => 'jwtiss'}
89
+ example_payload = { 'hello' => 'world', 'iss' => 'jwtiss' }
80
90
  example_secret = 'secret'
81
91
  example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
82
- decoded_payload = JWT.decode(example_jwt, example_secret, true, {'iss' => 'jwtiss'})
92
+ decoded_payload = JWT.decode(example_jwt, example_secret, true, 'iss' => 'jwtiss')
83
93
  expect(decoded_payload).to include(example_payload)
84
94
  end
85
95
 
86
- it 'raises invalid issuer' do
87
- # example_payload = {'hello' => 'world', 'iss' => 'jwtiss'}
88
- example_payload2 = {'hello' => 'world'}
96
+ context 'issuer claim verifications' do
97
+ it 'raises invalid issuer when "iss" claim does not match' do
98
+ example_secret = 'secret'
89
99
 
90
- example_secret = 'secret'
100
+ example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
101
+ expect { JWT.decode(example_jwt, example_secret, true, :verify_iss => true, 'iss' => 'jwt_iss') }.to raise_error(JWT::InvalidIssuerError, /Expected jwt_iss, received jwtiss/)
102
+ end
91
103
 
92
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
93
- expect{ JWT.decode(example_jwt, example_secret, true, {:verify_iss => true, 'iss' => 'jwt_iss'}) }.to raise_error(JWT::InvalidIssuerError)
104
+ it 'raises invalid issuer when "iss" claim is missing in payload' do
105
+ example_secret = 'secret'
106
+
107
+ example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIn0.bqxXg9VwcbXKoiWtp-osd0WKPX307RjcN7EuXbdq-CE'
108
+ expect { JWT.decode(example_jwt, example_secret, true, :verify_iss => true, 'iss' => 'jwt_iss') }.to raise_error(JWT::InvalidIssuerError, /received <none>/)
109
+ end
110
+
111
+ it 'does not raise invalid issuer when verify_iss is set to false (default option)' do
112
+ example_secret = 'secret'
113
+
114
+ example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
115
+ expect { JWT.decode(example_jwt, example_secret, true, 'iss' => 'jwt_iss') }.not_to raise_error
116
+ end
117
+
118
+ it 'does not raise invalid issuer when correct "iss" is in payload' do
119
+ example_secret = 'secret'
94
120
 
95
- example_jwt2 = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8'
96
- decode_payload2 = JWT.decode(example_jwt2, example_secret, true, {'iss' => 'jwt_iss'})
97
- expect(decode_payload2).to include(example_payload2)
121
+ example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0X2lzcyJ9.mwbyRJJZJR1C5lBt8WOLg0ZMuwP9VGDf5HiQtFhd-eA'
122
+ expect { JWT.decode(example_jwt, example_secret, true, :verify_iss => true, 'iss' => 'jwt_iss') }.not_to raise_error
123
+ end
98
124
  end
99
125
 
100
126
  it 'decodes valid JWTs with iat' do
101
- example_payload = {'hello' => 'world', 'iat' => 1425917209}
127
+ example_payload = { 'hello' => 'world', 'iat' => 1425917209 }
102
128
  example_secret = 'secret'
103
129
  example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5fQ.m4F-Ugo7aLnLunBBO3BeDidyWMx8T9eoJz6FW2rgQhU'
104
- decoded_payload = JWT.decode(example_jwt, example_secret, true, {'iat' => true})
130
+ decoded_payload = JWT.decode(example_jwt, example_secret, true, 'iat' => true)
105
131
  expect(decoded_payload).to include(example_payload)
106
132
  end
107
133
 
@@ -109,14 +135,14 @@ describe JWT do
109
135
  # example_payload = {'hello' => 'world', 'iat' => 'abc'}
110
136
  example_secret = 'secret'
111
137
  example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoiMTQyNTkxNzIwOSJ9.Mn_vk61xWjIhbXFqAB0nFmNkDiCmfzUgl_LaCKRT6S8'
112
- expect{ JWT.decode(example_jwt, example_secret, true, {:verify_iat => true, 'iat' => 1425917209}) }.to raise_error(JWT::InvalidIatError)
138
+ expect { JWT.decode(example_jwt, example_secret, true, :verify_iat => true, 'iat' => 1425917209) }.to raise_error(JWT::InvalidIatError)
113
139
  end
114
140
 
115
141
  it 'decodes valid JWTs with jti' do
116
- example_payload = {'hello' => 'world', 'iat' => 1425917209, 'jti' => Digest::MD5.hexdigest('secret:1425917209')}
142
+ example_payload = { 'hello' => 'world', 'iat' => 1425917209, 'jti' => Digest::MD5.hexdigest('secret:1425917209') }
117
143
  example_secret = 'secret'
118
144
  example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5LCJqdGkiOiI1NWM3NzZlMjFmN2NiZDg3OWMwNmZhYzAxOGRhYzQwMiJ9.ET0hb-VTUOL3M22oG13ofzvGPLMAncbF8rdNDIqo8tg'
119
- decoded_payload = JWT.decode(example_jwt, example_secret, true, {'jti' => Digest::MD5.hexdigest('secret:1425917209')})
145
+ decoded_payload = JWT.decode(example_jwt, example_secret, true, 'jti' => Digest::MD5.hexdigest('secret:1425917209'))
120
146
  expect(decoded_payload).to include(example_payload)
121
147
  end
122
148
 
@@ -124,7 +150,7 @@ describe JWT do
124
150
  # example_payload = {'hello' => 'world', 'iat' => 1425917209, 'jti' => Digest::MD5.hexdigest('secret:1425917209')}
125
151
  example_secret = 'secret'
126
152
  example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5LCJqdGkiOiI1NWM3NzZlMjFmN2NiZDg3OWMwNmZhYzAxOGRhYzQwMiJ9.ET0hb-VTUOL3M22oG13ofzvGPLMAncbF8rdNDIqo8tg'
127
- expect{ JWT.decode(example_jwt, example_secret, true, {:verify_jti => true, 'jti' => Digest::MD5.hexdigest('secret:1425922032')}) }.to raise_error(JWT::InvalidJtiError)
153
+ expect { JWT.decode(example_jwt, example_secret, true, :verify_jti => true, 'jti' => Digest::MD5.hexdigest('secret:1425922032')) }.to raise_error(JWT::InvalidJtiError)
128
154
  # expect{ JWT.decode(example_jwt, example_secret) }.to raise_error(JWT::InvalidJtiError)
129
155
  end
130
156
 
@@ -132,43 +158,46 @@ describe JWT do
132
158
  # example_payload = {'hello' => 'world', 'jti' => Digest::MD5.hexdigest('secret:1425917209')}
133
159
  example_secret = 'secret'
134
160
  example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwianRpIjoiNTVjNzc2ZTIxZjdjYmQ4NzljMDZmYWMwMThkYWM0MDIifQ.n0foJCnCM_-_xUvG_TOmR9mYpL2y0UqZOD_gv33djeE'
135
- expect{ JWT.decode(example_jwt, example_secret, true, {:verify_jti => true, 'jti' => Digest::MD5.hexdigest('secret:1425922032')}) }.to raise_error(JWT::InvalidJtiError)
136
- end
161
+ expect { JWT.decode(example_jwt, example_secret, true, :verify_jti => true, 'jti' => Digest::MD5.hexdigest('secret:1425922032')) }.to raise_error(JWT::InvalidJtiError)
162
+ end
163
+
164
+ context 'aud claim verifications' do
165
+ it 'decodes valid JWTs with aud' do
166
+ example_payload = { 'hello' => 'world', 'aud' => 'url:pnd' }
167
+ example_payload2 = { 'hello' => 'world', 'aud' => ['url:pnd', 'aud:yes'] }
168
+ example_secret = 'secret'
169
+ example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
170
+ example_jwt2 = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjpbInVybDpwbmQiLCJhdWQ6eWVzIl19.qNPNcT4X9B5uI91rIwbW2bIPTsp8wbRYW3jkZkrmqbQ'
171
+ decoded_payload = JWT.decode(example_jwt, example_secret, true, :verify_aud => true, 'aud' => 'url:pnd')
172
+ decoded_payload2 = JWT.decode(example_jwt2, example_secret, true, :verify_aud => true, 'aud' => 'url:pnd')
173
+ expect(decoded_payload).to include(example_payload)
174
+ expect(decoded_payload2).to include(example_payload2)
175
+ end
137
176
 
138
- it 'decodes valid JWTs with aud' do
139
- example_payload = {'hello' => 'world', 'aud' => 'url:pnd'}
140
- example_payload2 = {'hello' => 'world', 'aud' => ['url:pnd', 'aud:yes']}
141
- example_secret = 'secret'
142
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
143
- example_jwt2 = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjpbInVybDpwbmQiLCJhdWQ6eWVzIl19.qNPNcT4X9B5uI91rIwbW2bIPTsp8wbRYW3jkZkrmqbQ'
144
- decoded_payload = JWT.decode(example_jwt, example_secret, true, {'aud' => 'url:pnd'})
145
- decoded_payload2 = JWT.decode(example_jwt2, example_secret, true, {'aud' => 'url:pnd'})
146
- expect(decoded_payload).to include(example_payload)
147
- expect(decoded_payload2).to include(example_payload2)
148
- end
177
+ it 'raises deode exception when aud is invalid' do
178
+ # example_payload = {'hello' => 'world', 'aud' => 'url:pnd'}
179
+ example_secret = 'secret'
180
+ example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
181
+ expect { JWT.decode(example_jwt, example_secret, true, :verify_aud => true, 'aud' => 'wrong:aud') }.to raise_error(JWT::InvalidAudError)
182
+ end
149
183
 
150
- it 'raises deode exception when aud is invalid' do
151
- # example_payload = {'hello' => 'world', 'aud' => 'url:pnd'}
152
- example_secret = 'secret'
153
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
154
- expect{ JWT.decode(example_jwt, example_secret, true, {:verify_aud => true, 'aud' => 'wrong:aud'}) }.to raise_error(JWT::InvalidAudError)
184
+ it 'raises deode exception when aud is missing' do
185
+ # JWT.encode('hello' => 'world', 'secret')
186
+ example_secret = 'secret'
187
+ example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIn0.bqxXg9VwcbXKoiWtp-osd0WKPX307RjcN7EuXbdq-CE'
188
+ expect { JWT.decode(example_jwt, example_secret, true, :verify_aud => true, 'aud' => 'url:pnd') }.to raise_error(JWT::InvalidAudError)
189
+ end
155
190
  end
156
191
 
157
192
  it 'decodes valid JWTs with sub' do
158
- example_payload = {'hello' => 'world', 'sub' => 'subject'}
193
+ example_payload = { 'hello' => 'world', 'sub' => 'subject' }
159
194
  example_secret = 'secret'
160
195
  example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwic3ViIjoic3ViamVjdCJ9.QUnNVZm4SPB4vP2zY9m1LoUSOx-5oGXBhj7R89D_UtA'
161
- decoded_payload = JWT.decode(example_jwt, example_secret, true, {'sub' => 'subject'})
196
+ decoded_payload = JWT.decode(example_jwt, example_secret, true, 'sub' => 'subject')
162
197
  expect(decoded_payload).to include(example_payload)
163
198
  end
164
199
 
165
- it 'raise decode exception when the sub is invalid' do
166
- # example_payload = {'hello' => 'world', 'sub' => 'subject'}
167
- # TODO: Test not working
168
- example_secret = 'secret'
169
- example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwic3ViIjoic3ViamVjdCJ9.QUnNVZm4SPB4vP2zY9m1LoUSOx-5oGXBhj7R89D_UtA'
170
- # expect{ JWT.decode(example_jwt, example_secret, true, {:verify_iss => true, 'iss' => 'subject'}) }.to raise_error(JWT::InvalidSubError)
171
- end
200
+ it 'raise decode exception when the sub is invalid'
172
201
 
173
202
  it 'raises decode exception when the token is invalid' do
174
203
  example_secret = 'secret'
@@ -312,7 +341,7 @@ describe JWT do
312
341
  expired_payload['exp'] = Time.now.to_i - 1
313
342
  secret = 'secret'
314
343
  jwt = JWT.encode(expired_payload, secret)
315
- decoded_payload = JWT.decode(jwt, secret, true, {:verify_expiration => false})
344
+ decoded_payload = JWT.decode(jwt, secret, true, :verify_expiration => false)
316
345
  expect(decoded_payload).to include(expired_payload)
317
346
  end
318
347
 
@@ -321,7 +350,7 @@ describe JWT do
321
350
  expired_payload['exp'] = Time.now.to_i - 2
322
351
  secret = 'secret'
323
352
  jwt = JWT.encode(expired_payload, secret)
324
- decoded_payload = JWT.decode(jwt, secret, true, {:leeway => 3})
353
+ decoded_payload = JWT.decode(jwt, secret, true, :leeway => 3)
325
354
  expect(decoded_payload).to include(expired_payload)
326
355
  end
327
356
 
@@ -337,7 +366,7 @@ describe JWT do
337
366
  mature_payload = @payload.clone
338
367
  secret = 'secret'
339
368
  jwt = JWT.encode(mature_payload, secret)
340
- decoded_payload = JWT.decode(jwt, secret, true, {:verify_expiration => false})
369
+ decoded_payload = JWT.decode(jwt, secret, true, :verify_expiration => false)
341
370
  expect(decoded_payload).to include(mature_payload)
342
371
  end
343
372
 
@@ -354,7 +383,7 @@ describe JWT do
354
383
  immature_payload['nbf'] = Time.now.to_i + 2
355
384
  secret = 'secret'
356
385
  jwt = JWT.encode(immature_payload, secret)
357
- decoded_payload = JWT.decode(jwt, secret, true, {:verify_not_before => false})
386
+ decoded_payload = JWT.decode(jwt, secret, true, :verify_not_before => false)
358
387
  expect(decoded_payload).to include(immature_payload)
359
388
  end
360
389
 
@@ -363,7 +392,7 @@ describe JWT do
363
392
  immature_payload['nbf'] = Time.now.to_i - 2
364
393
  secret = 'secret'
365
394
  jwt = JWT.encode(immature_payload, secret)
366
- decoded_payload = JWT.decode(jwt, secret, true, {:leeway => 3})
395
+ decoded_payload = JWT.decode(jwt, secret, true, :leeway => 3)
367
396
  expect(decoded_payload).to include(immature_payload)
368
397
  end
369
398
 
@@ -402,13 +431,13 @@ xwIDAQAB
402
431
  -----END PUBLIC KEY-----
403
432
  PUBKEY
404
433
  jwt = (
405
- 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY' +
406
- 'XVkIjoiMTA2MDM1Nzg5MTY4OC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSI' +
407
- 'sImNpZCI6IjEwNjAzNTc4OTE2ODguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb' +
408
- '20iLCJpZCI6IjExNjQ1MjgyNDMwOTg1Njc4MjE2MyIsInRva2VuX2hhc2giOiJ' +
409
- '0Z2hEOUo4bjhWME4ydmN3NmVNaWpnIiwiaWF0IjoxMzIwNjcwOTc4LCJleHAiO' +
410
- 'jEzMjA2NzQ4Nzh9.D8x_wirkxDElqKdJBcsIws3Ogesk38okz6MN7zqC7nEAA7' +
411
- 'wcy1PxsROY1fmBvXSer0IQesAqOW-rPOCNReSn-eY8d53ph1x2HAF-AzEi3GOl' +
434
+ 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiY' \
435
+ 'XVkIjoiMTA2MDM1Nzg5MTY4OC5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSI' \
436
+ 'sImNpZCI6IjEwNjAzNTc4OTE2ODguYXBwcy5nb29nbGV1c2VyY29udGVudC5jb' \
437
+ '20iLCJpZCI6IjExNjQ1MjgyNDMwOTg1Njc4MjE2MyIsInRva2VuX2hhc2giOiJ' \
438
+ '0Z2hEOUo4bjhWME4ydmN3NmVNaWpnIiwiaWF0IjoxMzIwNjcwOTc4LCJleHAiO' \
439
+ 'jEzMjA2NzQ4Nzh9.D8x_wirkxDElqKdJBcsIws3Ogesk38okz6MN7zqC7nEAA7' \
440
+ 'wcy1PxsROY1fmBvXSer0IQesAqOW-rPOCNReSn-eY8d53ph1x2HAF-AzEi3GOl' \
412
441
  '6hFycH8wj7Su6JqqyEbIVLxE7q7DkAZGaMPkxbTHs1EhSd5_oaKQ6O4xO3ZnnT4'
413
442
  )
414
443
  expect { JWT.decode(jwt, pubkey, true) }.to raise_error(JWT::DecodeError)
@@ -427,7 +456,7 @@ PUBKEY
427
456
  jwt = JWT.encode(@payload, secret)
428
457
  decoded_segments = JWT.decoded_segments(jwt)
429
458
  expect(decoded_segments.size).to eq(4)
430
- expect(decoded_segments[0]).to eq({'typ' => 'JWT', 'alg' => 'HS256'})
459
+ expect(decoded_segments[0]).to eq('typ' => 'JWT', 'alg' => 'HS256')
431
460
  expect(decoded_segments[1]).to eq(@payload)
432
461
  end
433
462
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Lindsay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-09 00:00:00.000000000 Z
11
+ date: 2015-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: echoe