jwt-authorizer 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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