jwt 2.1.0 → 2.2.0.pre.beta.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.travis.yml +9 -3
  4. data/AUTHORS +84 -0
  5. data/Appraisals +14 -0
  6. data/CHANGELOG.md +77 -8
  7. data/README.md +96 -85
  8. data/lib/jwt.rb +9 -42
  9. data/lib/jwt/algos/ecdsa.rb +1 -1
  10. data/lib/jwt/algos/ps.rb +43 -0
  11. data/lib/jwt/base64.rb +19 -0
  12. data/lib/jwt/claims_validator.rb +33 -0
  13. data/lib/jwt/decode.rb +76 -25
  14. data/lib/jwt/encode.rb +42 -25
  15. data/lib/jwt/error.rb +16 -12
  16. data/lib/jwt/json.rb +18 -0
  17. data/lib/jwt/jwk.rb +31 -0
  18. data/lib/jwt/jwk/key_finder.rb +57 -0
  19. data/lib/jwt/jwk/rsa.rb +45 -0
  20. data/lib/jwt/security_utils.rb +6 -0
  21. data/lib/jwt/signature.rb +2 -0
  22. data/lib/jwt/verify.rb +1 -5
  23. data/lib/jwt/version.rb +3 -3
  24. data/ruby-jwt.gemspec +6 -3
  25. metadata +44 -58
  26. data/.reek.yml +0 -40
  27. data/Manifest +0 -8
  28. data/spec/fixtures/certs/ec256-private.pem +0 -8
  29. data/spec/fixtures/certs/ec256-public.pem +0 -4
  30. data/spec/fixtures/certs/ec256-wrong-private.pem +0 -8
  31. data/spec/fixtures/certs/ec256-wrong-public.pem +0 -4
  32. data/spec/fixtures/certs/ec384-private.pem +0 -9
  33. data/spec/fixtures/certs/ec384-public.pem +0 -5
  34. data/spec/fixtures/certs/ec384-wrong-private.pem +0 -9
  35. data/spec/fixtures/certs/ec384-wrong-public.pem +0 -5
  36. data/spec/fixtures/certs/ec512-private.pem +0 -10
  37. data/spec/fixtures/certs/ec512-public.pem +0 -6
  38. data/spec/fixtures/certs/ec512-wrong-private.pem +0 -10
  39. data/spec/fixtures/certs/ec512-wrong-public.pem +0 -6
  40. data/spec/fixtures/certs/rsa-1024-private.pem +0 -15
  41. data/spec/fixtures/certs/rsa-1024-public.pem +0 -6
  42. data/spec/fixtures/certs/rsa-2048-private.pem +0 -27
  43. data/spec/fixtures/certs/rsa-2048-public.pem +0 -9
  44. data/spec/fixtures/certs/rsa-2048-wrong-private.pem +0 -27
  45. data/spec/fixtures/certs/rsa-2048-wrong-public.pem +0 -9
  46. data/spec/fixtures/certs/rsa-4096-private.pem +0 -51
  47. data/spec/fixtures/certs/rsa-4096-public.pem +0 -14
  48. data/spec/integration/readme_examples_spec.rb +0 -202
  49. data/spec/jwt/verify_spec.rb +0 -232
  50. data/spec/jwt_spec.rb +0 -315
  51. data/spec/spec_helper.rb +0 -28
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'jwk/rsa'
4
+ require_relative 'jwk/key_finder'
5
+
6
+ module JWT
7
+ module JWK
8
+ MAPPINGS = {
9
+ 'RSA' => ::JWT::JWK::RSA,
10
+ OpenSSL::PKey::RSA => ::JWT::JWK::RSA
11
+ }.freeze
12
+
13
+ class << self
14
+ def import(jwk_data)
15
+ raise JWT::JWKError, 'Key type (kty) not provided' unless jwk_data[:kty]
16
+
17
+ MAPPINGS.fetch(jwk_data[:kty].to_s) do |kty|
18
+ raise JWT::JWKError, "Key type #{kty} not supported"
19
+ end.import(jwk_data)
20
+ end
21
+
22
+ def create_from(keypair)
23
+ MAPPINGS.fetch(keypair.class) do |klass|
24
+ raise JWT::JWKError, "Cannot create JWK from a #{klass.name}"
25
+ end.new(keypair)
26
+ end
27
+
28
+ alias new create_from
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ module JWK
5
+ class KeyFinder
6
+ def initialize(options)
7
+ jwks_or_loader = options[:jwks]
8
+ @jwks = jwks_or_loader if jwks_or_loader.is_a?(Hash)
9
+ @jwk_loader = jwks_or_loader if jwks_or_loader.respond_to?(:call)
10
+ end
11
+
12
+ def key_for(kid)
13
+ raise ::JWT::DecodeError, 'No key id (kid) found from token headers' unless kid
14
+
15
+ jwk = resolve_key(kid)
16
+
17
+ raise ::JWT::DecodeError, "Could not find public key for kid #{kid}" unless jwk
18
+
19
+ ::JWT::JWK.import(jwk).keypair
20
+ end
21
+
22
+ private
23
+
24
+ def resolve_key(kid)
25
+ jwk = find_key(kid)
26
+
27
+ return jwk if jwk
28
+
29
+ if reloadable?
30
+ load_keys(invalidate: true)
31
+ return find_key(kid)
32
+ end
33
+
34
+ nil
35
+ end
36
+
37
+ def jwks
38
+ return @jwks if @jwks
39
+
40
+ load_keys
41
+ @jwks
42
+ end
43
+
44
+ def load_keys(opts = {})
45
+ @jwks = @jwk_loader.call(opts)
46
+ end
47
+
48
+ def find_key(kid)
49
+ Array(jwks[:keys]).find { |key| key[:kid] == kid }
50
+ end
51
+
52
+ def reloadable?
53
+ @jwk_loader
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ module JWK
5
+ class RSA
6
+ extend Forwardable
7
+
8
+ attr_reader :keypair
9
+
10
+ def_delegators :keypair, :private?, :public_key
11
+
12
+ BINARY = 2
13
+ KTY = 'RSA'.freeze
14
+
15
+ def initialize(keypair)
16
+ raise ArgumentError, 'keypair must be of type OpenSSL::PKey::RSA' unless keypair.is_a?(OpenSSL::PKey::RSA)
17
+
18
+ @keypair = keypair
19
+ end
20
+
21
+ def kid
22
+ sequence = OpenSSL::ASN1::Sequence([OpenSSL::ASN1::Integer.new(public_key.n),
23
+ OpenSSL::ASN1::Integer.new(public_key.e)])
24
+ OpenSSL::Digest::SHA256.hexdigest(sequence.to_der)
25
+ end
26
+
27
+ def export
28
+ {
29
+ kty: KTY,
30
+ n: ::Base64.urlsafe_encode64(public_key.n.to_s(BINARY), padding: false),
31
+ e: ::Base64.urlsafe_encode64(public_key.e.to_s(BINARY), padding: false),
32
+ kid: kid
33
+ }
34
+ end
35
+
36
+ def self.import(jwk_data)
37
+ imported_key = OpenSSL::PKey::RSA.new
38
+ imported_key.set_key(OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data[:n]), BINARY),
39
+ OpenSSL::BN.new(::Base64.urlsafe_decode64(jwk_data[:e]), BINARY),
40
+ nil)
41
+ self.new(imported_key)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -20,6 +20,12 @@ module JWT
20
20
  public_key.verify(OpenSSL::Digest.new(algorithm.sub('RS', 'sha')), signature, signing_input)
