json-jwt 1.12.0 → 1.15.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of json-jwt might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68b182c2d39eda33bcfda685dc386a10575c6a30a740104101849d3396d96268
4
- data.tar.gz: 0cd7d0f10a6aa740d91055d98804a19589cd004092829d5de250df3a730dc8d2
3
+ metadata.gz: 881eaf3476eb9b98f7e02ba780e2893398f79f707c55c7e151f1de8f1a344f5c
4
+ data.tar.gz: fe2329046f613383e73b4b8579d440f6e394457ad3b090fee27c373b47daa690
5
5
  SHA512:
6
- metadata.gz: 36420fb065425af2ab32d5b6b17dede95077e990a9bcdbd4b71df51b89d7cf751566d8acfb4297b55f5f1e0bda7c44d07597163cfadd4c8168b5b6a65441b263
7
- data.tar.gz: 389b33e913fc804c3f824863a105505f54af77a7f9ad95c52d78616084ee5ac0acb4192ec58b7b91f0a50c080acb724debe98be625ad9eb2f9301e2392f02730
6
+ metadata.gz: d337b0e27607d55697ae6e162b25674fbcc27b21fe23bfa34d42bc4812e0a35f39f95b8eff66b7a4f6de7e78e883450f6e580931164c632a0146253b7ee89d58
7
+ data.tar.gz: 0fea890071b4038cbc4ee8080d5c99388035f7642707dd1f4303bcafd7f5f9d8c2f517a5d938d988b551d680211ef6909987b6bbd7e3a5d4688136e37a469f54
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ github: nov
@@ -0,0 +1,30 @@
1
+ name: Test Ruby
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ strategy:
13
+ matrix:
14
+ os: ['ubuntu-18.04', 'ubuntu-20.04']
15
+ ruby-version: ['2.5', '2.6', '2.7', '3.0', '3.1']
16
+ # ubuntu 22.04 only supports ssl 3 and thus only ruby 3.1
17
+ include:
18
+ - os: 'ubuntu-22.04'
19
+ ruby-version: '3.1'
20
+ runs-on: ${{ matrix.os }}
21
+
22
+ steps:
23
+ - uses: actions/checkout@v3
24
+ - name: Set up Ruby
25
+ uses: ruby/setup-ruby@v1
26
+ with:
27
+ ruby-version: ${{ matrix.ruby-version }}
28
+ bundler-cache: true
29
+ - name: Run tests
30
+ run: bundle exec rake
data/.gitmodules CHANGED
@@ -1,3 +1,3 @@
1
1
  [submodule "spec/helpers/json-jwt-nimbus"]
2
2
  path = spec/helpers/json-jwt-nimbus
3
- url = git://github.com/nov/json-jwt-nimbus.git
3
+ url = https://github.com/nov/json-jwt-nimbus.git
data/.travis.yml CHANGED
@@ -3,9 +3,9 @@ before_install:
3
3
  - git submodule update --init --recursive
4
4
 
5
5
  rvm:
6
- - 2.5.8
7
- - 2.6.6
8
- - 2.7.1
6
+ - 2.7.6
7
+ - 3.0.4
8
+ - 3.1.2
9
9
 
10
10
  jdk:
11
11
  - openjdk11
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.12.0
1
+ 1.15.0
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "json/jwt"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/json-jwt.gemspec CHANGED
@@ -12,12 +12,14 @@ Gem::Specification.new do |gem|
12
12
  end
13
13
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
14
14
  gem.require_paths = ['lib']
15
- gem.required_ruby_version = '>= 2.3'
15
+ gem.required_ruby_version = '>= 2.4'
16
16
  gem.add_runtime_dependency 'activesupport', '>= 4.2'
17
17
  gem.add_runtime_dependency 'bindata'
18
18
  gem.add_runtime_dependency 'aes_key_wrap'
19
+ gem.add_runtime_dependency 'httpclient'
19
20
  gem.add_development_dependency 'rake'
20
21
  gem.add_development_dependency 'simplecov'
22
+ gem.add_development_dependency 'webmock'
21
23
  gem.add_development_dependency 'rspec'
22
24
  gem.add_development_dependency 'rspec-its'
23
25
  end
