zaikio-jwt_auth 1.0.1 → 2.1.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: 4103bf1e59a9fa8a68a868c33d785082993255fe24616a01c1113a5a8026dcfe
4
- data.tar.gz: e0be8641749a07f97620c73a56a97211ba51e9fe4f9dc6e1bdbaa5dd0422b0e3
3
+ metadata.gz: e030f7e4c7f0be8b37a722ff691b7bf1398cd31ca449b41a9923b51f5a008df8
4
+ data.tar.gz: 13a0d7a174af3ca58772b116e22d2fcc893291d59010ce127df82f1dca77ea5c
5
5
  SHA512:
6
- metadata.gz: 28c8d6ea0b394450f7ae0027e9388fca1a9bd449213b6825356c65452e8a3efa4ab670802537cf9e08146d8a6980b5cbb22f2efa5cdec4c4b271b4c02b759fcf
7
- data.tar.gz: 647aa957f6e7d82ca26b50169fd265b30e144dcef5a26a8273e786c388569ac09babed909a1ddf295255df404f097bc5a867ff5520920d81f37ae4a48a5c60da
6
+ metadata.gz: c91befdc7f28018a2e19bcafdcbd805ef87467a6fde8fc1b4899b6c6a327a6a89327902f84bdd07f42749c265535cdc3b83bd6289e958fcd2b4d520e46462d94
7
+ data.tar.gz: aa56620ee2936346ef5b6d73ff0e8189ad8cc46d7ab44ca36783ad744f577513fb4786fa48023f4918491b04f166d9f0db5b66ef8b9f9a7d6ee04a315938bde7
data/README.md CHANGED
@@ -28,7 +28,9 @@ $ gem install zaikio-jwt_auth
28
28
  Zaikio::JWTAuth.configure do |config|
29
29
  config.environment = :sandbox # or production
30
30
  config.app_name = "test_app" # Your Zaikio App-Name
31
- config.redis = Redis.new
31
+
32
+ # Enable caching Hub API responses for e.g. revoked tokens
33
+ config.cache = Rails.cache
32
34
  end
33
35
  ```
34
36
 
@@ -63,6 +65,24 @@ end
63
65
 
64
66
  By convention, `authorize_by_jwt_scopes` automatically maps all CRUD actions in a controller. Requests for `show` and `index` with a read or read_write scope are allowed. All other actions like `create`, `update` and `destroy` are accepted if the scope is a write or read_write scope. Therefore it is strongly recommended to always create standard Rails resources. If a custom action is required, you will need to authorize yourself using the `after_jwt_auth`.
65
67
 
68
+ Both of these behaviours are automatically inherited by child classes, for example:
69
+
70
+ ```ruby
71
+ class API::ChildController < API::ResourcesController
72
+ end
73
+
74
+ API::ChildController.authorize_by_jwt_subject_type
75
+ #=> "Organization"
76
+ ```
77
+
78
+ You can always override the behaviour in children if needed:
79
+
80
+ ```ruby
81
+ class API::ChildController < API::ResourcesController
82
+ authorize_by_jwt_subject_type nil
83
+ end
84
+ ```
85
+
66
86
  #### Modifying required scopes
67
87
  If you nonetheless want to change the required scopes for CRUD routes, you can use the `type` option which accepts the following values: `:read`, `:write`, `:read_write`
68
88
 
@@ -165,6 +185,25 @@ rescue JWT::DecodeError, JWT::ExpiredSignature
165
185
  end
166
186
  ```
167
187
 
188
+ ### Using a different cache backend
189
+
190
+ This client supports any implementation of
191
+ [`ActiveSupport::Cache::Store`](https://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html),
192
+ but you can also write your own client that supports these methods: `#read(key)`,
193
+ `#write(key, value)`, `#delete(key)`
194
+
195
+ ### Pass custom options to JWT auth
196
+
197
+ In some cases you want to add custom options to the JWT check. For example you want to allow expired JWTs when revoking access tokens.
198
+
199
+ ```rb
200
+ class API::RevokedAccessTokensController < API::ApplicationController
201
+ def jwt_options
202
+ { verify_expiration: false }
203
+ end
204
+ end
205
+ ```
206
+
168
207
  ## Contributing
169
208
 
170
209
  **Make sure you have the dummy app running locally to validate your changes.**
@@ -11,7 +11,7 @@ module Zaikio
11
11
  production: "https://hub.zaikio.com"
12
12
  }.freeze