21
21
  end
22
22
 
23
+ def verify_ps(algorithm, public_key, signing_input, signature)
24
+ formatted_algorithm = algorithm.sub('PS', 'sha')
25
+
26
+ public_key.verify_pss(formatted_algorithm, signature, signing_input, salt_length: :auto, mgf1_hash: formatted_algorithm)
27
+ end
28
+
23
29
  def asn1_to_raw(signature, public_key)
24
30
  byte_size = (public_key.group.degree + 7) / 8
25
31
  OpenSSL::ASN1.decode(signature).value.map { |value| value.value.to_s(2).rjust(byte_size, "\x00") }.join
@@ -6,6 +6,7 @@ require 'jwt/algos/hmac'
6
6
  require 'jwt/algos/eddsa'
7
7
  require 'jwt/algos/ecdsa'
8
8
  require 'jwt/algos/rsa'
9
+ require 'jwt/algos/ps'
9
10
  require 'jwt/algos/unsupported'
10
11
  begin
11
12
  require 'rbnacl'
@@ -23,6 +24,7 @@ module JWT
23
24
  Algos::Ecdsa,
24
25
  Algos::Rsa,
25
26
  Algos::Eddsa,
27
+ Algos::Ps,
26
28
  Algos::Unsupported
27
29
  ].freeze