data/lib/json/jose.rb CHANGED
@@ -7,6 +7,8 @@ module JSON
7
7
  included do
8
8
  extend ClassMethods
9
9
  register_header_keys :alg, :jku, :jwk, :x5u, :x5t, :x5c, :kid, :typ, :cty, :crit
10
+
11
+ # NOTE: not used anymore in this gem, but keeping in case developers are calling it.
10
12
  alias_method :algorithm, :alg
11
13
 
12
14
  attr_writer :header
data/lib/json/jwe.rb CHANGED
@@ -107,7 +107,7 @@ module JSON
107
107
  end
108
108
 
109
109
  def dir?
110
- :dir == algorithm&.to_sym
110
+ :dir == alg&.to_sym
111
111
  end
112
112
 
113
113
  def cipher
@@ -159,7 +159,7 @@ module JSON
159
159
  # encryption
160
160
 
161
161
  def jwe_encrypted_key
162
- @jwe_encrypted_key ||= case algorithm&.to_sym
162
+ @jwe_encrypted_key ||= case alg&.to_sym
163
163
  when :RSA1_5
164
164
  public_key_or_secret.public_encrypt content_encryption_key
165
165
  when :'RSA-OAEP'
@@ -211,7 +211,7 @@ module JSON
211
211
 
212
212
  def decrypt_content_encryption_key
213
213
  fake_content_encryption_key = generate_content_encryption_key # NOTE: do this always not to make timing difference
214
- case algorithm&.to_sym
214
+ case alg&.to_sym
215
215
  when :RSA1_5
216
216
  private_key_or_secret.private_decrypt jwe_encrypted_key
217
217
  when :'RSA-OAEP'
@@ -44,6 +44,8 @@ module JSON
44
44
  :'P-384'
45
45
  when 'secp521r1'
46
46
  :'P-521'
47
+ when 'secp256k1'
48
+ :secp256k1
47
49
  else
48
50
  raise UnknownAlgorithm.new('Unknown EC Curve')
49
51
  end
@@ -0,0 +1,34 @@
1
+ module JSON
2
+ class JWK
3
+ class Set
4
+ module Fetcher
5
+ module Debugger
6
+ class RequestFilter
7
+ # Callback called in HTTPClient (before sending a request)
8
+ # request:: HTTP::Message
9
+ def filter_request(request)
10
+ started = "======= [JSON::JWK::Set::Fetcher] HTTP REQUEST STARTED ======="
11
+ log started, request.dump
12
+ end
13
+
14
+ # Callback called in HTTPClient (after received a response)
15
+ # request:: HTTP::Message
16
+ # response:: HTTP::Message
17
+ def filter_response(request, response)
18
+ finished = "======= [JSON::JWK::Set::Fetcher] HTTP REQUEST FINISHED ======="
19
+ log '-' * 50, response.dump, finished
20
+ end
21
+
22
+ private
23
+
24
+ def log(*outputs)
25
+ outputs.each do |output|
26
+ JSON::JWK::Set::Fetcher.logger.info output
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,83 @@
1
+ module JSON
2
+ class JWK
3
+ class Set
4
+ module Fetcher
5
+ class Cache
6
+ def fetch(cache_key)
7
+ yield
8
+ end
9
+ end
10
+
11
+ def self.logger
12
+ @@logger
13
+ end
14
+ def self.logger=(logger)
15
+ @@logger = logger
16
+ end
17
+ self.logger = Logger.new(STDOUT)
18
+ self.logger.progname = 'JSON::JWK::Set::Fetcher'
19
+
20
+ def self.debugging?
21
+ @@debugging
22
+ end
23
+ def self.debugging=(boolean)
24
+ @@debugging = boolean
25
+ end
26
+ def self.debug!
27
+ self.debugging = true
28
+ end
29
+ def self.debug(&block)
30
+ original = self.debugging?
31
+ debug!
32
+ yield
33
+ ensure
34
+ self.debugging = original
35
+ end
36
+ self.debugging = false
37
+
38
+ def self.http_client
39
+ _http_client_ = HTTPClient.new(
40
+ agent_name: "JSON::JWK::Set::Fetcher (#{JSON::JWT::VERSION})"
41
+ )
42
+
43
+ # NOTE: httpclient gem seems stopped maintaining root certtificate set, use OS default.
44
+ _http_client_.ssl_config.clear_cert_store
45
+ _http_client_.ssl_config.cert_store.set_default_paths
46
+
47
+ _http_client_.request_filter << Debugger::RequestFilter.new if debugging?
48
+ http_config.try(:call, _http_client_)
49
+ _http_client_
50
+ end
51
+ def self.http_config(&block)
52
+ @@http_config ||= block
53
+ end
54
+
55
+ def self.cache=(cache)
56
+ @@cache = cache
57
+ end
58
+ def self.cache
59
+ @@cache
60
+ end
61
+ self.cache = Cache.new
62
+
63
+ def self.fetch(jwks_uri, kid:)
64
+ cache_key = [
65
+ 'json:jwk:set',
66
+ OpenSSL::Digest::MD5.hexdigest(jwks_uri),
67
+ kid
68
+ ].collect(&:to_s).join(':')
69
+ jwks = Set.new(
70
+ JSON.parse(
71
+ cache.fetch(cache_key) do
72
+ http_client.get_content(jwks_uri)
73
+ end
74
+ )
75
+ )
76
+ jwks.detect do |jwk|
77
+ jwk[:kid] && jwk[:kid] == kid
78
+ end or raise JWK::Set::KidNotFound
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
data/lib/json/jwk.rb CHANGED
@@ -88,35 +88,42 @@ module JSON
88
88
  end