13
13
 
14
- attr_accessor :app_name, :redis, :host
14
+ attr_accessor :app_name, :cache, :host
15
15
  attr_reader :environment
16
16
  attr_writer :logger, :revoked_token_ids, :keys
17
17
 
@@ -16,7 +16,7 @@ module Zaikio
16
16
 
17
17
  class << self
18
18
  def fetch(directory_path, options = {})
19
- cache = Zaikio::JWTAuth.configuration.redis.get("zaikio::jwt_auth::#{directory_path}")
19
+ cache = Zaikio::JWTAuth.configuration.cache.read("zaikio::jwt_auth::#{directory_path}")
20
20
 
21
21
  json = Oj.load(cache) if cache
22
22
 
@@ -31,14 +31,14 @@ module Zaikio
31
31
  def update(directory_path, options = {})
32
32
  data = fetch(directory_path, options)
33
33
  data = yield(data)
34
- Zaikio::JWTAuth.configuration.redis.set("zaikio::jwt_auth::#{directory_path}", {
34
+ Zaikio::JWTAuth.configuration.cache.write("zaikio::jwt_auth::#{directory_path}", {
35
35
  fetched_at: Time.now.to_i,
36
36
  data: data
37
37
  }.to_json)
38
38
  end
39
39
 
40
40
  def reset(directory_path)
41
- Zaikio::JWTAuth.configuration.redis.del("zaikio::jwt_auth::#{directory_path}")
41
+ Zaikio::JWTAuth.configuration.cache.delete("zaikio::jwt_auth::#{directory_path}")
42
42
  end
43
43
 
44
44
  private
@@ -49,28 +49,34 @@ module Zaikio
49
49
 
50
50
  def reload_or_enqueue(directory_path)
51
51
  data = fetch_from_directory(directory_path)
52
- Zaikio::JWTAuth.configuration.redis.set("zaikio::jwt_auth::#{directory_path}", {
52
+ Zaikio::JWTAuth.configuration.cache.write("zaikio::jwt_auth::#{directory_path}", {
53
53
  fetched_at: Time.now.to_i,
54
54
  data: data
55
55
  }.to_json)
56
56
 
57
57
  data
58
58
  rescue Errno::ECONNREFUSED, Net::ReadTimeout, BadResponseError
59
- Zaikio::JWTAuth.configuration.logger.info("Error updating DirectoryCache(#{directory_path}), enqueueing job to update")
59
+ Zaikio::JWTAuth.configuration.logger
60
+ .info("Error updating DirectoryCache(#{directory_path}), enqueueing job to update")
60
61
  UpdateJob.set(wait: 10.seconds).perform_later(directory_path)
61
62
  nil
62
63
  end
63
64
 
64
65
  def fetch_from_directory(directory_path)
65
- uri = URI("#{Zaikio::JWTAuth.configuration.host}/#{directory_path}")
66
- http = Net::HTTP.new(uri.host, uri.port)
67
- http.use_ssl = uri.scheme == "https"
68
- response = http.request(Net::HTTP::Get.new(uri.request_uri))
66
+ response = make_http_request(directory_path)
67
+
69
68
  raise BadResponseError unless (200..299).cover?(response.code.to_i)
70
69
  raise BadResponseError unless response["content-type"].to_s.include?("application/json")
71
70
 
72
71
  Oj.load(response.body)
73
72
  end
73
+
74
+ def make_http_request(directory_path)
75
+ uri = URI("#{Zaikio::JWTAuth.configuration.host}/#{directory_path}")
76
+ http = Net::HTTP.new(uri.host, uri.port)
77
+ http.use_ssl = uri.scheme == "https"
78
+ http.request(Net::HTTP::Get.new(uri.request_uri))
79
+ end
74
80
  end
75
81
  end
76
82
  end
@@ -1,5 +1,5 @@
1
1
  module Zaikio
2
2
  module JWTAuth
3
- VERSION = "1.0.1".freeze
3
+ VERSION = "2.1.0".freeze
4
4
  end
5
5
  end
@@ -45,7 +45,7 @@ module Zaikio
45
45
  end
46
46
 
47
47
  def self.mocked_jwt_payload
48
- @mocked_jwt_payload
48
+ instance_variable_defined?(:@mocked_jwt_payload) && @mocked_jwt_payload
49
49
  end
50
50
 
51
51
  def self.mocked_jwt_payload=(payload)
@@ -54,21 +54,27 @@ module Zaikio
54
54
 
55
55
  HEADER_FORMAT = /\ABearer (.+)\z/.freeze
56
56
 
57
- def self.extract(authorization_header_string)
57
+ def self.extract(authorization_header_string, **options)
58
58
  return TokenData.new(Zaikio::JWTAuth.mocked_jwt_payload) if Zaikio::JWTAuth.mocked_jwt_payload
59
59
 
60
60
  return if authorization_header_string.blank?
61
61
 
62
62
  return unless (token = authorization_header_string[HEADER_FORMAT, 1])
63
63
 
64
- payload, = JWT.decode(token, nil, true, algorithms: ["RS256"], jwks: JWK.loader)
64
+ options.reverse_merge!(algorithms: ["RS256"], jwks: JWK.loader)
65
+
66
+ payload, = JWT.decode(token, nil, true, **options)
65
67
 
66
68
  TokenData.new(payload)
67
69
  end
68
70
 
69
71
  module ClassMethods
70
- def authorize_by_jwt_subject_type(type = nil)
71
- @authorize_by_jwt_subject_type ||= type
72
+ def authorize_by_jwt_subject_type(type = :_not_given_)
73
+ if type != :_not_given_
74
+ @authorize_by_jwt_subject_type = type
75
+ elsif instance_variable_defined?(:@authorize_by_jwt_subject_type)
76
+ @authorize_by_jwt_subject_type
77
+ end
72
78
  end
73
79
 
74
80
  def authorize_by_jwt_scopes(scopes = nil, options = {})
@@ -78,11 +84,18 @@ module Zaikio
78
84
 
79
85
  @authorize_by_jwt_scopes
80
86
  end
87
+
88
+ def inherited(child)
89
+ super(child)
90
+
91
+ child.instance_variable_set(:@authorize_by_jwt_subject_type, @authorize_by_jwt_subject_type)
92
+ child.instance_variable_set(:@authorize_by_jwt_scopes, @authorize_by_jwt_scopes)
93
+ end
81
94
  end
82
95
 
83
96
  module InstanceMethods
84
97
  def authenticate_by_jwt
85
- token_data = Zaikio::JWTAuth.extract(request.headers["Authorization"])
98
+ token_data = Zaikio::JWTAuth.extract(request.headers["Authorization"], **jwt_options)
86
99
  return render_error("no_jwt_passed", status: :unauthorized) unless token_data
87
100
 
88
101
  return if show_error_if_token_is_revoked(token_data)
@@ -139,6 +152,10 @@ module Zaikio
139
152
  def render_error(error, status: :forbidden)
140
153
  render(status: status, json: { "errors" => [error] })
141
154
  end
155
+
156
+ def jwt_options
157
+ {}
158
+ end
142
159
  end
143
160
  end
144
161
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zaikio-jwt_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - crispymtn
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-04-28 00:00:00.000000000 Z
13
+ date: 2022-08-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activejob
@@ -113,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
113
  - !ruby/object:Gem::Version
114
114
  version: '0'
115
115
  requirements: []
116
- rubygems_version: 3.1.4
116
+ rubygems_version: 3.3.11
117
117
  signing_key:
118
118
  specification_version: 4
119
119
  summary: JWT-Based authentication and authorization with zaikio