Skip to content

Commit

Permalink
Merge pull request #62 from Ruby-Study/master
Browse files Browse the repository at this point in the history
Add  iat, aud, sub, jti  support for ruby-jwt
  • Loading branch information
excpt committed Mar 9, 2015
2 parents 93f2977 + da46e95 commit 094f5ea
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
26 changes: 26 additions & 0 deletions lib/jwt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ class VerificationError < DecodeError; end
class ExpiredSignature < DecodeError; end
class ImmatureSignature < DecodeError; end
class InvalidIssuerError < DecodeError; end
class InvalidIatError < DecodeError; end
class InvalidAudError < DecodeError; end
class InvalidSubError < DecodeError; end
class InvalidJtiError < DecodeError; end
extend JWT::Json

module_function
Expand Down Expand Up @@ -107,6 +111,10 @@ def decode(jwt, key=nil, verify=true, options={}, &keyfinder)
:verify_expiration => true,
:verify_not_before => true,
:verify_iss => true,
:verify_iat => true,
:verify_jti => true,
:verify_aud => true,
:verify_sub => true,
:leeway => 0
}

Expand All @@ -126,6 +134,24 @@ def decode(jwt, key=nil, verify=true, options={}, &keyfinder)
if options[:verify_iss] && payload.include?('iss')
raise JWT::InvalidIssuerError.new("Invalid issuer") unless payload['iss'].to_s == options[:iss].to_s
end
if options[:verify_iat] && payload.include?('iat')
raise JWT::InvalidIatError.new("Invalid iat") unless (payload['iat'].is_a?(Integer) and payload['iat'].to_i <= Time.now.to_i)
end
if options[:verify_aud] && payload.include?('aud')
if payload['aud'].is_a?(Array)
raise JWT::InvalidAudError.new("Invalid audience") unless payload['aud'].include?(options[:aud])
else
raise JWT::InvalidAudError.new("Invalid audience") unless payload['aud'].to_s == options[:aud].to_s
end
end
if options[:verify_sub] && payload.include?('sub')
raise JWT::InvalidSubError.new("Invalid subject") unless payload['sub'].to_s == options[:sub].to_s
end
if options[:verify_jti] && payload.include?('jti')
raise JWT::InvalidJtiError.new("need iat for verify jwt id") unless payload.include?('iat')
raise JWT::InvalidJtiError.new("Not a uniq jwt id") unless options[:jti].to_s == Digest::MD5.hexdigest("#{key}:#{payload['iat']}")
end

return payload,header
end

Expand Down
71 changes: 71 additions & 0 deletions spec/jwt_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,77 @@
expect(decode_payload2).to include(example_payload2)
end

it "decodes valid JWTs with iat" do
example_payload = {"hello" => "world", "iat" => 1425917209}
example_secret = 'secret'
example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5fQ.m4F-Ugo7aLnLunBBO3BeDidyWMx8T9eoJz6FW2rgQhU'
decoded_payload = JWT.decode(example_jwt, example_secret, true, {iat: true})
expect(decoded_payload).to include(example_payload)
end

it "raises decode exception when iat is invalid" do
example_payload = {"hello" => "world", "iat" => "abc"}
example_secret = 'secret'
example_jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoiMTQyNTkxNzIwOSJ9.Mn_vk61xWjIhbXFqAB0nFmNkDiCmfzUgl_LaCKRT6S8"
expect{ JWT.decode(example_jwt, example_secret, true, {iat: 1425917209}) }.to raise_error(JWT::InvalidIatError)
end

it "decodes valid JWTs with jti" do
example_payload = {"hello" => "world", "iat" => 1425917209, "jti" => Digest::MD5.hexdigest("secret:1425917209")}
example_secret = 'secret'
example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5LCJqdGkiOiI1NWM3NzZlMjFmN2NiZDg3OWMwNmZhYzAxOGRhYzQwMiJ9.ET0hb-VTUOL3M22oG13ofzvGPLMAncbF8rdNDIqo8tg'
decoded_payload = JWT.decode(example_jwt, example_secret, true, {jti: Digest::MD5.hexdigest("secret:1425917209")})
expect(decoded_payload).to include(example_payload)
end

it "raises decode exception when jti is invalid" do
example_payload = {"hello" => "world", "iat" => 1425917209, "jti" => Digest::MD5.hexdigest("secret:1425917209")}
example_secret = 'secret'
example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5LCJqdGkiOiI1NWM3NzZlMjFmN2NiZDg3OWMwNmZhYzAxOGRhYzQwMiJ9.ET0hb-VTUOL3M22oG13ofzvGPLMAncbF8rdNDIqo8tg'
expect{ JWT.decode(example_jwt, example_secret, true, {jti: Digest::MD5.hexdigest("secret:1425922032")}) }.to raise_error(JWT::InvalidJtiError)
expect{ JWT.decode(example_jwt, example_secret) }.to raise_error(JWT::InvalidJtiError)
end

it "raises decode exception when jti without iat" do
example_payload = {"hello" => "world", "jti" => Digest::MD5.hexdigest("secret:1425917209")}
example_secret = 'secret'
example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwianRpIjoiNTVjNzc2ZTIxZjdjYmQ4NzljMDZmYWMwMThkYWM0MDIifQ.n0foJCnCM_-_xUvG_TOmR9mYpL2y0UqZOD_gv33djeE'
expect{ JWT.decode(example_jwt, example_secret, true, {jti: Digest::MD5.hexdigest("secret:1425922032")}) }.to raise_error(JWT::InvalidJtiError)
end

it "decodes valid JWTs with aud" do
example_payload = {"hello" => "world", "aud" => "url:pnd"}
example_payload2 = {"hello" => "world", "aud" => ["url:pnd", "aud:yes"]}
example_secret = 'secret'
example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
example_jwt2 = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjpbInVybDpwbmQiLCJhdWQ6eWVzIl19.qNPNcT4X9B5uI91rIwbW2bIPTsp8wbRYW3jkZkrmqbQ"
decoded_payload = JWT.decode(example_jwt, example_secret, true, {aud: "url:pnd"})
decoded_payload2 = JWT.decode(example_jwt2, example_secret, true, {aud: "url:pnd"})
expect(decoded_payload).to include(example_payload)
expect(decoded_payload2).to include(example_payload2)
end

it "raises deode exception when aud is invalid" do
example_payload = {"hello" => "world", "aud" => "url:pnd"}
example_secret = 'secret'
example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
expect{ JWT.decode(example_jwt, example_secret, true, {aud: "wrong:aud"}) }.to raise_error(JWT::InvalidAudError)
end

it "decodes valid JWTs with sub" do
example_payload = {"hello" => "world", "sub" => 'subject'}
example_secret = 'secret'
example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwic3ViIjoic3ViamVjdCJ9.QUnNVZm4SPB4vP2zY9m1LoUSOx-5oGXBhj7R89D_UtA'
decoded_payload = JWT.decode(example_jwt, example_secret, true, {sub: 'subject'})
expect(decoded_payload).to include(example_payload)
end

it "raise decode exception when the sub is invalid" do
example_payload = {"hello" => "world", "sub" => 'subject'}
example_secret = 'secret'
example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwic3ViIjoic3ViamVjdCJ9.QUnNVZm4SPB4vP2zY9m1LoUSOx-5oGXBhj7R89D_UtA'
expect{ JWT.decode(example_jwt, example_secret, true, {iss: 'subject'}) }.to raise_error(JWT::InvalidSubError)
end

it "raises decode exception when the token is invalid" do
example_secret = 'secret'
Expand Down

0 comments on commit 094f5ea

Please sign in to comment.