zaikio-jwt_auth 0.4.1 → 0.5.1

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: fd2758c610957007baf7499e46f22d286a5c61dceb5895270080f20af8e5a57d
4
- data.tar.gz: 5c945887dca4cd07ebfc836a5cbadb81667a56dbed0c6f67152dba297d4399fd
3
+ metadata.gz: cbd7c7fb4d5cb2a3d1001e5a24036beafbf3dcf76200bd052ee4c1d731c39a2d
4
+ data.tar.gz: 94a597d69c55f1dee78784967f6b6fa33d0b3aee98d55b4001060bc28ad1cf97
5
5
  SHA512:
6
- metadata.gz: 73a3192d97b3f20caab44a96306258cd7b1b0240fb9e912726e3dfd536ef46183e0590a9cb513ed4be6afb66f4ee3c0a415153c4a7e7259a7bd569374e30eab4
7
- data.tar.gz: bb9db302ba5caafeae825b25c244a91d213c1026d879c62ca2da230db6f29ade726121fcd0c0727c1e5625a84e2ed2cfb282a25ecaa827562efe6e6a9cb1a58f
6
+ metadata.gz: 6be2c8d3b1000c4dcbe09518fc4afb38a6f550fced5dfb82eca44636755adbcc50897c8ed81729346f8ab2b3838b2a033a0c6b33a7cb37d3e2027644e2e2daad
7
+ data.tar.gz: 370e9de4ce7973de106fb66259d43186876591770f71e819448d386d5c64f17751ebb32573130533777a4477df6cd0b93997e4fb6de5f7418ef4f2c82d22d560
data/README.md CHANGED
@@ -63,6 +63,26 @@ end
63
63
 
64
64
  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
65
 
66
+ #### Modifying required scopes
67
+ 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
+
69
+ ```rb
70
+ class API::ResourcesController < API::ApplicationController
71
+ # Require a write or read_write scope on the index route
72
+ authorize_by_jwt_scopes 'resources', only: :index, type: :write
73
+ end
74
+ ```
75
+
76
+ #### Using custom actions
77
+ You can also specify authorization for custom actions. When doing so the `type` option is required.
78
+
79
+ ```rb
80
+ class API::ResourcesController < API::ApplicationController
81
+ # Require the index use to have a write or read_write scope
82
+ authorize_by_jwt_scopes 'resources', only: :my_custom_route, type: :write
83
+ end
84
+ ```
85
+
66
86
  ### 6. Optionally, if you are using SSO: Check revoked tokens
67
87
 
68
88
  Additionally, the API provides a method called `revoked_jwt?` which expects the `jti` of the JWT.
@@ -132,7 +152,18 @@ class MyRackMiddleware < Rack::Middleware
132
152
  ...