89
89
 
90
90
  private
91
-
91
+
92
92
  def calculate_default_kid
93
93
  self[:kid] = thumbprint
94
94
  rescue
95
95
  # ignore
96
96
  end
97
-
97
+
98
98
  def to_rsa_key
99
99
  e, n, d, p, q, dp, dq, qi = [:e, :n, :d, :p, :q, :dp, :dq, :qi].collect do |key|
100
100
  if self[key]
101
101
  OpenSSL::BN.new Base64.urlsafe_decode64(self[key]), 2
102
102
  end
103
103
  end
104
- key = OpenSSL::PKey::RSA.new
105
- if key.respond_to? :set_key
106
- key.set_key n, e, d
107
- key.set_factors p, q if p && q
108
- key.set_crt_params dp, dq, qi if dp && dq && qi
109
- else
110
- key.e = e
111
- key.n = n
112
- key.d = d if d
113
- key.p = p if p
114
- key.q = q if q
115
- key.dmp1 = dp if dp
116
- key.dmq1 = dq if dq
117
- key.iqmp = qi if qi
104
+
105
+ # Public key
106
+ data_sequence = OpenSSL::ASN1::Sequence([
107
+ OpenSSL::ASN1::Integer(n),
108
+ OpenSSL::ASN1::Integer(e),
109
+ ])
110
+
111
+ if d && p && q && dp && dq && qi
112
+ data_sequence = OpenSSL::ASN1::Sequence([
113
+ OpenSSL::ASN1::Integer(0),
114
+ OpenSSL::ASN1::Integer(n),
115
+ OpenSSL::ASN1::Integer(e),
116
+ OpenSSL::ASN1::Integer(d),
117
+ OpenSSL::ASN1::Integer(p),
118
+ OpenSSL::ASN1::Integer(q),
119
+ OpenSSL::ASN1::Integer(dp),
120
+ OpenSSL::ASN1::Integer(dq),
121
+ OpenSSL::ASN1::Integer(qi),
122
+ ])
118
123
  end
119
- key
124
+
125
+ asn1 = OpenSSL::ASN1::Sequence(data_sequence)
126
+ OpenSSL::PKey::RSA.new(asn1.to_der)
120
127
  end
121
128
 
122
129
  def to_ec_key
@@ -127,6 +134,8 @@ module JSON
127
134
  'secp384r1'
128
135
  when :'P-521'
129
136
  'secp521r1'
137
+ when :secp256k1
138
+ 'secp256k1'
130
139
  else
131
140
  raise UnknownAlgorithm.new('Unknown EC Curve')
132
141
  end
@@ -135,13 +144,32 @@ module JSON
135
144
  Base64.urlsafe_decode64(self[key])
