jwt-authorizer 1.0.0 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 574e87e13f93a85345b4ed43bcb8263cd043c3eca38be8091ad36b8914fab552
4
- data.tar.gz: 896da83de80dbb5f670b096b5a7e7fcbf66fc1958eeaab44ca163c02e5c901c4
3
+ metadata.gz: c254092f30d5fb5f9d152e33ae49e915eb102cb831258ba231312e9204d36f24
4
+ data.tar.gz: 4ac378bd9ece18fc5cfd4243415b0e820d2c82a48180da5b012120499c60346d
5
5
  SHA512:
6
- metadata.gz: 75a902f8ebc415dae716e4cf83cc90b03df82de6e50b70941720222995c9d70eedb68e904863972f19df551f43073c383d4d79ec69b6e63bc62da6316da12609
7
- data.tar.gz: 0cadbcb705af0e7ef9e13ced3902f01bbbfeecf20792b06c7e2d5d449701c8d6f906ca9c99e7273f82b44d46dccf42969c723ff7cfc6b2655200630119ec8702
6
+ metadata.gz: '05694a5caddeef86498257f5768d4f57be2ccc6a41e638c93a5ec8ec7bc202a2d5ba7fa940e326ccaf360f9758f28bfa037d5ed402c820e6ec24c872cca71197'
7
+ data.tar.gz: f7689a3b2c287c79e2294eacbbd39a6dcb245272853065b0f3c3264b2d6105dc60cc4849005b7be488cce95cd5658683835d4126f8434131eee12f31a91d692b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 2.0.0
2
+ - Change the way public and private keys are configured, allowing checking JWT signatures against multiple public keys in RSA and ECDSA strategies
3
+
1
4
  ## 1.0.0
2
5
 
3
6
  - First release :fireworks:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jwt-authorizer (1.0.0)
4
+ jwt-authorizer (2.0.0)
5
5
  jwt (~> 2.1)
6
6
 
7
7
  GEM
@@ -10,20 +10,21 @@ GEM
10
10
  ast (2.4.0)
11
11
  coderay (1.1.2)
12
12
  diff-lcs (1.3)
13
- docile (1.1.5)
13
+ docile (1.3.1)
14
+ jaro_winkler (1.5.1)
14
15
  json (2.1.0)
15
16
  jwt (2.1.0)
16
17
  method_source (0.9.0)
17
18
  parallel (1.12.1)
18
- parser (2.5.0.2)
19
+ parser (2.5.1.0)
19
20
  ast (~> 2.4.0)
20
- powerpack (0.1.1)
21
+ powerpack (0.1.2)
21
22
  pry (0.11.3)
22
23
  coderay (~> 1.1.0)
23
24
  method_source (~> 0.9.0)
24
- rack (2.0.4)
25
+ rack (2.0.5)
25
26
  rainbow (3.0.0)
26
- rake (12.3.0)
27
+ rake (12.3.1)
27
28
  rspec (3.7.0)
28
29
  rspec-core (~> 3.7.0)
29
30
  rspec-expectations (~> 3.7.0)
@@ -37,7 +38,8 @@ GEM
37
38
  diff-lcs (>= 1.2.0, < 2.0)
38
39
  rspec-support (~> 3.7.0)
39
40
  rspec-support (3.7.1)
40
- rubocop (0.53.0)
41
+ rubocop (0.57.2)
42
+ jaro_winkler (~> 1.5.1)
41
43
  parallel (~> 1.10)
42
44
  parser (>= 2.5)
43
45
  powerpack (~> 0.1)
@@ -45,13 +47,13 @@ GEM
45
47
  ruby-progressbar (~> 1.7)
46
48
  unicode-display_width (~> 1.0, >= 1.0.1)
47
49
  ruby-progressbar (1.9.0)
48
- simplecov (0.15.1)
49
- docile (~> 1.1.0)
50
+ simplecov (0.16.1)
51
+ docile (~> 1.1)
50
52
  json (>= 1.8, < 3)
51
53
  simplecov-html (~> 0.10.0)
52
54
  simplecov-html (0.10.2)
53
55
  timecop (0.9.1)
54
- unicode-display_width (1.3.0)
56
+ unicode-display_width (1.4.0)
55
57
 
56
58
  PLATFORMS
57
59
  ruby
data/README.md CHANGED
@@ -32,14 +32,18 @@ JWT::Token.configuration
32
32
  JWT::Token.configure do |config|
33
33
  config.expiry = 12 * 60 * 60
34
34
  config.algorithm = "RS256"
35
- config.secret = { private_key: nil, public_key: ENV["SECRET_KEY"] }
35
+ config.rsa.authorized_keys = [OpenSSL::PKey::RSA.new(ENV["SECRET_KEY"])]
36
36
  end
