jwt-multisig 1.0.0.beta.2 → 1.0.4
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/.drone.yml +29 -0
- data/.ruby-version +1 -1
- data/.travis.yml +2 -4
- data/Gemfile.lock +18 -16
- data/Rakefile +2 -0
- data/jwt-multisig.gemspec +3 -3
- data/lib/jwt-multisig.rb +17 -13
- data/lib/jwt-multisig/version.rb +1 -1
- data/test/test-jws-verificator.rb +3 -2
- data/test/test-jwt-verificator.rb +9 -0
- metadata +11 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5edf239b75b41453236a1d170ab81b6233ab334df41805c916ebc0c89a28a1e6
|
4
|
+
data.tar.gz: 3d634939c51b36d78feab51e9d71275feca0386e7f31a8927dac6085ff3c461c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91988aafe86882352b806addea59a6390140d2e258817507783bbf5c2addda3cdb028d821a771179568b9bbb461ac04432d1e384472f0894a45b97dc396477c2
|
7
|
+
data.tar.gz: 99c553c60a72d97233de4012e06a7a1a12ffb8e5f7eef1cd5fab16c801781f31d606954d84ee27440fbe1b4c61020b9f1e3d92472120c5403818dc6d36cca069
|
data/.drone.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
---
|
2
|
+
kind: pipeline
|
3
|
+
name: default
|
4
|
+
|
5
|
+
steps:
|
6
|
+
- name: Run tests
|
7
|
+
image: ruby:2.6
|
8
|
+
commands:
|
9
|
+
- bundle install
|
10
|
+
- bundle exec rake test
|
11
|
+
|
12
|
+
- name: Release gems
|
13
|
+
image: ruby:2.6
|
14
|
+
environment:
|
15
|
+
GEM_CREDENTIALS:
|
16
|
+
from_secret: gem_credentials
|
17
|
+
commands:
|
18
|
+
- mkdir -p ~/.gem
|
19
|
+
- echo $GEM_CREDENTIALS | base64 -d > ~/.gem/credentials
|
20
|
+
- chmod 0600 ~/.gem/credentials
|
21
|
+
- gem build jwt-multisig.gemspec
|
22
|
+
- gem push jwt-multisig-*.gem
|
23
|
+
when:
|
24
|
+
branch:
|
25
|
+
- master
|
26
|
+
|
27
|
+
trigger:
|
28
|
+
event:
|
29
|
+
- push
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.3
|
data/.travis.yml
CHANGED
@@ -3,16 +3,14 @@ language: ruby
|
|
3
3
|
cache: bundler
|
4
4
|
|
5
5
|
rvm:
|
6
|
-
- 2.2
|
7
|
-
- 2.3
|
8
|
-
- 2.4
|
9
6
|
- 2.5
|
7
|
+
- 2.6
|
10
8
|
|
11
9
|
env:
|
12
10
|
- RAKE_ENV=test BUNDLE_PATH=vendor/bundle
|
13
11
|
|
14
12
|
before_install:
|
15
|
-
- gem install bundler
|
13
|
+
- gem install bundler -v 1.17.3
|
16
14
|
|
17
15
|
install:
|
18
16
|
- bundle install
|
data/Gemfile.lock
CHANGED
@@ -1,41 +1,43 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
jwt-multisig (1.0.
|
5
|
-
activesupport (>= 4.0
|
6
|
-
jwt (~> 2.
|
4
|
+
jwt-multisig (1.0.4)
|
5
|
+
activesupport (>= 4.0)
|
6
|
+
jwt (~> 2.2)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activesupport (
|
11
|
+
activesupport (6.0.3.4)
|
12
12
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
13
|
-
i18n (
|
13
|
+
i18n (>= 0.7, < 2)
|
14
14
|
minitest (~> 5.1)
|
15
15
|
tzinfo (~> 1.1)
|
16
|
-
|
17
|
-
|
16
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
17
|
+
concurrent-ruby (1.1.7)
|
18
|
+
i18n (1.8.5)
|
18
19
|
concurrent-ruby (~> 1.0)
|
19
|
-
jwt (2.
|
20
|
-
memoist (0.16.
|
21
|
-
minitest (5.
|
22
|
-
power_assert (1.
|
23
|
-
rake (12.3.
|
24
|
-
test-unit (3.
|
20
|
+
jwt (2.2.2)
|
21
|
+
memoist (0.16.2)
|
22
|
+
minitest (5.14.2)
|
23
|
+
power_assert (1.2.0)
|
24
|
+
rake (12.3.3)
|
25
|
+
test-unit (3.3.6)
|
25
26
|
power_assert
|
26
27
|
thread_safe (0.3.6)
|
27
|
-
tzinfo (1.2.
|
28
|
+
tzinfo (1.2.7)
|
28
29
|
thread_safe (~> 0.1)
|
30
|
+
zeitwerk (2.4.0)
|
29
31
|
|
30
32
|
PLATFORMS
|
31
33
|
ruby
|
32
34
|
|
33
35
|
DEPENDENCIES
|
34
|
-
bundler (~> 1.
|
36
|
+
bundler (~> 1.17)
|
35
37
|
jwt-multisig!
|
36
38
|
memoist (~> 0.16)
|
37
39
|
rake (~> 12.3)
|
38
40
|
test-unit (~> 3.1)
|
39
41
|
|
40
42
|
BUNDLED WITH
|
41
|
-
1.
|
43
|
+
1.17.3
|
data/Rakefile
CHANGED
data/jwt-multisig.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.test_files = `git ls-files -z -- {test,spec,features}/*`.split("\x0")
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
|
20
|
-
s.add_dependency "jwt", "~> 2.
|
21
|
-
s.add_dependency "activesupport", ">= 4.0"
|
22
|
-
s.add_development_dependency "bundler", "~> 1.
|
20
|
+
s.add_dependency "jwt", "~> 2.2"
|
21
|
+
s.add_dependency "activesupport", ">= 4.0"
|
22
|
+
s.add_development_dependency "bundler", "~> 1.17"
|
23
23
|
end
|
data/lib/jwt-multisig.rb
CHANGED
@@ -5,6 +5,7 @@ require "jwt"
|
|
5
5
|
require "openssl"
|
6
6
|
require "active_support/core_ext/hash/keys"
|
7
7
|
require "active_support/core_ext/hash/slice"
|
8
|
+
require "active_support/core_ext/hash/indifferent_access"
|
8
9
|
|
9
10
|
module JWT
|
10
11
|
#
|
@@ -39,8 +40,11 @@ module JWT
|
|
39
40
|
# @raise [JWT::EncodeError]
|
40
41
|
def generate_jwt(payload, private_keychain, algorithms)
|
41
42
|
proxy_exception JWT::EncodeError do
|
43
|
+
algorithms_mapping = algorithms.with_indifferent_access
|
42
44
|
{ payload: base64_encode(payload.to_json),
|
43
|
-
signatures: private_keychain.map
|
45
|
+
signatures: private_keychain.map do |id, value|
|
46
|
+
generate_jws(payload, id, value, algorithms_mapping.fetch(id))
|
47
|
+
end }
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -112,12 +116,14 @@ module JWT
|
|
112
116
|
# The returning value contains payload, list of verified, and unverified signatures (key ID).
|
113
117
|
# Example:
|
114
118
|
# { payload: { sub: "session", profile: { email: "username@mailbox.example" },
|
115
|
-
# verified: ["backend-1.mycompany.example", "backend-3.mycompany.example"],
|
116
|
-
# unverified: ["backend-2.mycompany.example"] }
|
119
|
+
# verified: [:"backend-1.mycompany.example", :"backend-3.mycompany.example"],
|
120
|
+
# unverified: [:"backend-2.mycompany.example"] }
|
117
121
|
# }
|
118
122
|
# @raise [JWT::DecodeError]
|
119
123
|
def verify_jwt(jwt, public_keychain, options = {})
|
120
124
|
proxy_exception JWT::DecodeError do
|
125
|
+
keychain = public_keychain.with_indifferent_access
|
126
|
+
encoded_payload = jwt.fetch("payload")
|
121
127
|
serialized_payload = base64_decode(jwt.fetch("payload"))
|
122
128
|
payload = JSON.parse(serialized_payload)
|
123
129
|
verified = []
|
@@ -125,16 +131,16 @@ module JWT
|
|
125
131
|
|
126
132
|
jwt.fetch("signatures").each do |jws|
|
127
133
|
key_id = jws.fetch("header").fetch("kid")
|
128
|
-
if
|
129
|
-
verify_jws(jws,
|
134
|
+
if keychain.key?(key_id)
|
135
|
+
verify_jws(jws, encoded_payload, public_keychain, options)
|
130
136
|
verified << key_id
|
131
137
|
else
|
132
138
|
unverified << key_id
|
133
139
|
end
|
134
140
|
end
|
135
141
|
{ payload: payload.deep_symbolize_keys,
|
136
|
-
verified: verified.uniq,
|
137
|
-
unverified: unverified.uniq }
|
142
|
+
verified: verified.uniq.map(&:to_sym),
|
143
|
+
unverified: unverified.uniq.map(&:to_sym) }
|
138
144
|
end
|
139
145
|
end
|
140
146
|
|
@@ -188,14 +194,12 @@ module JWT
|
|
188
194
|
# @return [Hash]
|
189
195
|
# Returns payload if signature is valid.
|
190
196
|
# @raise [JWT::DecodeError]
|
191
|
-
def verify_jws(jws,
|
197
|
+
def verify_jws(jws, encoded_payload, public_keychain, options = {})
|
192
198
|
proxy_exception JWT::DecodeError do
|
193
199
|
encoded_header = jws.fetch("protected")
|
194
200
|
serialized_header = base64_decode(encoded_header)
|
195
|
-
serialized_payload = payload.to_json
|
196
|
-
encoded_payload = base64_encode(serialized_payload)
|
197
201
|
signature = jws.fetch("signature")
|
198
|
-
public_key = public_keychain.fetch(jws.fetch("header").fetch("kid"))
|
202
|
+
public_key = public_keychain.with_indifferent_access.fetch(jws.fetch("header").fetch("kid"))
|
199
203
|
jwt = [encoded_header, encoded_payload, signature].join(".")
|
200
204
|
algorithm = JSON.parse(serialized_header).fetch("alg")
|
201
205
|
JWT.decode(jwt, to_pem_or_key(public_key, algorithm), true, options.merge(algorithms: [algorithm])).first
|
@@ -235,7 +239,7 @@ module JWT
|
|
235
239
|
# @param string [String]
|
236
240
|
# @return [String]
|
237
241
|
def base64_encode(string)
|
238
|
-
JWT::
|
242
|
+
JWT::Base64.url_encode(string)
|
239
243
|
end
|
240
244
|
|
241
245
|
#
|
@@ -244,7 +248,7 @@ module JWT
|
|
244
248
|
# @param string [String]
|
245
249
|
# @return [String]
|
246
250
|
def base64_decode(string)
|
247
|
-
JWT::
|
251
|
+
JWT::Base64.url_decode(string)
|
248
252
|
end
|
249
253
|
end
|
250
254
|
end
|
data/lib/jwt-multisig/version.rb
CHANGED
@@ -74,12 +74,13 @@ class JWSVerificatorTest < Test::Unit::TestCase
|
|
74
74
|
private
|
75
75
|
|
76
76
|
def example(jws, payload, options, expected)
|
77
|
+
encoded_payload = JWT::Base64.url_encode(JSON.dump(payload))
|
77
78
|
# Pass instance of OpenSSL::PKey::PKey.
|
78
|
-
returned = JWT::Multisig.verify_jws(JSON.parse(jws),
|
79
|
+
returned = JWT::Multisig.verify_jws(JSON.parse(jws), encoded_payload, public_keychain, options)
|
79
80
|
assert_equal expected, JSON.dump(returned)
|
80
81
|
|
81
82
|
# Pass key in PEM format.
|
82
|
-
returned = JWT::Multisig.verify_jws(JSON.parse(jws),
|
83
|
+
returned = JWT::Multisig.verify_jws(JSON.parse(jws), encoded_payload, public_keychain, options)
|
83
84
|
assert_equal expected, JSON.dump(returned)
|
84
85
|
end
|
85
86
|
end
|
@@ -31,6 +31,15 @@ class JWTVerificatorTest < Test::Unit::TestCase
|
|
31
31
|
example jwt, {}, {}, %({"payload":{"xxx":"zzz"},"verified":[],"unverified":["hoegerrenner.info","powlowski.info"]})
|
32
32
|
end
|
33
33
|
|
34
|
+
def test_both_symbols_and_strings_are_supported
|
35
|
+
jwt = %({"payload":"eyJpc3MiOiJmb28iLCJiYXIiOnsiYmF6IjoicXV4In19","signatures":[{"protected":"eyJhbGciOiJIUzUxMiJ9","header":{"kid":"ebert.biz"},"signature":"1koPnSwejNF5aCRsqlySX9Td7_gc-dfUkko5G0Svccw-WkBYrwoJJwRJ2Op_-OxjoqSe3ViBGGCbgVUz0khuJQ"},{"protected":"eyJhbGciOiJIUzI1NiJ9","header":{"kid":"wisoky.co"},"signature":"AqtFKTlaVDqg2dOfLBODMhcBlg1gm9ejn6hYQynTyto"},{"protected":"eyJhbGciOiJSUzM4NCJ9","header":{"kid":"hoegerrenner.info"},"signature":"LR9TpJTLwgducdCkN1KmfwXXxd3pp7Xe5fJXJZZM8FVrFrVOEAGQcPnMPIgfPA1UckIXnzih46j4qPOQdotVHEvYvUuvLLT8QQi8y6-vBMlsP-cQehKGpI1T4N5qPzvJqPmhVzZYedWzlvr-VV9wd0BYeBgr65m9BSpFjLFhWVH4NJZuHFPxeYuDEpYoM-lPHdTzdf1E8xd_xwbpz9WpNh0MQib387-wakGWz-UGt9BmJLU8KV01FTAoR0EO9rQfIm5HQ3wGQ7t8U4N4HsOmsXkWF_fRgxjhMHeChDES2awwB4G4KCNw-6ezSBCD7FZcxzbCL2657OEPHNuHA36M91j54jjm1tweYhYJxuUOk5c8j_wSxtieeaORCxOrPp3mshHS_FE0sI_TNNBsIDI_sQwiS08y3d6tv7H4a_MZj_Pe7JWJ3TXlcsaSHy3xuSLYxCZQeLBwJtyz2ERCZOA9ew0BY34tpRwDKxbgF51X7t7uilYxnBn2rBdQeWQKb9q2"}]})
|
36
|
+
keychain = {
|
37
|
+
"hoegerrenner.info": public_keychain["hoegerrenner.info"],
|
38
|
+
"wisoky.co": public_keychain["wisoky.co"],
|
39
|
+
"ebert.biz" => public_keychain["ebert.biz"] }
|
40
|
+
example jwt, keychain, { iss: "foo" }, %({"payload":{"iss":"foo","bar":{"baz":"qux"}},"verified":["ebert.biz","wisoky.co","hoegerrenner.info"],"unverified":[]})
|
41
|
+
end
|
42
|
+
|
34
43
|
private
|
35
44
|
|
36
45
|
def example(jwt, keychain, options, expected)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jwt-multisig
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- RubyKube
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jwt
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '2.
|
19
|
+
version: '2.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '2.
|
26
|
+
version: '2.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activesupport
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -31,9 +31,6 @@ dependencies:
|
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '4.0'
|
34
|
-
- - "<"
|
35
|
-
- !ruby/object:Gem::Version
|
36
|
-
version: '6.0'
|
37
34
|
type: :runtime
|
38
35
|
prerelease: false
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -41,23 +38,20 @@ dependencies:
|
|
41
38
|
- - ">="
|
42
39
|
- !ruby/object:Gem::Version
|
43
40
|
version: '4.0'
|
44
|
-
- - "<"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '6.0'
|
47
41
|
- !ruby/object:Gem::Dependency
|
48
42
|
name: bundler
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
50
44
|
requirements:
|
51
45
|
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
53
|
-
version: '1.
|
47
|
+
version: '1.17'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
51
|
requirements:
|
58
52
|
- - "~>"
|
59
53
|
- !ruby/object:Gem::Version
|
60
|
-
version: '1.
|
54
|
+
version: '1.17'
|
61
55
|
description: The tool for working with JWT signed by multiple verificators as per
|
62
56
|
RFC 7515. Based on the RubyGem «jwt» under the hood.
|
63
57
|
email: support@rubykube.io
|
@@ -65,6 +59,7 @@ executables: []
|
|
65
59
|
extensions: []
|
66
60
|
extra_rdoc_files: []
|
67
61
|
files:
|
62
|
+
- ".drone.yml"
|
68
63
|
- ".gitignore"
|
69
64
|
- ".rubocop.yml"
|
70
65
|
- ".ruby-version"
|
@@ -98,19 +93,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
93
|
version: '0'
|
99
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
95
|
requirements:
|
101
|
-
- - "
|
96
|
+
- - ">="
|
102
97
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
98
|
+
version: '0'
|
104
99
|
requirements: []
|
105
|
-
|
106
|
-
rubygems_version: 2.7.3
|
100
|
+
rubygems_version: 3.0.3
|
107
101
|
signing_key:
|
108
102
|
specification_version: 4
|
109
103
|
summary: The tool for working with multi-signature JWT.
|
110
|
-
test_files:
|
111
|
-
- test/test-helper.rb
|
112
|
-
- test/test-jws-generator.rb
|
113
|
-
- test/test-jws-verificator.rb
|
114
|
-
- test/test-jwt-editor.rb
|
115
|
-
- test/test-jwt-generator.rb
|
116
|
-
- test/test-jwt-verificator.rb
|
104
|
+
test_files: []
|