jwt 1.3.0 → 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.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/jwt.gemspec +3 -3
- data/lib/jwt.rb +34 -2
- data/spec/helper.rb +0 -3
- data/spec/jwt_spec.rb +160 -66
- 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: 22e5c1eafdf6a7e80397bbca142c3bff69524b21
         | 
| 4 | 
            +
              data.tar.gz: e7acda6c7609412c393a5ebb29e575cb82618f9f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: f897824dd5f6ccc196f16c9944914c14ca0d476d9bc030bc8872ad7e2c5234a3db907ee35b780715689549fe397a4e76521b0e3d06d37f2b06d890cbcf855633
         | 
| 7 | 
            +
              data.tar.gz: aec0e48a68cee3b5694d97f47aa0b3721ac2eee8a82b038c172c884d3ccfc1ade1728a4d4bf92d7cedd2d8bca9273cb180a14fb4ee306b01e981b2e752341515
         | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/jwt.gemspec
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            -
            # stub: jwt 1. | 
| 2 | 
            +
            # stub: jwt 1.4.0 ruby lib
         | 
| 3 3 |  | 
| 4 4 | 
             
            Gem::Specification.new do |s|
         | 
| 5 5 | 
             
              s.name = "jwt"
         | 
| 6 | 
            -
              s.version = "1. | 
| 6 | 
            +
              s.version = "1.4.0"
         | 
| 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- | 
| 11 | 
            +
              s.date = "2015-03-10"
         | 
| 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
    
    | @@ -11,8 +11,13 @@ require "jwt/json" | |
| 11 11 | 
             
            module JWT
         | 
| 12 12 | 
             
              class DecodeError < StandardError; end
         | 
| 13 13 | 
             
              class VerificationError < DecodeError; end
         | 
| 14 | 
            -
              class ExpiredSignature <  | 
| 15 | 
            -
              class ImmatureSignature <  | 
| 14 | 
            +
              class ExpiredSignature < DecodeError; end
         | 
| 15 | 
            +
              class ImmatureSignature < DecodeError; end
         | 
| 16 | 
            +
              class InvalidIssuerError < DecodeError; end
         | 
| 17 | 
            +
              class InvalidIatError < DecodeError; end
         | 
| 18 | 
            +
              class InvalidAudError < DecodeError; end
         | 
| 19 | 
            +
              class InvalidSubError < DecodeError; end
         | 
| 20 | 
            +
              class InvalidJtiError < DecodeError; end
         | 
| 16 21 | 
             
              extend JWT::Json
         | 
| 17 22 |  | 
| 18 23 | 
             
              module_function
         | 
| @@ -105,8 +110,14 @@ module JWT | |
| 105 110 | 
             
                default_options = {
         | 
| 106 111 | 
             
                  :verify_expiration => true,
         | 
| 107 112 | 
             
                  :verify_not_before => true,
         | 
| 113 | 
            +
                  :verify_iss => true,
         | 
| 114 | 
            +
                  :verify_iat => true,
         | 
| 115 | 
            +
                  :verify_jti => true,
         | 
| 116 | 
            +
                  :verify_aud => true,
         | 
| 117 | 
            +
                  :verify_sub => true,
         | 
| 108 118 | 
             
                  :leeway => 0
         | 
| 109 119 | 
             
                }
         | 
| 120 | 
            +
             | 
| 110 121 | 
             
                options = default_options.merge(options)
         | 
| 111 122 |  | 
| 112 123 | 
             
                if verify
         | 
| @@ -120,6 +131,27 @@ module JWT | |
| 120 131 | 
             
                if options[:verify_not_before] && payload.include?('nbf')
         | 
| 121 132 | 
             
                  raise JWT::ImmatureSignature.new("Signature nbf has not been reached") unless payload['nbf'].to_i < (Time.now.to_i + options[:leeway])
         | 
| 122 133 | 
             
                end
         | 
| 134 | 
            +
                if options[:verify_iss] && payload.include?('iss')
         | 
| 135 | 
            +
                  raise JWT::InvalidIssuerError.new("Invalid issuer") unless payload['iss'].to_s == options['iss'].to_s
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
                if options[:verify_iat] && payload.include?('iat')
         | 
| 138 | 
            +
                  raise JWT::InvalidIatError.new("Invalid iat") unless (payload['iat'].is_a?(Integer) and payload['iat'].to_i <= Time.now.to_i)
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
                if options[:verify_aud] && payload.include?('aud')
         | 
