jwt 2.1.0 → 2.2.0.pre.beta.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.
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-----