28
30
  ToSign = Struct.new(:algorithm, :msg, :key)
@@ -45,7 +45,7 @@ module JWT
45
45
  return unless @payload.include?('iat')
46
46
 
47
47
  iat = @payload['iat']
48
- raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(Numeric) || iat.to_f > (Time.now.to_f + iat_leeway)
48
+ raise(JWT::InvalidIatError, 'Invalid iat') if !iat.is_a?(Numeric) || iat.to_f > Time.now.to_f
49
49
  end
50
50
 
51
51
  def verify_iss
@@ -91,10 +91,6 @@ module JWT
91
91
  @options[:exp_leeway] || global_leeway
92
92
  end
93
93
 
94
- def iat_leeway
95
- @options[:iat_leeway] || global_leeway
96
- end
97
-
98
94
  def nbf_leeway
99
95
  @options[:nbf_leeway] || global_leeway
100
96
  end
@@ -12,13 +12,13 @@ module JWT
12
12
  # major version
13
13
  MAJOR = 2
14
14
  # minor version
15
- MINOR = 1
15
+ MINOR = 2
16
16
  # tiny version
17
17
  TINY = 0
18
18
  # alpha, beta, etc. tag
19
- PRE = nil
19
+ PRE = 'beta.0'
20
20
 
21
21
  # Build version string
22
- STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
22
+ STRING = [[MAJOR, MINOR, TINY].compact.join('.'), PRE].compact.join('-')
23
23
  end
24
24
  end
@@ -11,15 +11,16 @@ Gem::Specification.new do |spec|
11
11
  spec.email = 'timrudat@gmail.com'
12
12
  spec.summary = 'JSON Web Token implementation in Ruby'
13
13
  spec.description = 'A pure ruby implementation of the RFC 7519 OAuth JSON Web Token (JWT) standard.'
14
- spec.homepage = 'http://github.com/jwt/ruby-jwt'
14
+ spec.homepage = 'https://github.com/jwt/ruby-jwt'
15
15
  spec.license = 'MIT'
16
16
  spec.required_ruby_version = '>= 2.1'
17
17
 
18
- spec.files = `git ls-files -z`.split("\x0")
19
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|gemfiles|coverage|bin)/}) }
19
+ spec.executables = []
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
21
  spec.require_paths = %w[lib]
22
22
 
23
+ spec.add_development_dependency 'appraisal'
23
24
  spec.add_development_dependency 'bundler'
24
25
  spec.add_development_dependency 'rake'
25
26
  spec.add_development_dependency 'rspec'
@@ -28,4 +29,6 @@ Gem::Specification.new do |spec|
28
29
  spec.add_development_dependency 'codeclimate-test-reporter'
29
30
  spec.add_development_dependency 'codacy-coverage'
30
31
  spec.add_development_dependency 'rbnacl'
32
+ # RSASSA-PSS support provided by OpenSSL +2.1
33
+ spec.add_development_dependency 'openssl', '~> 2.1'
31
34
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0.pre.beta.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Rudat
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-06 00:00:00.000000000 Z
11
+ date: 2019-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: appraisal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +136,20 @@ dependencies:
122
136
  - - ">="
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: openssl
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '2.1'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '2.1'
125
153
  description: A pure ruby implementation of the RFC 7519 OAuth JSON Web Token (JWT)