133
153
  ```
134
154
 
135
- This function expects to receive the string in the format `"Bearer $token"`.
155
+ This function expects to receive the string in the format `"Bearer $token"`. If the JWT is
156
+ invalid, expired, or has some other fundamental issues, the JWT library may throw
157
+ [additional errors](https://github.com/jwt/ruby-jwt/blob/v2.2.2/lib/jwt/error.rb), and you
158
+ should be prepared to handle these, for example:
159
+
160
+ ```ruby
161
+ def call(env)
162
+ token = Zaikio::JWTAuth.extract("definitely.not.jwt")
163
+ rescue JWT::DecodeError, JWT::ExpiredSignature
164
+ [401, {}, ["Unauthorized"]]
165
+ end
166
+ ```
136
167
 
137
168
  ## Contributing
138
169
 
@@ -18,7 +18,7 @@ module Zaikio
18
18
  def self.configure
19
19
  self.configuration ||= Configuration.new
20
20
 
21
- if Zaikio.const_defined?("Webhooks")
21
+ if Zaikio.const_defined?("Webhooks", false)
22
22
  Zaikio::Webhooks.on "directory.revoked_access_token", Zaikio::JWTAuth::RevokeAccessTokenJob,
23
23
  perform_now: true
24
24
  end
@@ -5,6 +5,8 @@ require "logger"
5
5
  module Zaikio
6
6
  module JWTAuth
7
7
  class DirectoryCache
8
+ BadResponseError = Class.new(StandardError)
9
+
8
10
  class << self
9
11
  def fetch(directory_path, options = {})
10
12
  cache = Zaikio::JWTAuth.configuration.redis.get("zaikio::jwt_auth::#{directory_path}")
@@ -48,10 +50,10 @@ module Zaikio
48
50
  }.to_json)
49
51
 
50
52
  data
51
- rescue Errno::ECONNREFUSED, Net::ReadTimeout => e
53
+ rescue Errno::ECONNREFUSED, Net::ReadTimeout, BadResponseError => e
52
54
  raise unless (retries += 1) <= 3
53
55
 
54
- Zaikio::JWTAuth.configuration.logger.log("Timeout (#{e}), retrying in 1 second...")
56
+ Zaikio::JWTAuth.configuration.logger.info("Timeout (#{e}), retrying in 1 second...")
55
57
  sleep(1)
56
58
  retry
57
59
  end
@@ -59,7 +61,13 @@ module Zaikio
59
61
 
60
62
  def fetch_from_directory(directory_path)
61
63
  uri = URI("#{Zaikio::JWTAuth.configuration.host}/#{directory_path}")
62
- Oj.load(Net::HTTP.get(uri))
64
+ http = Net::HTTP.new(uri.host, uri.port)
65
+ http.use_ssl = uri.scheme == "https"
66
+ response = http.request(Net::HTTP::Get.new(uri.request_uri))
67
+ raise BadResponseError unless (200..299).cover?(response.code.to_i)
68
+ raise BadResponseError unless response["content-type"].to_s.include?("application/json")
69
+
70
+ Oj.load(response.body)
63
71
  end
64
72
  end
65
73
  end
@@ -13,6 +13,14 @@ module Zaikio
13
13
  }.freeze
14
14
  end
15
15
 
16
+ def self.permissions_by_type
17
+ {
18
+ read: %w[r rw],
19
+ write: %w[rw w],
20
+ read_write: %w[r rw w]
21
+ }
22
+ end
23
+
16
24
  def initialize(payload)
17
25
  @payload = payload
18
26
  end
@@ -38,8 +46,8 @@ module Zaikio
38
46
  end
39
47
 
40
48
  # scope_options is an array of objects with:
41
- # scope, app_name (optional), except/only (array, optional)
42
- def scope_by_configurations?(scope_configurations, action_name, context)
49
+ # scope, app_name (optional), except/only (array, optional), type (read, write, readwrite)
50
+ def scope_by_configurations?(scope_configurations, action_name, context) # rubocop:disable Metrics/AbcSize
43
51
  configuration = scope_configurations.find do |scope_configuration|
44
52
  action_matches = action_matches_config?(scope_configuration, action_name)
45
53
 
@@ -54,7 +62,7 @@ module Zaikio
54
62
 
55
63
  return true unless configuration
56
64
 
57
- scope?(configuration[:scopes], action_name, configuration[:app_name])
65
+ scope?(configuration[:scopes], action_name, app_name: configuration[:app_name], type: configuration[:type])
58
66
  end
59
67
 
60
68
  def action_matches_config?(scope_configuration, action_name)
@@ -67,14 +75,14 @@ module Zaikio
67
75
  end
68
76
  end
69
77
 
70
- def scope?(allowed_scopes, action_name, app_name = nil)
78
+ def scope?(allowed_scopes, action_name, app_name: nil, type: nil)
71
79
  app_name ||= Zaikio::JWTAuth.configuration.app_name
72
80
  Array(allowed_scopes).map(&:to_s).any? do |allowed_scope|
73
81
  scope.any? do |s|
74
82
  parts = s.split(".")
75
83
  parts[0] == app_name &&
76
84
  parts[1] == allowed_scope &&
77
- action_in_permission?(action_name, parts[2])
85
+ action_permitted?(action_name, parts[2], type: type)
78
86
  end
79
87
  end
80
88
  end
@@ -101,8 +109,14 @@ module Zaikio
101
109
 
102
110
  private
103
111
 
104
- def action_in_permission?(action_name, permission)
105
- self.class.actions_by_permission[permission].include?(action_name)
112
+ def action_permitted?(action_name, permission, type: nil)
113
+ if type
114
+ return false unless self.class.permissions_by_type.key?(type)
115
+
116
+ self.class.permissions_by_type[type].include?(permission)
117
+ else
118
+ self.class.actions_by_permission[permission].include?(action_name)
119
+ end
106
120
  end
107
121
  end
108
122
  end
@@ -1,5 +1,5 @@
1
1
  module Zaikio
2
2
  module JWTAuth
3
- VERSION = "0.4.1".freeze
3
+ VERSION = "0.5.1".freeze
4
4
  end
5
5
  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: 0.4.1
4
+ version: 0.5.1
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-02-15 00:00:00.000000000 Z
13
+ date: 2021-04-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: oj
@@ -27,7 +27,7 @@ dependencies:
27
27
  - !ruby/object:Gem::Version
28
28
  version: 3.0.0
29
29
  - !ruby/object:Gem::Dependency
30
- name: rails
30
+ name: railties
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
33
  - - ">="