| 141 | 
            +
                  if payload['aud'].is_a?(Array)
         | 
| 142 | 
            +
                    raise JWT::InvalidAudError.new("Invalid audience") unless payload['aud'].include?(options['aud'])
         | 
| 143 | 
            +
                  else
         | 
| 144 | 
            +
                    raise JWT::InvalidAudError.new("Invalid audience") unless payload['aud'].to_s == options['aud'].to_s
         | 
| 145 | 
            +
                  end
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
                if options[:verify_sub] && payload.include?('sub')
         | 
| 148 | 
            +
                  raise JWT::InvalidSubError.new("Invalid subject") unless payload['sub'].to_s == options['sub'].to_s
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
                if options[:verify_jti] && payload.include?('jti')
         | 
| 151 | 
            +
                  raise JWT::InvalidJtiError.new("need iat for verify jwt id") unless payload.include?('iat')
         | 
| 152 | 
            +
                  raise JWT::InvalidJtiError.new("Not a uniq jwt id") unless options['jti'].to_s == Digest::MD5.hexdigest("#{key}:#{payload['iat']}")
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 123 155 | 
             
                return payload,header
         | 
| 124 156 | 
             
              end
         | 
| 125 157 |  | 
    
        data/spec/helper.rb
    CHANGED
    
    
    
        data/spec/jwt_spec.rb
    CHANGED
    
    | @@ -2,81 +2,175 @@ require 'helper' | |
| 2 2 |  | 
| 3 3 | 
             
            describe JWT do
         | 
| 4 4 | 
             
              before do
         | 