126
154
  standard.
127
155
  email: timrudat@gmail.com
@@ -132,56 +160,39 @@ files:
132
160
  - ".codeclimate.yml"
133
161
  - ".ebert.yml"
134
162
  - ".gitignore"
135
- - ".reek.yml"
136
163
  - ".rspec"
137
164
  - ".rubocop.yml"
138
165
  - ".travis.yml"
166
+ - AUTHORS
167
+ - Appraisals
139
168
  - CHANGELOG.md
140
169
  - Gemfile
141
170
  - LICENSE
142
- - Manifest
143
171
  - README.md
144
172
  - Rakefile
145
173
  - lib/jwt.rb
146
174
  - lib/jwt/algos/ecdsa.rb
147
175
  - lib/jwt/algos/eddsa.rb
148
176
  - lib/jwt/algos/hmac.rb
177
+ - lib/jwt/algos/ps.rb
149
178
  - lib/jwt/algos/rsa.rb
150
179
  - lib/jwt/algos/unsupported.rb
180
+ - lib/jwt/base64.rb
181
+ - lib/jwt/claims_validator.rb
151
182
  - lib/jwt/decode.rb
152
183
  - lib/jwt/default_options.rb
153
184
  - lib/jwt/encode.rb
154
185
  - lib/jwt/error.rb
186
+ - lib/jwt/json.rb
187
+ - lib/jwt/jwk.rb
188
+ - lib/jwt/jwk/key_finder.rb
189
+ - lib/jwt/jwk/rsa.rb
155
190
  - lib/jwt/security_utils.rb
156
191
  - lib/jwt/signature.rb
157
192
  - lib/jwt/verify.rb
158
193
  - lib/jwt/version.rb
159
194
  - ruby-jwt.gemspec
160
- - spec/fixtures/certs/ec256-private.pem
161
- - spec/fixtures/certs/ec256-public.pem
162
- - spec/fixtures/certs/ec256-wrong-private.pem
163
- - spec/fixtures/certs/ec256-wrong-public.pem
164
- - spec/fixtures/certs/ec384-private.pem
165
- - spec/fixtures/certs/ec384-public.pem
166
- - spec/fixtures/certs/ec384-wrong-private.pem
167
- - spec/fixtures/certs/ec384-wrong-public.pem
168
- - spec/fixtures/certs/ec512-private.pem
169
- - spec/fixtures/certs/ec512-public.pem
170
- - spec/fixtures/certs/ec512-wrong-private.pem
171
- - spec/fixtures/certs/ec512-wrong-public.pem
172
- - spec/fixtures/certs/rsa-1024-private.pem
173
- - spec/fixtures/certs/rsa-1024-public.pem
174
- - spec/fixtures/certs/rsa-2048-private.pem
175
- - spec/fixtures/certs/rsa-2048-public.pem
176
- - spec/fixtures/certs/rsa-2048-wrong-private.pem
177
- - spec/fixtures/certs/rsa-2048-wrong-public.pem
178
- - spec/fixtures/certs/rsa-4096-private.pem
179
- - spec/fixtures/certs/rsa-4096-public.pem
180
- - spec/integration/readme_examples_spec.rb
181
- - spec/jwt/verify_spec.rb
182
- - spec/jwt_spec.rb
183
- - spec/spec_helper.rb
184
- homepage: http://github.com/jwt/ruby-jwt
195
+ homepage: https://github.com/jwt/ruby-jwt
185
196
  licenses:
186
197
  - MIT
187
198
  metadata: {}
@@ -196,37 +207,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
196
207
  version: '2.1'
197
208
  required_rubygems_version: !ruby/object:Gem::Requirement
198
209
  requirements:
199
- - - ">="
210
+ - - ">"
200
211
  - !ruby/object:Gem::Version
201
- version: '0'
212
+ version: 1.3.1
202
213
  requirements: []
203
- rubyforge_project:
204
- rubygems_version: 2.6.13
214
+ rubygems_version: 3.0.3
205
215
  signing_key:
206
216
  specification_version: 4