136
145
  end
137
146
  end
138
- key = OpenSSL::PKey::EC.new curve_name
139
- key.private_key = OpenSSL::BN.new(d, 2) if d
140
- key.public_key = OpenSSL::PKey::EC::Point.new(
147
+
148
+ point = OpenSSL::PKey::EC::Point.new(
141
149
  OpenSSL::PKey::EC::Group.new(curve_name),
142
150
  OpenSSL::BN.new(['04' + x.unpack('H*').first + y.unpack('H*').first].pack('H*'), 2)
143
151
  )
144
- key
152
+
153
+ # Public key
154
+ data_sequence = OpenSSL::ASN1::Sequence([
155
+ OpenSSL::ASN1::Sequence([
156
+ OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
157
+ OpenSSL::ASN1::ObjectId(curve_name)
158
+ ]),
159
+ OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed))
160
+ ])
161
+
162
+ if d
163
+ # Private key
164
+ data_sequence = OpenSSL::ASN1::Sequence([
165
+ OpenSSL::ASN1::Integer(1),
166
+ OpenSSL::ASN1::OctetString(OpenSSL::BN.new(d, 2).to_s(2)),
167
+ OpenSSL::ASN1::ObjectId(curve_name, 0, :EXPLICIT),
168
+ OpenSSL::ASN1::BitString(point.to_octet_string(:uncompressed), 1, :EXPLICIT)
169
+ ])
170
+ end
171
+
172
+ OpenSSL::PKey::EC.new(data_sequence.to_der)
145
173
  end
146
174
  end
147
175
  end
data/lib/json/jws.rb CHANGED
@@ -13,7 +13,7 @@ module JSON
13
13
  end
14
14
 
15
15
  def sign!(private_key_or_secret)
16
- self.alg = autodetected_algorithm_from(private_key_or_secret) if algorithm == :autodetect
16
+ self.alg = autodetected_algorithm_from(private_key_or_secret) if alg == :autodetect
17
17
  self.signature = sign signature_base_string, private_key_or_secret
18
18
  self
19
19
  end
@@ -43,31 +43,23 @@ module JSON
43
43
  private
44
44
 
45
45
  def digest
46
- OpenSSL::Digest.new "SHA#{algorithm.to_s[2, 3]}"
46
+ OpenSSL::Digest.new "SHA#{alg.to_s[2, 3]}"
47
47
  end
48
48
 
49
49
  def hmac?
50
- [:HS256, :HS384, :HS512].include? algorithm&.to_sym
50
+ [:HS256, :HS384, :HS512].include? alg&.to_sym
51
51
  end
52
52
 
53
53
  def rsa?
54
- [:RS256, :RS384, :RS512].include? algorithm&.to_sym
54
+ [:RS256, :RS384, :RS512].include? alg&.to_sym
55
55
  end
56
56
 
57
57
  def rsa_pss?
58
- if [:PS256, :PS384, :PS512].include? algorithm&.to_sym
59
- if OpenSSL::VERSION < '2.1.0'
60
- raise "#{alg} isn't supported. OpenSSL gem v2.1.0+ is required to use #{alg}."
61
- else
62
- true
63
- end
64
- else
65
- false
66
- end
58
+ [:PS256, :PS384, :PS512].include? alg&.to_sym
67
59
  end
68
60
 
69
61
  def ecdsa?
70
- [:ES256, :ES384, :ES512].include? algorithm&.to_sym
62
+ [:ES256, :ES384, :ES512, :ES256K].include? alg&.to_sym
71
63
  end
72
64
 
73
65
  def autodetected_algorithm_from(private_key_or_secret)
@@ -85,6 +77,8 @@ module JSON
85
77
  :ES384
86
78
  when 'secp521r1'
87
79
  :ES512
80
+ when 'secp256k1'
81
+ :ES256K
88
82
  else
89
83
  raise UnknownAlgorithm.new('Unknown EC Curve')
90
84
  end
@@ -118,8 +112,7 @@ module JSON
118
112
  private_key = private_key_or_secret
119
113
  verify_ecdsa_group! private_key