37
37
  ```
38
38
 
39
39
  `JWT::Token` have following options available:
40
40
 
41
41
  * `algorithm` - determines algorithm used on signing and verifying JWT tokens. Defaults to `"HS256"`.
42
- * `secret` - for [`HMAC`](https://en.wikipedia.org/wiki/HMAC) algorithms it accepts simple `String` with symmetric key, for [`RSA`](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) and [`ECDSA`](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) it requires hash with `:private_key` and `:public_key` keys.
42
+ * `hmac` - [`HMAC`](https://en.wikipedia.org/wiki/HMAC) configuration:
43
+ - `hmac.key` - symmetric key used by HMAC algorithm
44
+ * `rsa` | `ecdsa` - [`RSA`](https://en.wikipedia.org/wiki/RSA_(cryptosystem)) and [`ECDSA`](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) configuration:
45
+ - `rsa.authorized_keys` | `ecdsa.authorized_keys` - `Array` of `OpenSSL::PKey::PKey` objects with allowed public keys
46
+ - `rsa.authorized_keys_file` | `ecdsa.authorized_keys_file` - path to file containing authorized public keys in PEM format
43
47
  * `expiry` - sets default expiry for generated tokens. Defaults to 1 hour. It can be set to `nil` in order to not include `exp` claim in the token
44
48
  * `issuer` - sets `iss` claim in the token. Defaults to `nil`.
45
49
  * `allowed_issuers` - array of issuers that will be allowed on token verification. Defaults to empty array, tokens with any value in `iss` claim (and without this claim) will be valid. If array contains any elements, *only* listed issuers will be valid.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module JWT
4
4
  module Authorizer
5
- VERSION = "1.0.0"
5
+ VERSION = "2.0.0"
6
6
  end
7
7
  end
@@ -3,7 +3,10 @@
3
3
  require "jwt/authorizer/version"
4
4
  require "jwt"
5
5
 
6
+ require "jwt/token/asymmetric_key_configuration"
6
7
  require "jwt/token/builder"
8
+ require "jwt/token/hmac_configuration"
9
+ require "jwt/token/configuration"
7
10
  require "jwt/token/configuration"
8
11
  require "jwt/token/configurable"
9
12
  require "jwt/token/verifier"
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ class Token
5
+ class AsymmetricKeyConfiguration
6
+ class PublicKeySet
7
+ def initialize(keys)
8
+ @keys = keys
9
+ end
10
+
11
+ def verify(digest, signature, data)
12
+ @keys.any? { |key| key.verify(digest, signature, data) }
13
+ end
14
+ end
15
+
16
+ attr_accessor :authorized_keys, :private_key
17
+
18
+ def initialize(key_class)
19
+ @key_class = key_class
20
+ end
21
+
22
+ def authorized_keys_file=(file_path)
23
+ self.authorized_keys =
24
+ File.read(file_path)
25
+ .each_line("-----END PUBLIC KEY-----\n")
26
+ .map { |pem| @key_class.new(pem) }
27
+ end
28
+
29
+ def public_key
30
+ PublicKeySet.new(authorized_keys) if authorized_keys
31
+ end
32
+
33
+ def freeze
34
+ super
35
+ authorized_keys&.freeze
36
+ authorized_keys&.map(&:freeze)
37
+ end
38
+
39
+ def dup
40
+ super.tap do |new_config|
41
+ new_config.instance_variable_set("@private_key", private_key.dup)
42
+ new_config.instance_variable_set("@authorized_keys", authorized_keys&.map(&:dup))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -8,7 +8,7 @@ module JWT
8
8
  end
9
9
 
10
10
  def to_jwt
11
- JWT.encode claims.compact, secret[:private], algorithm
11
+ JWT.encode claims.compact, private_key, algorithm
12
12
  end; alias to_s to_jwt
13
13
  end
14
14
  end
@@ -6,7 +6,7 @@ module JWT
6
6
  def self.included(base)
7
7
  base.extend(ClassMethods)
8
8
  base.extend(Forwardable)
9
- base.delegate %i[algorithm secret allowed_issuers] => "self.class.configuration"
9
+ base.delegate %i[algorithm private_key allowed_issuers] => "self.class.configuration"
10
10
  end
11
11
 
12
12
  module ClassMethods
@@ -3,7 +3,7 @@
3
3
  module JWT
4
4
  class Token
5
5
  class Configuration
6
- ATTRIBUTES = %i[algorithm secret expiry issuer allowed_issuers].freeze
6
+ ATTRIBUTES = %i[algorithm hmac rsa ecdsa expiry issuer allowed_issuers allowed_algorithms].freeze
7
7
 
8
8
  ALGORITHMS = {
9
9
  "HS256" => :hmac, "HS512256" => :hmac, "HS384" => :hmac, "HS512" => :hmac,
@@ -15,29 +15,28 @@ module JWT
15
15
  @algorithm = "HS256"
16
16
  @expiry = 60 * 60
17
17
  @allowed_issuers = []
18
+ @allowed_algorithms = ["HS256"]
19
+ @hmac = HMACConfiguration.new
20
+ @rsa = AsymmetricKeyConfiguration.new(OpenSSL::PKey::RSA)
21
+ @ecdsa = AsymmetricKeyConfiguration.new(OpenSSL::PKey::EC)
18
22
  end
19
23
 
20
- attr_accessor :expiry, :allowed_issuers, :issuer
21
- attr_reader :secret, :algorithm
24
+ attr_accessor :expiry, :allowed_issuers, :allowed_algorithms, :issuer
25
+ attr_reader :algorithm, :hmac, :rsa, :ecdsa
22
26
 
23
27
  def algorithm=(value)
24
28
  assert_algorithm_valid(value)
25
29
  @algorithm = value.to_s
26
30
  end
27
31
 
28
- def secret=(hmac_key = nil, private_key: nil, public_key: nil)
29
- @secret = case algorithm_type
30
- when :hmac
31
- { private: hmac_key, public: hmac_key }
32
- else
33
- { private: private_key, public: public_key }
34
- end
35
- end
36
-
37
32
  def algorithm_type
38
33
  ALGORITHMS[algorithm]
39
34
  end
40
35
 
36
+ def private_key
37
+ send(algorithm_type).private_key
38
+ end
39
+
41
40
  def to_h
42
41
  ATTRIBUTES.each_with_object({}) { |attribute, hash| hash[attribute] = send(attribute) }
43
42
  end
@@ -47,7 +46,11 @@ module JWT
47
46
  raise ArgumentError, "Unpermitted options: #{unpermitted_options.join(', ')}" if unpermitted_options.any?
48
47
 
49
48
  options.each do |key, value|
50
- send("#{key}=", value)
49
+ if value.is_a?(Hash)
50
+ send(key).tap { |option| value.each { |suboption, subvalue| option.send("#{suboption}=", subvalue) } }
51
+ else
52
+ send("#{key}=", value)
53
+ end
51
54
  end
52
55
 
53
56
  self
@@ -55,15 +58,15 @@ module JWT
55
58
 
56
59
  def dup
57
60
  super.tap do |new_config|
58
- new_config.instance_variable_set("@allowed_issuers", allowed_issuers.dup)
59
- new_config.instance_variable_set("@secret", secret.dup)
61
+ %i[allowed_issuers allowed_algorithms hmac rsa ecdsa].each do |option|
62
+ new_config.instance_variable_set("@#{option}", send(option).dup)
63
+ end
60
64
  end
61
65
  end
62
66
 
63
67
  def freeze
64
68
  super
65
- allowed_issuers.freeze
66
- secret.freeze
69
+ [allowed_issuers, allowed_algorithms, hmac, rsa, ecdsa].each(&:freeze)
67
70
  end
68
71
 
69
72
  private
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JWT
4
+ class Token
5
+ class HMACConfiguration
6
+ attr_accessor :key
7
+ alias public_key key
8
+ alias private_key key
9
+
10
+ def dup
11
+ super.tap do |new_config|
12
+ new_config.instance_variable_set("@key", key.dup)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -10,7 +10,10 @@ module JWT
10
10
 
11
11
  module ClassMethods
12
12
  def verify(jwt_token, context = nil)
13
- decoded = JWT.decode(jwt_token, configuration.secret[:public], true, decode_options)
13
+ decoded = JWT.decode(jwt_token, nil, true, decode_options) do |header|
14
+ algorithm_type = JWT::Token::Configuration::ALGORITHMS[header["alg"]]
15
+ configuration.send(algorithm_type).public_key if algorithm_type
16
+ end
14
17
 
15
18
  new(decoded[0]).tap do |token|
16
19
  claims.each do |claim|
@@ -22,12 +25,8 @@ module JWT
22
25
  private
23
26
 
24
27
  def decode_options
25
- {}.tap do |result|
26
- if configuration.allowed_issuers.any?
27
- result[:iss] = configuration.allowed_issuers
28
- result[:verify_iss] = true
29
- end
30
- result[:algorithm] = configuration.algorithm
28
+ { algorithms: configuration.allowed_algorithms }.tap do |result|
29
+ result.merge!(iss: configuration.allowed_issuers, verify_iss: true) if configuration.allowed_issuers.any?
31
30
  end
32
31
  end
33
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jwt-authorizer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michał Begejowicz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-08 00:00:00.000000000 Z
11
+ date: 2018-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jwt
@@ -162,12 +162,14 @@ files:
162
162
  - lib/jwt/authorizer/version.rb
163
163
  - lib/jwt/endpoint_token.rb
164
164
  - lib/jwt/token.rb
165
+ - lib/jwt/token/asymmetric_key_configuration.rb
165
166
  - lib/jwt/token/builder.rb
166
167
  - lib/jwt/token/claim.rb
167
168
  - lib/jwt/token/claim_builder.rb
168
169
  - lib/jwt/token/configurable.rb
169
170
  - lib/jwt/token/configuration.rb
170
171
  - lib/jwt/token/default_claims.rb
172
+ - lib/jwt/token/hmac_configuration.rb
171
173
  - lib/jwt/token/verifier.rb
172
174
  homepage: https://github.com/codesthq/jwt-authorizer
173
175
  licenses:
@@ -189,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
191
  version: '0'
190
192
  requirements: []
191
193
  rubyforge_project:
192
- rubygems_version: 2.7.3
194
+ rubygems_version: 2.7.6
193
195
  signing_key:
194
196
  specification_version: 4
195
197
  summary: Authorization of requests for microservices based on JWT