207
217
  summary: JSON Web Token implementation in Ruby
208
- test_files:
209
- - spec/fixtures/certs/ec256-private.pem
210
- - spec/fixtures/certs/ec256-public.pem
211
- - spec/fixtures/certs/ec256-wrong-private.pem
212
- - spec/fixtures/certs/ec256-wrong-public.pem
213
- - spec/fixtures/certs/ec384-private.pem
214
- - spec/fixtures/certs/ec384-public.pem
215
- - spec/fixtures/certs/ec384-wrong-private.pem
216
- - spec/fixtures/certs/ec384-wrong-public.pem
217
- - spec/fixtures/certs/ec512-private.pem
218
- - spec/fixtures/certs/ec512-public.pem
219
- - spec/fixtures/certs/ec512-wrong-private.pem
220
- - spec/fixtures/certs/ec512-wrong-public.pem
221
- - spec/fixtures/certs/rsa-1024-private.pem
222
- - spec/fixtures/certs/rsa-1024-public.pem
223
- - spec/fixtures/certs/rsa-2048-private.pem
224
- - spec/fixtures/certs/rsa-2048-public.pem
225
- - spec/fixtures/certs/rsa-2048-wrong-private.pem
226
- - spec/fixtures/certs/rsa-2048-wrong-public.pem
227
- - spec/fixtures/certs/rsa-4096-private.pem
228
- - spec/fixtures/certs/rsa-4096-public.pem
229
- - spec/integration/readme_examples_spec.rb
230
- - spec/jwt/verify_spec.rb
231
- - spec/jwt_spec.rb
232
- - spec/spec_helper.rb
218
+ test_files: []
data/.reek.yml DELETED
@@ -1,40 +0,0 @@
1
- ---
2
- TooManyStatements:
3
- max_statements: 10
4
- UncommunicativeMethodName:
5
- reject:
6
- - !ruby/regexp /^[a-z]$/
7
- - !ruby/regexp /[0-9]$/
8
- UncommunicativeParameterName:
9
- reject:
10
- - !ruby/regexp /^.$/
11
- - !ruby/regexp /[0-9]$/
12
- - !ruby/regexp /^_/
13
- UncommunicativeVariableName:
14
- reject:
15
- - !ruby/regexp /^.$/
16
- - !ruby/regexp /[0-9]$/
17
- UtilityFunction:
18
- enabled: false
19
- LongParameterList:
20
- enabled: false
21
- DuplicateMethodCall:
22
- max_calls: 2
23
- IrresponsibleModule:
24
- enabled: false
25
- NestedIterators:
26
- max_allowed_nesting: 2
27
- PrimaDonnaMethod:
28
- enabled: false
29
- UnusedParameters:
30
- enabled: false
31
- FeatureEnvy:
32
- enabled: false
33
- ControlParameter:
34
- enabled: false
35
- UnusedPrivateMethod:
36
- enabled: false
37
- InstanceVariableAssumption:
38
- exclude:
39
- - !ruby/regexp /Controller$/
40
- - !ruby/regexp /Mailer$/s
data/Manifest DELETED
@@ -1,8 +0,0 @@
1
- Rakefile
2
- README.md
3
- LICENSE
4
- lib/jwt.rb
5
- lib/jwt/json.rb
6
- spec/spec_helper.rb
7
- spec/jwt_spec.rb
8
- Manifest
@@ -1,8 +0,0 @@
1
- -----BEGIN EC PARAMETERS-----
2
- BggqhkjOPQMBBw==
3
- -----END EC PARAMETERS-----
4
- -----BEGIN EC PRIVATE KEY-----
5
- MHcCAQEEIJmVse5uPfj6B4TcXrUAvf9/8pJh+KrKKYLNcmOnp/vPoAoGCCqGSM49
6
- AwEHoUQDQgAEAr+WbDE5VtIDGhtYMxvEc6cMsDBc/DX1wuhIMu8dQzOLSt0tpqK9
7
- MVfXbVfrKdayVFgoWzs8MilcYq0QIhKx/w==
8
- -----END EC PRIVATE KEY-----