jwt 2.3.0 → 2.4.0.beta1
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/.codeclimate.yml +8 -0
- data/.github/workflows/coverage.yml +27 -0
- data/.github/workflows/test.yml +2 -10
- data/.gitignore +2 -0
- data/.rubocop.yml +12 -28
- data/.rubocop_todo.yml +9 -172
- data/AUTHORS +60 -53
- data/Appraisals +3 -0
- data/CHANGELOG.md +48 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +3 -1
- data/README.md +59 -8
- data/Rakefile +2 -0
- data/lib/jwt/algos/ecdsa.rb +23 -5
- data/lib/jwt/algos/eddsa.rb +3 -0
- data/lib/jwt/algos/hmac.rb +2 -0
- data/lib/jwt/algos/none.rb +2 -0
- data/lib/jwt/algos/ps.rb +3 -3
- data/lib/jwt/algos/rsa.rb +4 -1
- data/lib/jwt/algos/unsupported.rb +2 -0
- data/lib/jwt/claims_validator.rb +3 -1
- data/lib/jwt/decode.rb +43 -9
- data/lib/jwt/default_options.rb +2 -0
- data/lib/jwt/encode.rb +6 -6
- data/lib/jwt/error.rb +1 -0
- data/lib/jwt/jwk/ec.rb +5 -5
- data/lib/jwt/jwk/hmac.rb +1 -1
- data/lib/jwt/jwk/key_base.rb +1 -0
- data/lib/jwt/jwk/rsa.rb +4 -3
- data/lib/jwt/jwk.rb +1 -0
- data/lib/jwt/security_utils.rb +2 -0
- data/lib/jwt/signature.rb +3 -7
- data/lib/jwt/verify.rb +10 -2
- data/lib/jwt/version.rb +2 -3
- data/lib/jwt/x5c_key_finder.rb +55 -0
- data/lib/jwt.rb +1 -1
- data/ruby-jwt.gemspec +4 -2
- metadata +10 -7
- data/lib/jwt/base64.rb +0 -19
data/lib/jwt/signature.rb
CHANGED
@@ -13,7 +13,8 @@ end
|
|
13
13
|
module JWT
|
14
14
|
# Signature logic for JWT
|
15
15
|
module Signature
|
16
|
-
|
16
|
+
module_function
|
17
|
+
|
17
18
|
ToSign = Struct.new(:algorithm, :msg, :key)
|
18
19
|
ToVerify = Struct.new(:algorithm, :public_key, :signing_input, :signature)
|
19
20
|
|
@@ -23,13 +24,8 @@ module JWT
|
|
23
24
|
end
|
24
25
|
|
25
26
|
def verify(algorithm, key, signing_input, signature)
|
26
|
-
return true if algorithm.casecmp('none').zero?
|
27
|
-
|
28
|
-
raise JWT::DecodeError, 'No verification key available' unless key
|
29
|
-
|
30
27
|
algo, code = Algos.find(algorithm)
|
31
|
-
|
32
|
-
raise(JWT::VerificationError, 'Signature verification raised') unless verified
|
28
|
+
algo.verify(ToVerify.new(code, key, signing_input, signature))
|
33
29
|
rescue OpenSSL::PKey::PKeyError
|
34
30
|
raise JWT::VerificationError, 'Signature verification raised'
|
35
31
|
ensure
|
data/lib/jwt/verify.rb
CHANGED
@@ -19,6 +19,7 @@ module JWT
|
|
19
19
|
def verify_claims(payload, options)
|
20
20
|
options.each do |key, val|
|
21
21
|
next unless key.to_s =~ /verify/
|
22
|
+
|
22
23
|
Verify.send(key, payload, options) if val
|
23
24
|
end
|
24
25
|
end
|
@@ -53,9 +54,14 @@ module JWT
|
|
53
54
|
|
54
55
|
iss = @payload['iss']
|
55
56
|
|
56
|
-
|
57
|
+
options_iss = Array(options_iss).map { |item| item.is_a?(Symbol) ? item.to_s : item }
|
57
58
|
|
58
|
-
|
59
|
+
case iss
|
60
|
+
when *options_iss
|
61
|
+
nil
|
62
|
+
else
|
63
|
+
raise(JWT::InvalidIssuerError, "Invalid issuer. Expected #{options_iss}, received #{iss || '<none>'}")
|
64
|
+
end
|
59
65
|
end
|
60
66
|
|
61
67
|
def verify_jti
|
@@ -77,12 +83,14 @@ module JWT
|
|
77
83
|
|
78
84
|
def verify_sub
|
79
85
|
return unless (options_sub = @options[:sub])
|
86
|
+
|
80
87
|
sub = @payload['sub']
|
81
88
|
raise(JWT::InvalidSubError, "Invalid subject. Expected #{options_sub}, received #{sub || '<none>'}") unless sub.to_s == options_sub.to_s
|
82
89
|
end
|
83
90
|
|
84
91
|
def verify_required_claims
|
85
92
|
return unless (options_required_claims = @options[:required_claims])
|
93
|
+
|
86
94
|
options_required_claims.each do |required_claim|
|
87
95
|
raise(JWT::MissingRequiredClaim, "Missing required claim #{required_claim}") unless @payload.include?(required_claim)
|
88
96
|
end
|
data/lib/jwt/version.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
# Moments version builder module
|
@@ -12,11 +11,11 @@ module JWT
|
|
12
11
|
# major version
|
13
12
|
MAJOR = 2
|
14
13
|
# minor version
|
15
|
-
MINOR =
|
14
|
+
MINOR = 4
|
16
15
|
# tiny version
|
17
16
|
TINY = 0
|
18
17
|
# alpha, beta, etc. tag
|
19
|
-
PRE =
|
18
|
+
PRE = 'beta1'
|
20
19
|
|
21
20
|
# Build version string
|
22
21
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
require 'jwt/error'
|
5
|
+
|
6
|
+
module JWT
|
7
|
+
# If the x5c header certificate chain can be validated by trusted root
|
8
|
+
# certificates, and none of the certificates are revoked, returns the public
|
9
|
+
# key from the first certificate.
|
10
|
+
# See https://tools.ietf.org/html/rfc7515#section-4.1.6
|
11
|
+
class X5cKeyFinder
|
12
|
+
def initialize(root_certificates, crls = nil)
|
13
|
+
raise(ArgumentError, 'Root certificates must be specified') unless root_certificates
|
14
|
+
|
15
|
+
@store = build_store(root_certificates, crls)
|
16
|
+
end
|
17
|
+
|
18
|
+
def from(x5c_header_or_certificates)
|
19
|
+
signing_certificate, *certificate_chain = parse_certificates(x5c_header_or_certificates)
|
20
|
+
store_context = OpenSSL::X509::StoreContext.new(@store, signing_certificate, certificate_chain)
|
21
|
+
|
22
|
+
if store_context.verify
|
23
|
+
signing_certificate.public_key
|
24
|
+
else
|
25
|
+
error = "Certificate verification failed: #{store_context.error_string}."
|
26
|
+
if (current_cert = store_context.current_cert)
|
27
|
+
error = "#{error} Certificate subject: #{current_cert.subject}."
|
28
|
+
end
|
29
|
+
|
30
|
+
raise(JWT::VerificationError, error)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def build_store(root_certificates, crls)
|
37
|
+
store = OpenSSL::X509::Store.new
|
38
|
+
store.purpose = OpenSSL::X509::PURPOSE_ANY
|
39
|
+
store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK | OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
|
40
|
+
root_certificates.each { |certificate| store.add_cert(certificate) }
|
41
|
+
crls&.each { |crl| store.add_crl(crl) }
|
42
|
+
store
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_certificates(x5c_header_or_certificates)
|
46
|
+
if x5c_header_or_certificates.all? { |obj| obj.is_a?(OpenSSL::X509::Certificate) }
|
47
|
+
x5c_header_or_certificates
|
48
|
+
else
|
49
|
+
x5c_header_or_certificates.map do |encoded|
|
50
|
+
OpenSSL::X509::Certificate.new(::Base64.strict_decode64(encoded))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/jwt.rb
CHANGED
data/ruby-jwt.gemspec
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
5
|
require 'jwt/version'
|
4
6
|
|
@@ -13,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
13
15
|
spec.description = 'A pure ruby implementation of the RFC 7519 OAuth JSON Web Token (JWT) standard.'
|
14
16
|
spec.homepage = 'https://github.com/jwt/ruby-jwt'
|
15
17
|
spec.license = 'MIT'
|
16
|
-
spec.required_ruby_version = '>= 2.
|
18
|
+
spec.required_ruby_version = '>= 2.5'
|
17
19
|
spec.metadata = {
|
18
20
|
'bug_tracker_uri' => 'https://github.com/jwt/ruby-jwt/issues',
|
19
21
|
'changelog_uri' => "https://github.com/jwt/ruby-jwt/blob/v#{JWT.gem_version}/CHANGELOG.md"
|
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: 2.
|
4
|
+
version: 2.4.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Rudat
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: appraisal
|
@@ -87,6 +87,8 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
+
- ".codeclimate.yml"
|
91
|
+
- ".github/workflows/coverage.yml"
|
90
92
|
- ".github/workflows/test.yml"
|
91
93
|
- ".gitignore"
|
92
94
|
- ".rspec"
|
@@ -96,6 +98,7 @@ files:
|
|
96
98
|
- AUTHORS
|
97
99
|
- Appraisals
|
98
100
|
- CHANGELOG.md
|
101
|
+
- CODE_OF_CONDUCT.md
|
99
102
|
- Gemfile
|
100
103
|
- LICENSE
|
101
104
|
- README.md
|
@@ -109,7 +112,6 @@ files:
|
|
109
112
|
- lib/jwt/algos/ps.rb
|
110
113
|
- lib/jwt/algos/rsa.rb
|
111
114
|
- lib/jwt/algos/unsupported.rb
|
112
|
-
- lib/jwt/base64.rb
|
113
115
|
- lib/jwt/claims_validator.rb
|
114
116
|
- lib/jwt/decode.rb
|
115
117
|
- lib/jwt/default_options.rb
|
@@ -126,13 +128,14 @@ files:
|
|
126
128
|
- lib/jwt/signature.rb
|
127
129
|
- lib/jwt/verify.rb
|
128
130
|
- lib/jwt/version.rb
|
131
|
+
- lib/jwt/x5c_key_finder.rb
|
129
132
|
- ruby-jwt.gemspec
|
130
133
|
homepage: https://github.com/jwt/ruby-jwt
|
131
134
|
licenses:
|
132
135
|
- MIT
|
133
136
|
metadata:
|
134
137
|
bug_tracker_uri: https://github.com/jwt/ruby-jwt/issues
|
135
|
-
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.
|
138
|
+
changelog_uri: https://github.com/jwt/ruby-jwt/blob/v2.4.0.beta1/CHANGELOG.md
|
136
139
|
post_install_message:
|
137
140
|
rdoc_options: []
|
138
141
|
require_paths:
|
@@ -141,12 +144,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
141
144
|
requirements:
|
142
145
|
- - ">="
|
143
146
|
- !ruby/object:Gem::Version
|
144
|
-
version: '2.
|
147
|
+
version: '2.5'
|
145
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
149
|
requirements:
|
147
|
-
- - "
|
150
|
+
- - ">"
|
148
151
|
- !ruby/object:Gem::Version
|
149
|
-
version:
|
152
|
+
version: 1.3.1
|
150
153
|
requirements: []
|
151
154
|
rubygems_version: 3.2.19
|
152
155
|
signing_key:
|
data/lib/jwt/base64.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'base64'
|
4
|
-
|
5
|
-
module JWT
|
6
|
-
# Base64 helpers
|
7
|
-
class Base64
|
8
|
-
class << self
|
9
|
-
def url_encode(str)
|
10
|
-
::Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '')
|
11
|
-
end
|
12
|
-
|
13
|
-
def url_decode(str)
|
14
|
-
str += '=' * (4 - str.length.modulo(4))
|
15
|
-
::Base64.decode64(str.tr('-_', '+/'))
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|