120
114
  asn1_to_raw(
121
- private_key.dsa_sign_asn1(digest.digest signature_base_string),
122
- # private_key.sign(digest, signature_base_string), # NOTE: this causes `undefined method `private?'` error in ruby 2.3
115
+ private_key.sign(digest, signature_base_string),
123
116
  private_key
124
117
  )
125
118
  else
@@ -152,14 +145,19 @@ module JSON
152
145
  def verify_ecdsa_group!(key)
153
146
  group_name = case digest.digest_length * 8
154
147
  when 256
155
- :prime256v1
148
+ case key.group.curve_name
149
+ when 'secp256k1'
150
+ :secp256k1
151
+ else
152
+ :prime256v1
153
+ end
156
154
  when 384
157
155
  :secp384r1
158
156
  when 512
159
157
  :secp521r1
160
158
  end
161
- key.group = OpenSSL::PKey::EC::Group.new group_name.to_s
162
- key.check_key
159
+ newkey = OpenSSL::PKey::EC.generate(group_name.to_s)
160
+ newkey.check_key
163
161
  end
164
162
 
165
163
  def raw_to_asn1(signature, public_key)
data/lib/json/jwt.rb CHANGED
@@ -1,11 +1,16 @@
1
1
  require 'openssl'
2
2
  require 'base64'
3
+ require 'httpclient'
3
4
  require 'active_support'
4
5
  require 'active_support/core_ext'
5
6
  require 'json/jose'
6
7
 
7
8
  module JSON
8
9
  class JWT < ActiveSupport::HashWithIndifferentAccess
10
+ VERSION = ::File.read(
11
+ ::File.join(::File.dirname(__FILE__), '../../VERSION')
12
+ ).chomp
13
+
9
14
  attr_accessor :blank_payload
10
15
  attr_accessor :signature
11
16
 
@@ -132,3 +137,5 @@ require 'json/jwe'
132
137
  require 'json/jwk'
133
138
  require 'json/jwk/jwkizable'
134
139
  require 'json/jwk/set'
140
+ require 'json/jwk/set/fetcher'
141
+ require 'json/jwk/set/fetcher/debugger/request_filter'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-jwt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 1.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nov matake
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-22 00:00:00.000000000 Z
11
+ date: 2022-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: httpclient
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: rspec
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -112,10 +140,13 @@ description: JSON Web Token and its family (JSON Web Signature, JSON Web Encrypt
112
140
  and JSON Web Key) in Ruby
113
141
  email:
114
142
  - nov@matake.jp
115
- executables: []
143
+ executables:
144
+ - console
116
145
  extensions: []
117
146
  extra_rdoc_files: []
118
147
  files:
148
+ - ".github/FUNDING.yml"
149
+ - ".github/workflows/test_ruby.yml"
119
150
  - ".gitignore"
120
151
  - ".gitmodules"
121
152
  - ".rspec"
@@ -125,12 +156,15 @@ files:
125
156
  - README.md
126
157
  - Rakefile
127
158
  - VERSION
159
+ - bin/console
128
160
  - json-jwt.gemspec
129
161
  - lib/json/jose.rb
130
162
  - lib/json/jwe.rb
131
163
  - lib/json/jwk.rb
132
164
  - lib/json/jwk/jwkizable.rb
133
165
  - lib/json/jwk/set.rb
166
+ - lib/json/jwk/set/fetcher.rb
167
+ - lib/json/jwk/set/fetcher/debugger/request_filter.rb
134
168
  - lib/json/jws.rb
135
169
  - lib/json/jwt.rb
136
170
  homepage: https://github.com/nov/json-jwt
@@ -145,14 +179,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
145
179
  requirements:
146
180
  - - ">="
147
181
  - !ruby/object:Gem::Version
148
- version: '2.3'
182
+ version: '2.4'
149
183
  required_rubygems_version: !ruby/object:Gem::Requirement
150
184
  requirements:
151
185
  - - ">="
152
186
  - !ruby/object:Gem::Version
153
187
  version: '0'
154
188
  requirements: []
155
- rubygems_version: 3.0.3
189
+ rubygems_version: 3.1.6
156
190
  signing_key:
157
191
  specification_version: 4
158
192
  summary: JSON Web Token and its family (JSON Web Signature, JSON Web Encryption and