| 5 | 
            -
                @payload = { | 
| 5 | 
            +
                @payload = {'foo' => 'bar', 'exp' => Time.now.to_i + 1, 'nbf' => Time.now.to_i - 1 }
         | 
| 6 6 | 
             
              end
         | 
| 7 7 |  | 
| 8 | 
            -
              it  | 
| 9 | 
            -
                secret =  | 
| 8 | 
            +
              it 'encodes and decodes JWTs' do
         | 
| 9 | 
            +
                secret = 'secret'
         | 
| 10 10 | 
             
                jwt = JWT.encode(@payload, secret)
         | 
| 11 11 | 
             
                decoded_payload = JWT.decode(jwt, secret)
         | 
| 12 12 | 
             
                expect(decoded_payload).to include(@payload)
         | 
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 | 
            -
              it  | 
| 15 | 
            +
              it 'encodes and decodes JWTs for RSA signatures' do
         | 
| 16 16 | 
             
                private_key = OpenSSL::PKey::RSA.generate(512)
         | 
| 17 | 
            -
                jwt = JWT.encode(@payload, private_key,  | 
| 17 | 
            +
                jwt = JWT.encode(@payload, private_key, 'RS256')
         | 
| 18 18 | 
             
                decoded_payload = JWT.decode(jwt, private_key.public_key)
         | 
| 19 19 | 
             
                expect(decoded_payload).to include(@payload)
         | 
| 20 20 | 
             
              end
         | 
| 21 21 |  | 
| 22 | 
            -
              it  | 
| 22 | 
            +
              it 'encodes and decodes JWTs with custom header fields' do
         | 
| 23 23 | 
             
                private_key = OpenSSL::PKey::RSA.generate(512)
         | 
| 24 | 
            -
                jwt = JWT.encode(@payload, private_key,  | 
| 24 | 
            +
                jwt = JWT.encode(@payload, private_key, 'RS256', {'kid' => 'default'})
         | 
| 25 25 | 
             
                decoded_payload = JWT.decode(jwt) do |header|
         | 
| 26 | 
            -
                  expect(header[ | 
| 26 | 
            +
                  expect(header['kid']).to eq('default')
         | 
| 27 27 | 
             
                  private_key.public_key
         | 
| 28 28 | 
             
                end
         | 
| 29 29 | 
             
                expect(decoded_payload).to include(@payload)
         | 
| 30 30 | 
             
              end
         | 
| 31 31 |  | 
| 32 | 
            -
              it  | 
| 33 | 
            -
                example_payload = { | 
| 32 | 
            +
              it 'decodes valid JWTs' do
         | 
| 33 | 
            +
                example_payload = {'hello' => 'world'}
         | 
| 34 34 | 
             
                example_secret = 'secret'
         | 
| 35 35 | 
             
                example_jwt = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8'
         | 
| 36 36 | 
             
                decoded_payload = JWT.decode(example_jwt, example_secret)
         | 
| 37 37 | 
             
                expect(decoded_payload).to include(example_payload)
         | 
| 38 38 | 
             
              end
         | 
| 39 39 |  | 
| 40 | 
            -
              it  | 
| 40 | 
            +
              it 'decodes valid JWTs with iss' do
         | 
| 41 | 
            +
                example_payload = {'hello' => 'world', 'iss' => 'jwtiss'}
         | 
| 42 | 
            +
                example_secret = 'secret'
         | 
| 43 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
         | 
| 44 | 
            +
                decoded_payload = JWT.decode(example_jwt, example_secret, true, {'iss' => 'jwtiss'})
         | 
| 45 | 
            +
                expect(decoded_payload).to include(example_payload)
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              it 'raises invalid issuer' do
         | 
| 49 | 
            +
                # example_payload = {'hello' => 'world', 'iss' => 'jwtiss'}
         | 
| 50 | 
            +
                example_payload2 = {'hello' => 'world'}
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                example_secret = 'secret'
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaXNzIjoiand0aXNzIn0.nTZkyYfpGUyKULaj45lXw_1gXXjHvGW4h5V7okHdUqQ'
         | 
| 55 | 
            +
                expect{ JWT.decode(example_jwt, example_secret, true, {'iss' => 'jwt_iss'}) }.to raise_error(JWT::InvalidIssuerError)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                example_jwt2 = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8'
         | 
| 58 | 
            +
                decode_payload2 = JWT.decode(example_jwt2, example_secret, true, {'iss' => 'jwt_iss'})
         | 
| 59 | 
            +
                expect(decode_payload2).to include(example_payload2)
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              it 'decodes valid JWTs with iat' do
         | 
| 63 | 
            +
                example_payload = {'hello' => 'world', 'iat' => 1425917209}
         | 
| 64 | 
            +
                example_secret = 'secret'
         | 
| 65 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5fQ.m4F-Ugo7aLnLunBBO3BeDidyWMx8T9eoJz6FW2rgQhU'
         | 
| 66 | 
            +
                decoded_payload = JWT.decode(example_jwt, example_secret, true, {'iat' => true})
         | 
| 67 | 
            +
                expect(decoded_payload).to include(example_payload)
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              it 'raises decode exception when iat is invalid' do
         | 
| 71 | 
            +
                # example_payload = {'hello' => 'world', 'iat' => 'abc'}
         | 
| 72 | 
            +
                example_secret = 'secret'
         | 
| 73 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoiMTQyNTkxNzIwOSJ9.Mn_vk61xWjIhbXFqAB0nFmNkDiCmfzUgl_LaCKRT6S8'
         | 
| 74 | 
            +
                expect{ JWT.decode(example_jwt, example_secret, true, {'iat' => 1425917209}) }.to raise_error(JWT::InvalidIatError)
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              it 'decodes valid JWTs with jti' do
         | 
| 78 | 
            +
                example_payload = {'hello' => 'world', 'iat' => 1425917209, 'jti' => Digest::MD5.hexdigest('secret:1425917209')}
         | 
| 79 | 
            +
                example_secret = 'secret'
         | 
| 80 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5LCJqdGkiOiI1NWM3NzZlMjFmN2NiZDg3OWMwNmZhYzAxOGRhYzQwMiJ9.ET0hb-VTUOL3M22oG13ofzvGPLMAncbF8rdNDIqo8tg'
         | 
| 81 | 
            +
                decoded_payload = JWT.decode(example_jwt, example_secret, true, {'jti' => Digest::MD5.hexdigest('secret:1425917209')})
         | 
| 82 | 
            +
                expect(decoded_payload).to include(example_payload)
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              it 'raises decode exception when jti is invalid' do
         | 
| 86 | 
            +
                # example_payload = {'hello' => 'world', 'iat' => 1425917209, 'jti' => Digest::MD5.hexdigest('secret:1425917209')}
         | 
| 87 | 
            +
                example_secret = 'secret'
         | 
| 88 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiaWF0IjoxNDI1OTE3MjA5LCJqdGkiOiI1NWM3NzZlMjFmN2NiZDg3OWMwNmZhYzAxOGRhYzQwMiJ9.ET0hb-VTUOL3M22oG13ofzvGPLMAncbF8rdNDIqo8tg'
         | 
| 89 | 
            +
                expect{ JWT.decode(example_jwt, example_secret, true, {'jti' => Digest::MD5.hexdigest('secret:1425922032')}) }.to raise_error(JWT::InvalidJtiError)
         | 
| 90 | 
            +
                expect{ JWT.decode(example_jwt, example_secret) }.to raise_error(JWT::InvalidJtiError)
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
              it 'raises decode exception when jti without iat' do
         | 
| 94 | 
            +
                # example_payload = {'hello' => 'world', 'jti' => Digest::MD5.hexdigest('secret:1425917209')}
         | 
| 95 | 
            +
                example_secret = 'secret'
         | 
| 96 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwianRpIjoiNTVjNzc2ZTIxZjdjYmQ4NzljMDZmYWMwMThkYWM0MDIifQ.n0foJCnCM_-_xUvG_TOmR9mYpL2y0UqZOD_gv33djeE'
         | 
| 97 | 
            +
                expect{ JWT.decode(example_jwt, example_secret, true, {'jti' => Digest::MD5.hexdigest('secret:1425922032')}) }.to raise_error(JWT::InvalidJtiError)
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              it 'decodes valid JWTs with aud' do
         | 
| 101 | 
            +
                example_payload = {'hello' => 'world', 'aud' => 'url:pnd'}
         | 
| 102 | 
            +
                example_payload2 = {'hello' => 'world', 'aud' => ['url:pnd', 'aud:yes']}
         | 
| 103 | 
            +
                example_secret = 'secret'
         | 
| 104 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
         | 
| 105 | 
            +
                example_jwt2 = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjpbInVybDpwbmQiLCJhdWQ6eWVzIl19.qNPNcT4X9B5uI91rIwbW2bIPTsp8wbRYW3jkZkrmqbQ'
         | 
| 106 | 
            +
                decoded_payload = JWT.decode(example_jwt, example_secret, true, {'aud' => 'url:pnd'})
         | 
| 107 | 
            +
                decoded_payload2 = JWT.decode(example_jwt2, example_secret, true, {'aud' => 'url:pnd'})
         | 
| 108 | 
            +
                expect(decoded_payload).to include(example_payload)
         | 
| 109 | 
            +
                expect(decoded_payload2).to include(example_payload2)
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
              it 'raises deode exception when aud is invalid' do
         | 
| 113 | 
            +
                # example_payload = {'hello' => 'world', 'aud' => 'url:pnd'}
         | 
| 114 | 
            +
                example_secret = 'secret'
         | 
| 115 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiYXVkIjoidXJsOnBuZCJ9._gT5veUtNiZD7wLEC6Gd0-nkQV3cl1z8G0zXq8qcd-8'
         | 
| 116 | 
            +
                expect{ JWT.decode(example_jwt, example_secret, true, {'aud' => 'wrong:aud'}) }.to raise_error(JWT::InvalidAudError)
         | 
| 117 | 
            +
              end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
              it 'decodes valid JWTs with sub' do
         | 
| 120 | 
            +
                example_payload = {'hello' => 'world', 'sub' => 'subject'}
         | 
| 121 | 
            +
                example_secret = 'secret'
         | 
| 122 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwic3ViIjoic3ViamVjdCJ9.QUnNVZm4SPB4vP2zY9m1LoUSOx-5oGXBhj7R89D_UtA'
         | 
| 123 | 
            +
                decoded_payload = JWT.decode(example_jwt, example_secret, true, {'sub' => 'subject'})
         | 
| 124 | 
            +
                expect(decoded_payload).to include(example_payload)
         | 
| 125 | 
            +
              end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
              it 'raise decode exception when the sub is invalid' do
         | 
| 128 | 
            +
                # example_payload = {'hello' => 'world', 'sub' => 'subject'}
         | 
| 129 | 
            +
                example_secret = 'secret'
         | 
| 130 | 
            +
                example_jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwic3ViIjoic3ViamVjdCJ9.QUnNVZm4SPB4vP2zY9m1LoUSOx-5oGXBhj7R89D_UtA'
         | 
| 131 | 
            +
                expect{ JWT.decode(example_jwt, example_secret, true, {'iss' => 'subject'}) }.to raise_error(JWT::InvalidSubError)
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
              it 'raises decode exception when the token is invalid' do
         | 
| 41 135 | 
             
                example_secret = 'secret'
         | 
| 42 136 | 
             
                # Same as above exmaple with some random bytes replaced
         | 
| 43 137 | 
             
                example_jwt = 'eyJhbGciOiAiSFMyNTYiLCAidHiMomlwIjogIkJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.tvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8'
         | 
| 44 138 | 
             
                expect { JWT.decode(example_jwt, example_secret) }.to raise_error(JWT::DecodeError)
         | 
| 45 139 | 
             
              end
         | 
| 46 140 |  | 
| 47 | 
            -
              it  | 
| 141 | 
            +
              it 'raises verification exception with wrong hmac key' do
         | 
| 48 142 | 
             
                right_secret = 'foo'
         | 
| 49 143 | 
             
                bad_secret = 'bar'
         | 
| 50 | 
            -
                jwt_message = JWT.encode(@payload, right_secret,  | 
| 144 | 
            +
                jwt_message = JWT.encode(@payload, right_secret, 'HS256')
         | 
| 51 145 | 
             
                expect { JWT.decode(jwt_message, bad_secret) }.to raise_error(JWT::VerificationError)
         | 
| 52 146 | 
             
              end
         | 
| 53 147 |  | 
| 54 | 
            -
              it  | 
| 148 | 
            +
              it 'raises verification exception with wrong rsa key' do
         | 
| 55 149 | 
             
                right_private_key = OpenSSL::PKey::RSA.generate(512)
         | 
| 56 150 | 
             
                bad_private_key = OpenSSL::PKey::RSA.generate(512)
         | 
| 57 | 
            -
                jwt = JWT.encode(@payload, right_private_key,  | 
| 151 | 
            +
                jwt = JWT.encode(@payload, right_private_key, 'RS256')
         | 
| 58 152 | 
             
                expect { JWT.decode(jwt, bad_private_key.public_key) }.to raise_error(JWT::VerificationError)
         | 
| 59 153 | 
             
              end
         | 
| 60 154 |  | 
| 61 | 
            -
              it  | 
| 155 | 
            +
              it 'raises decode exception with invalid signature' do
         | 
| 62 156 | 
             
                example_secret = 'secret'
         | 
| 63 157 | 
             
                example_jwt = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.'
         | 
| 64 158 | 
             
                expect { JWT.decode(example_jwt, example_secret) }.to raise_error(JWT::DecodeError)
         | 
| 65 159 | 
             
              end
         | 
| 66 160 |  | 
| 67 | 
            -
              it  | 
| 68 | 
            -
                expect { JWT.decode( | 
| 161 | 
            +
              it 'raises decode exception with nonexistent header' do
         | 
| 162 | 
            +
                expect { JWT.decode('..stuff') }.to raise_error(JWT::DecodeError)
         | 
| 69 163 | 
             
              end
         | 
| 70 164 |  | 
| 71 | 
            -
              it  | 
| 72 | 
            -
                expect { JWT.decode( | 
| 165 | 
            +
              it 'raises decode exception with nonexistent payload' do
         | 
| 166 | 
            +
                expect { JWT.decode('eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9..stuff') }.to raise_error(JWT::DecodeError)
         | 
| 73 167 | 
             
              end
         | 
| 74 168 |  | 
| 75 | 
            -
              it  | 
| 169 | 
            +
              it 'raises decode exception with nil jwt' do
         | 
| 76 170 | 
             
                expect { JWT.decode(nil) }.to raise_error(JWT::DecodeError)
         | 
| 77 171 | 
             
              end
         | 
| 78 172 |  | 
| 79 | 
            -
              it  | 
| 173 | 
            +
              it 'allows decoding without key' do
         | 
| 80 174 | 
             
                right_secret = 'foo'
         | 
| 81 175 | 
             
                bad_secret = 'bar'
         | 
| 82 176 | 
             
                jwt = JWT.encode(@payload, right_secret)
         | 
| @@ -84,35 +178,35 @@ describe JWT do | |
| 84 178 | 
             
                expect(decoded_payload).to include(@payload)
         | 
| 85 179 | 
             
              end
         | 
| 86 180 |  | 
| 87 | 
            -
              it  | 
| 181 | 
            +
              it 'checks the key when verify is truthy' do
         | 
| 88 182 | 
             
                right_secret = 'foo'
         | 
| 89 183 | 
             
                bad_secret = 'bar'
         | 
| 90 184 | 
             
                jwt = JWT.encode(@payload, right_secret)
         | 
| 91 | 
            -
                verify =  | 
| 185 | 
            +
                verify = 'yes' =~ /^y/i
         | 
| 92 186 | 
             
                expect { JWT.decode(jwt, bad_secret, verify) }.to raise_error(JWT::DecodeError)
         | 
| 93 187 | 
             
              end
         | 
| 94 188 |  | 
| 95 | 
            -
              it  | 
| 96 | 
            -
                expect { JWT.encode(@payload,  | 
| 189 | 
            +
              it 'raises exception on unsupported crypto algorithm' do
         | 
| 190 | 
            +
                expect { JWT.encode(@payload, 'secret', 'HS1024') }.to raise_error(NotImplementedError)
         | 
| 97 191 | 
             
              end
         | 
| 98 192 |  | 
| 99 | 
            -
              it  | 
| 193 | 
            +
              it 'encodes and decodes plaintext JWTs' do
         | 
| 100 194 | 
             
                jwt = JWT.encode(@payload, nil, nil)
         | 
| 101 195 | 
             
                expect(jwt.split('.').length).to eq(2)
         | 
| 102 196 | 
             
                decoded_payload = JWT.decode(jwt, nil, nil)
         | 
| 103 197 | 
             
                expect(decoded_payload).to include(@payload)
         | 
| 104 198 | 
             
              end
         | 
| 105 199 |  | 
| 106 | 
            -
              it  | 
| 200 | 
            +
              it 'requires a signature segment when verify is truthy' do
         | 
| 107 201 | 
             
                jwt = JWT.encode(@payload, nil, nil)
         | 
| 108 202 | 
             
                expect(jwt.split('.').length).to eq(2)
         | 
| 109 203 | 
             
                expect { JWT.decode(jwt, nil, true) }.to raise_error(JWT::DecodeError)
         | 
| 110 204 | 
             
              end
         | 
| 111 205 |  | 
| 112 | 
            -
              it  | 
| 113 | 
            -
                secret =  | 
| 206 | 
            +
              it 'does not use == to compare digests' do
         | 
| 207 | 
            +
                secret = 'secret'
         | 
| 114 208 | 
             
                jwt = JWT.encode(@payload, secret)
         | 
| 115 | 
            -
                crypto_segment = jwt.split( | 
| 209 | 
            +
                crypto_segment = jwt.split('.').last
         | 
| 116 210 |  | 
| 117 211 | 
             
                signature = JWT.base64url_decode(crypto_segment)
         | 
| 118 212 | 
             
                expect(signature).not_to receive('==')
         | 
| @@ -122,96 +216,96 @@ describe JWT do | |
| 122 216 | 
             
                JWT.decode(jwt, secret)
         | 
| 123 217 | 
             
              end
         | 
| 124 218 |  | 
| 125 | 
            -
              it  | 
| 219 | 
            +
              it 'raises error when expired' do
         | 
| 126 220 | 
             
                expired_payload = @payload.clone
         | 
| 127 221 | 
             
                expired_payload['exp'] = Time.now.to_i - 1
         | 
| 128 | 
            -
                secret =  | 
| 222 | 
            +
                secret = 'secret'
         | 
| 129 223 | 
             
                jwt = JWT.encode(expired_payload, secret)
         | 
| 130 224 | 
             
                expect { JWT.decode(jwt, secret) }.to raise_error(JWT::ExpiredSignature)
         | 
| 131 225 | 
             
              end
         | 
| 132 226 |  | 
| 133 | 
            -
              it  | 
| 227 | 
            +
              it 'raise ExpiredSignature even when exp claims is a string' do
         | 
| 134 228 | 
             
                expired_payload = @payload.clone
         | 
| 135 229 | 
             
                expired_payload['exp'] = (Time.now.to_i).to_s
         | 
| 136 | 
            -
                secret =  | 
| 230 | 
            +
                secret = 'secret'
         | 
| 137 231 | 
             
                jwt = JWT.encode(expired_payload, secret)
         | 
| 138 232 | 
             
                expect { JWT.decode(jwt, secret) }.to raise_error(JWT::ExpiredSignature)
         | 
| 139 233 | 
             
              end
         | 
| 140 234 |  | 
| 141 | 
            -
              it  | 
| 235 | 
            +
              it 'performs normal decode with skipped expiration check' do
         | 
| 142 236 | 
             
                expired_payload = @payload.clone
         | 
| 143 237 | 
             
                expired_payload['exp'] = Time.now.to_i - 1
         | 
| 144 | 
            -
                secret =  | 
| 238 | 
            +
                secret = 'secret'
         | 
| 145 239 | 
             
                jwt = JWT.encode(expired_payload, secret)
         | 
| 146 240 | 
             
                decoded_payload = JWT.decode(jwt, secret, true, {:verify_expiration => false})
         | 
| 147 241 | 
             
                expect(decoded_payload).to include(expired_payload)
         | 
| 148 242 | 
             
              end
         | 
| 149 243 |  | 
| 150 | 
            -
              it  | 
| 244 | 
            +
              it 'performs normal decode using leeway' do
         | 
| 151 245 | 
             
                expired_payload = @payload.clone
         | 
| 152 246 | 
             
                expired_payload['exp'] = Time.now.to_i - 2
         | 
| 153 | 
            -
                secret =  | 
| 247 | 
            +
                secret = 'secret'
         | 
| 154 248 | 
             
                jwt = JWT.encode(expired_payload, secret)
         | 
| 155 249 | 
             
                decoded_payload = JWT.decode(jwt, secret, true, {:leeway => 3})
         | 
| 156 250 | 
             
                expect(decoded_payload).to include(expired_payload)
         | 
| 157 251 | 
             
              end
         | 
| 158 252 |  | 
| 159 | 
            -
              it  | 
| 253 | 
            +
              it 'raises error when before nbf' do
         | 
| 160 254 | 
             
                immature_payload = @payload.clone
         | 
| 161 255 | 
             
                immature_payload['nbf'] = Time.now.to_i + 1
         | 
| 162 | 
            -
                secret =  | 
| 256 | 
            +
                secret = 'secret'
         | 
| 163 257 | 
             
                jwt = JWT.encode(immature_payload, secret)
         | 
| 164 258 | 
             
                expect { JWT.decode(jwt, secret) }.to raise_error(JWT::ImmatureSignature)
         | 
| 165 259 | 
             
              end
         | 
| 166 260 |  | 
| 167 | 
            -
              it  | 
| 261 | 
            +
              it 'doesnt raise error when after nbf' do
         | 
| 168 262 | 
             
                mature_payload = @payload.clone
         | 
| 169 | 
            -
                secret =  | 
| 263 | 
            +
                secret = 'secret'
         | 
| 170 264 | 
             
                jwt = JWT.encode(mature_payload, secret)
         | 
| 171 265 | 
             
                decoded_payload = JWT.decode(jwt, secret, true, {:verify_expiration => false})
         | 
| 172 266 | 
             
                expect(decoded_payload).to include(mature_payload)
         | 
| 173 267 | 
             
              end
         | 
| 174 268 |  | 
| 175 | 
            -
              it  | 
| 269 | 
            +
              it 'raise ImmatureSignature even when nbf claim is a string' do
         | 
| 176 270 | 
             
                immature_payload = @payload.clone
         | 
| 177 271 | 
             
                immature_payload['nbf'] = (Time.now.to_i).to_s
         | 
| 178 | 
            -
                secret =  | 
| 272 | 
            +
                secret = 'secret'
         | 
| 179 273 | 
             
                jwt = JWT.encode(immature_payload, secret)
         | 
| 180 274 | 
             
                expect { JWT.decode(jwt, secret) }.to raise_error(JWT::ImmatureSignature)
         | 
| 181 275 | 
             
              end
         | 
| 182 276 |  | 
| 183 | 
            -
              it  | 
| 277 | 
            +
              it 'performs normal decode with skipped not before check' do
         | 
| 184 278 | 
             
                immature_payload = @payload.clone
         | 
| 185 279 | 
             
                immature_payload['nbf'] = Time.now.to_i + 2
         | 
| 186 | 
            -
                secret =  | 
| 280 | 
            +
                secret = 'secret'
         | 
| 187 281 | 
             
                jwt = JWT.encode(immature_payload, secret)
         | 
| 188 282 | 
             
                decoded_payload = JWT.decode(jwt, secret, true, {:verify_not_before => false})
         | 
| 189 283 | 
             
                expect(decoded_payload).to include(immature_payload)
         | 
| 190 284 | 
             
              end
         | 
| 191 285 |  | 
| 192 | 
            -
              it  | 
| 286 | 
            +
              it 'performs normal decode using leeway' do
         | 
| 193 287 | 
             
                immature_payload = @payload.clone
         | 
| 194 288 | 
             
                immature_payload['nbf'] = Time.now.to_i - 2
         | 
| 195 | 
            -
                secret =  | 
| 289 | 
            +
                secret = 'secret'
         | 
| 196 290 | 
             
                jwt = JWT.encode(immature_payload, secret)
         | 
| 197 291 | 
             
                decoded_payload = JWT.decode(jwt, secret, true, {:leeway => 3})
         | 
| 198 292 | 
             
                expect(decoded_payload).to include(immature_payload)
         | 
| 199 293 | 
             
              end
         | 
| 200 294 |  | 
| 201 | 
            -
              describe  | 
| 202 | 
            -
                it  | 
| 203 | 
            -
                  expect(JWT.secure_compare( | 
| 295 | 
            +
              describe 'secure comparison' do
         | 
| 296 | 
            +
                it 'returns true if strings are equal' do
         | 
| 297 | 
            +
                  expect(JWT.secure_compare('Foo', 'Foo')).to be true
         | 
| 204 298 | 
             
                end
         | 
| 205 299 |  | 
| 206 | 
            -
                it  | 
| 207 | 
            -
                  [nil,  | 
| 208 | 
            -
                    expect(JWT.secure_compare(bad,  | 
| 209 | 
            -
                    expect(JWT.secure_compare( | 
| 300 | 
            +
                it 'returns false if either input is nil or empty' do
         | 
| 301 | 
            +
                  [nil, ''].each do |bad|
         | 
| 302 | 
            +
                    expect(JWT.secure_compare(bad, 'Foo')).to be false
         | 
| 303 | 
            +
                    expect(JWT.secure_compare('Foo', bad)).to be false
         | 
| 210 304 | 
             
                  end
         | 
| 211 305 | 
             
                end
         | 
| 212 306 |  | 
| 213 | 
            -
                it  | 
| 214 | 
            -
                  expect(JWT.secure_compare( | 
| 307 | 
            +
                it 'retuns false if the strings are different' do
         | 
| 308 | 
            +
                  expect(JWT.secure_compare('Foo', 'Bar')).to be false
         | 
| 215 309 | 
             
                end
         | 
| 216 310 | 
             
              end
         | 
| 217 311 |  | 
| @@ -220,7 +314,7 @@ describe JWT do | |
| 220 314 | 
             
                expect(OpenSSL.errors).to be_empty
         | 
| 221 315 | 
             
              end
         | 
| 222 316 |  | 
| 223 | 
            -
              it  | 
| 317 | 
            +
              it 'raise exception on invalid signature' do
         | 
| 224 318 | 
             
                pubkey = OpenSSL::PKey::RSA.new(<<-PUBKEY)
         | 
| 225 319 | 
             
            -----BEGIN PUBLIC KEY-----
         | 
| 226 320 | 
             
            MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCaY7425h964bjaoLeUm
         | 
| @@ -245,20 +339,20 @@ PUBKEY | |
| 245 339 | 
             
                expect { JWT.decode(jwt, pubkey, true) }.to raise_error(JWT::DecodeError)
         | 
| 246 340 | 
             
              end
         | 
| 247 341 |  | 
| 248 | 
            -
              describe  | 
| 249 | 
            -
                it  | 
| 250 | 
            -
                  allow(Base64).to receive(:encode64) {  | 
| 251 | 
            -
                  expect(JWT.base64url_encode( | 
| 342 | 
            +
              describe 'urlsafe base64 encoding' do
         | 
| 343 | 
            +
                it 'replaces + and / with - and _' do
         | 
| 344 | 
            +
                  allow(Base64).to receive(:encode64) { 'string+with/non+url-safe/characters_' }
         | 
| 345 | 
            +
                  expect(JWT.base64url_encode('foo')).to eq('string-with_non-url-safe_characters_')
         | 
| 252 346 | 
             
                end
         | 
| 253 347 | 
             
              end
         | 
| 254 348 |  | 
| 255 349 | 
             
              describe 'decoded_segments' do
         | 
| 256 | 
            -
                it  | 
| 257 | 
            -
                  secret =  | 
| 350 | 
            +
                it 'allows access to the decoded header and payload' do
         | 
| 351 | 
            +
                  secret = 'secret'
         | 
| 258 352 | 
             
                  jwt = JWT.encode(@payload, secret)
         | 
| 259 353 | 
             
                  decoded_segments = JWT.decoded_segments(jwt)
         | 
| 260 354 | 
             
                  expect(decoded_segments.size).to eq(4)
         | 
| 261 | 
            -
                  expect(decoded_segments[0]).to eq({ | 
| 355 | 
            +
                  expect(decoded_segments[0]).to eq({'typ' => 'JWT', 'alg' => 'HS256'})
         | 
| 262 356 | 
             
                  expect(decoded_segments[1]).to eq(@payload)
         | 
| 263 357 | 
             
                end
         | 
| 264 358 | 
             
              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. | 
| 4 | 
            +
              version: 1.4.0
         | 
| 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- | 
| 11 | 
            +
            date: 2015-03-10 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: echoe
         |