rabarber 1.3.1 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -17
- data/README.md +54 -29
- data/lib/rabarber/configuration.rb +14 -6
- data/lib/rabarber/controllers/concerns/authorization.rb +10 -6
- data/lib/rabarber/core/access.rb +2 -8
- data/lib/rabarber/logger.rb +33 -4
- data/lib/rabarber/missing/roles.rb +1 -3
- data/lib/rabarber/models/concerns/has_roles.rb +20 -11
- data/lib/rabarber/railtie.rb +5 -0
- data/lib/rabarber/version.rb +1 -1
- data/lib/rabarber.rb +2 -0
- data/rabarber.gemspec +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23a3e2a6c83a827ad3cd468761de12d2124cdd2f1b022e18661fdf97f21302e7
|
4
|
+
data.tar.gz: 1b56b41289ce816796856832f07e76453ecfa0c290f1cd8f37f4a83690227abc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac4af855dc20a41b78633fa4c4e946d1c54fad1df93e5f8505954bc4ff2cd43307fc94789718e1f9a563b44a57d3266660b84057f9de1d61afdab1111eb5b506
|
7
|
+
data.tar.gz: 17408ae706718e23ac594cd7c3144413c78aa69ce1ae0d0a230e5f62400917e1d5a82a22bd727df19391c7cbf235510cbaea8bbf6edc7aba47b8bcab06e6de81
|
data/CHANGELOG.md
CHANGED
@@ -1,21 +1,31 @@
|
|
1
|
-
##
|
1
|
+
## v1.4.1
|
2
|
+
|
3
|
+
- Fix an issue where an error could be raised when using controller-wide dynamic rules
|
4
|
+
|
5
|
+
## v1.4.0
|
6
|
+
|
7
|
+
- Add 'Audit trail' feature: Logging of role assignments, revocations, and unauthorized access attempts
|
8
|
+
- Add `audit_trail_enabled` configuration option, allowing to enable or disable the audit trail
|
9
|
+
- Deprecate `when_actions_missing` and `when_roles_missing` configuration options (see [the discussion](https://github.com/enjaku4/rabarber/discussions/48))
|
10
|
+
|
11
|
+
## v1.3.1
|
2
12
|
|
3
13
|
- Add `Rabarber::Role.assignees_for` method
|
4
14
|
- Fix inconsistent behavior where passing `nil` as a role name to role management methods would raise an `ActiveRecord` error instead of `Rabarber` error
|
5
15
|
- Various minor code improvements
|
6
16
|
|
7
|
-
##
|
17
|
+
## v1.3.0
|
8
18
|
|
9
19
|
- Add methods to directly add, rename, and remove roles
|
10
20
|
- Modify `Rabarber::HasRoles#assign_roles` and `Rabarber::HasRoles#revoke_roles` methods to return the list of roles assigned to the user
|
11
21
|
- Minor performance improvements
|
12
22
|
|
13
|
-
##
|
23
|
+
## v1.2.2
|
14
24
|
|
15
25
|
- Refactor to improve readability and maintainability
|
16
26
|
- Fix minor code errors
|
17
27
|
|
18
|
-
##
|
28
|
+
## v1.2.1
|
19
29
|
|
20
30
|
- Cache roles to avoid unnecessary database queries
|
21
31
|
- Introduce `cache_enabled` configuration option allowing to enable or disable role caching
|
@@ -23,61 +33,61 @@
|
|
23
33
|
- Fix an issue where an error would be raised if the user is not authenticated
|
24
34
|
- Various minor improvements
|
25
35
|
|
26
|
-
##
|
36
|
+
## v1.2.0
|
27
37
|
|
28
38
|
- Enhance handling of missing actions and roles specified in `grant_access` method by raising an error for missing actions and logging a warning for missing roles
|
29
39
|
- Introduce `when_actions_missing` and `when_roles_missing` configuration options, allowing to customize the behavior when actions or roles are not found
|
30
40
|
|
31
|
-
##
|
41
|
+
## v1.1.0
|
32
42
|
|
33
43
|
- Add support for `unless` argument in `grant_access` method, allowing to define negated dynamic rules
|
34
44
|
- Fix a bug where specifying a dynamic rule as a symbol without specifying an action would result in an error
|
35
45
|
|
36
|
-
##
|
46
|
+
## v1.0.5
|
37
47
|
|
38
48
|
- Add co-author: [trafium](https://github.com/trafium)
|
39
49
|
|
40
|
-
##
|
50
|
+
## v1.0.4
|
41
51
|
|
42
52
|
- Allow to use strings as role names
|
43
53
|
|
44
|
-
##
|
54
|
+
## v1.0.3
|
45
55
|
|
46
56
|
- Enhance clarity by improving error types and messages
|
47
57
|
- Resolve inconsistency in types of role names
|
48
58
|
|
49
|
-
##
|
59
|
+
## v1.0.2
|
50
60
|
|
51
61
|
- Various enhancements for gem development and release
|
52
62
|
- Modify `Rabarber::HasRoles#roles` method to return an array of role names instead of `Rabarber::Role` objects
|
53
63
|
|
54
|
-
##
|
64
|
+
## v1.0.1
|
55
65
|
|
56
66
|
- Various enhancements for gem development
|
57
67
|
|
58
|
-
##
|
68
|
+
## v1.0.0
|
59
69
|
|
60
70
|
- Drop support for Ruby 2.7
|
61
71
|
- Add support for Ruby 3.3
|
62
72
|
- Various minor improvements
|
63
73
|
|
64
|
-
##
|
74
|
+
## v0.1.5
|
65
75
|
|
66
76
|
- Add missing `foreign_key` option to `CreateRabarberRoles` migration
|
67
77
|
- Allow only lowercase alphanumeric characters and underscores in role names
|
68
78
|
|
69
|
-
##
|
79
|
+
## v0.1.4
|
70
80
|
|
71
81
|
- Remove `Rabarber::HasRoles#role?` method as unnecessary
|
72
82
|
|
73
|
-
##
|
83
|
+
## v0.1.3
|
74
84
|
|
75
85
|
- Fully revise and update README for clarity
|
76
86
|
|
77
|
-
##
|
87
|
+
## v0.1.2
|
78
88
|
|
79
89
|
- Fix check that `Rabarber::HasRoles` can only be included once
|
80
90
|
|
81
|
-
##
|
91
|
+
## v0.1.1
|
82
92
|
|
83
93
|
- Initial release
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/rabarber.svg)](http://badge.fury.io/rb/rabarber)
|
4
4
|
[![Github Actions badge](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml/badge.svg)](https://github.com/enjaku4/rabarber/actions/workflows/ci.yml)
|
5
5
|
|
6
|
-
Rabarber is a role-based authorization library for Ruby on Rails, designed
|
6
|
+
Rabarber is a role-based authorization library for Ruby on Rails, primarily designed for use in the web layer of your application but not limited to that. It provides a set of tools for managing user roles and defining authorization rules, along with audit logging for enhanced security.
|
7
7
|
|
8
8
|
---
|
9
9
|
|
@@ -63,26 +63,32 @@ If specific customization is required, Rabarber can be configured by using `.con
|
|
63
63
|
|
64
64
|
```rb
|
65
65
|
Rabarber.configure do |config|
|
66
|
+
config.audit_trail_enabled = true
|
66
67
|
config.cache_enabled = true
|
67
68
|
config.current_user_method = :current_user
|
68
69
|
config.must_have_roles = false
|
69
|
-
config.
|
70
|
-
|
71
|
-
|
70
|
+
config.when_unauthorized = -> (controller) {
|
71
|
+
if controller.request.format.html?
|
72
|
+
controller.redirect_back fallback_location: controller.root_path
|
73
|
+
else
|
74
|
+
controller.head :unauthorized
|
75
|
+
end
|
76
|
+
}
|
72
77
|
end
|
73
78
|
```
|
74
79
|
|
80
|
+
- `audit_trail_enabled` must be a boolean determining whether the audit trail functionality is enabled. _The audit trail is enabled by default._
|
75
81
|
- `cache_enabled` must be a boolean determining whether roles are cached. _Roles are cached by default to avoid unnecessary database queries._ If you want to disable caching, set this option to `false`. If caching is enabled and you need to clear the cache, use `Rabarber::Cache.clear` method.
|
76
|
-
|
77
82
|
- `current_user_method` must be a symbol representing the method that returns the currently authenticated user. _The default value is `:current_user`._
|
78
|
-
|
79
83
|
- `must_have_roles` must be a boolean determining whether a user with no roles can access endpoints permitted to everyone. _The default value is `false` (allowing users without roles to access endpoints permitted to everyone)._
|
84
|
+
- `when_unauthorized` must be a proc where you can define the behaviour when access is not authorized. Lambda argument `controller` is an instance of the controller where the code is executed. _By default, the user is redirected back if the request format is HTML; otherwise, a 401 Unauthorized response is sent._
|
80
85
|
|
81
|
-
|
86
|
+
### Deprecated Configuration Options
|
82
87
|
|
83
|
-
|
88
|
+
The following configuration options are deprecated and will be removed in the next major version (see [the discussion](https://github.com/enjaku4/rabarber/discussions/48)):
|
84
89
|
|
85
|
-
- `
|
90
|
+
- `when_actions_missing` must be a proc where you can define the behaviour when the action specified in `grant_access` method cannot be found in the controller. Lambda argument `missing_actions` is an array of symbols, e.g., `[:index]`, while `context` argument is a hash that looks like this: `{ controller: "InvoicesController" }`. This check is performed when the application is initialized if `eager_load` configuration is enabled in Rails and also on every request. _By default, an error is raised when action is missing._
|
91
|
+
- `when_roles_missing` must be a proc where you can define the behaviour when the roles specified in `grant_access` method cannot be found in the database. Lambda argument `missing_roles` is an array of symbols, e.g., `[:admin]`, while `context` argument is a hash that looks like this: `{ controller: "InvoicesController", action: "index" }`. This check is performed when the application is initialized if `eager_load` configuration is enabled in Rails and also on every request. _By default, a warning is logged when roles are missing._
|
86
92
|
|
87
93
|
## Roles
|
88
94
|
|
@@ -97,20 +103,20 @@ end
|
|
97
103
|
|
98
104
|
This adds the following methods:
|
99
105
|
|
100
|
-
**`#assign_roles`**
|
106
|
+
**`#assign_roles(*roles, create_new: true)`**
|
101
107
|
|
102
108
|
To assign roles, use:
|
103
109
|
|
104
110
|
```rb
|
105
111
|
user.assign_roles(:accountant, :marketer)
|
106
112
|
```
|
107
|
-
By default,
|
113
|
+
By default, it will automatically create any roles that don't exist. If you want to assign only existing roles and prevent the creation of new ones, use the method with `create_new: false` argument:
|
108
114
|
```rb
|
109
115
|
user.assign_roles(:accountant, :marketer, create_new: false)
|
110
116
|
```
|
111
117
|
The method returns an array of roles assigned to the user.
|
112
118
|
|
113
|
-
**`#revoke_roles`**
|
119
|
+
**`#revoke_roles(*roles)`**
|
114
120
|
|
115
121
|
To revoke roles, use:
|
116
122
|
|
@@ -121,7 +127,7 @@ If any of the specified roles doesn't exist or the user doesn't have the role yo
|
|
121
127
|
|
122
128
|
The method returns an array of roles assigned to the user.
|
123
129
|
|
124
|
-
**`#has_role
|
130
|
+
**`#has_role?(*roles)`**
|
125
131
|
|
126
132
|
To check whether the user has a role, use:
|
127
133
|
|
@@ -143,7 +149,7 @@ user.roles
|
|
143
149
|
|
144
150
|
To manipulate roles directly, you can use `Rabarber::Role` methods:
|
145
151
|
|
146
|
-
**`.add`**
|
152
|
+
**`.add(role)`**
|
147
153
|
|
148
154
|
To add a new role, use:
|
149
155
|
|
@@ -153,7 +159,7 @@ Rabarber::Role.add(:admin)
|
|
153
159
|
|
154
160
|
This will create a new role with the specified name and return `true`. If the role already exists, it will return `false`.
|
155
161
|
|
156
|
-
**`.rename`**
|
162
|
+
**`.rename(old_role_name, new_role_name, force: false)`**
|
157
163
|
|
158
164
|
To rename a role, use:
|
159
165
|
|
@@ -167,7 +173,7 @@ The method won't rename the role and will return `false` if it is assigned to an
|
|
167
173
|
Rabarber::Role.rename(:admin, :administrator, force: true)
|
168
174
|
```
|
169
175
|
|
170
|
-
**`.remove`**
|
176
|
+
**`.remove(role, force: false)`**
|
171
177
|
|
172
178
|
To remove a role, use:
|
173
179
|
|
@@ -190,7 +196,7 @@ If you need to list all the role names available in your application, use:
|
|
190
196
|
Rabarber::Role.names
|
191
197
|
```
|
192
198
|
|
193
|
-
**`.assignees_for`**
|
199
|
+
**`.assignees_for(role)`**
|
194
200
|
|
195
201
|
To get all the users to whom the role is assigned, use:
|
196
202
|
|
@@ -208,7 +214,7 @@ class ApplicationController < ActionController::Base
|
|
208
214
|
...
|
209
215
|
end
|
210
216
|
```
|
211
|
-
This adds `.grant_access` method which allows you to define the authorization rules.
|
217
|
+
This adds `.grant_access(action: nil, roles: nil, if: nil, unless: nil)` method which allows you to define the authorization rules.
|
212
218
|
|
213
219
|
The most basic usage of the method is as follows:
|
214
220
|
|
@@ -216,16 +222,18 @@ The most basic usage of the method is as follows:
|
|
216
222
|
class InvoicesController < ApplicationController
|
217
223
|
grant_access action: :index, roles: [:accountant, :admin]
|
218
224
|
def index
|
225
|
+
@invoices = Invoice.all
|
226
|
+
@invoices = @invoices.paid if current_user.has_role?(:accountant)
|
219
227
|
...
|
220
228
|
end
|
221
229
|
|
222
|
-
grant_access action: :
|
223
|
-
def
|
230
|
+
grant_access action: :destroy, roles: :admin
|
231
|
+
def destroy
|
224
232
|
...
|
225
233
|
end
|
226
234
|
end
|
227
235
|
```
|
228
|
-
This grants access to `index` action for users with `accountant` or `admin` role, and access to `
|
236
|
+
This grants access to `index` action for users with `accountant` or `admin` role, and access to `destroy` action for `admin` users only.
|
229
237
|
|
230
238
|
You can also define controller-wide rules (without `action` argument):
|
231
239
|
|
@@ -278,14 +286,16 @@ For more complex cases, Rabarber provides dynamic rules:
|
|
278
286
|
|
279
287
|
```rb
|
280
288
|
class OrdersController < ApplicationController
|
281
|
-
grant_access if: :
|
282
|
-
|
283
|
-
|
289
|
+
grant_access roles: :manager, if: :company_manager?, unless: :fired?
|
290
|
+
|
291
|
+
def index
|
292
|
+
...
|
293
|
+
end
|
284
294
|
|
285
295
|
private
|
286
296
|
|
287
|
-
def
|
288
|
-
|
297
|
+
def company_manager?
|
298
|
+
Company.find(params[:company_id]).manager == current_user
|
289
299
|
end
|
290
300
|
|
291
301
|
def fired?
|
@@ -294,12 +304,17 @@ class OrdersController < ApplicationController
|
|
294
304
|
end
|
295
305
|
|
296
306
|
class InvoicesController < ApplicationController
|
297
|
-
grant_access
|
307
|
+
grant_access roles: :senior_accountant
|
308
|
+
|
309
|
+
grant_access action: :index, roles: [:secretary, :accountant], if: -> { InvoicesPolicy.new(current_user).can_access?(:index) }
|
298
310
|
def index
|
311
|
+
@invoices = Invoice.all
|
312
|
+
@invoices = @invoices.where("total < 10000") if current_user.has_role?(:accountant)
|
313
|
+
@invoices = @invoices.unpaid if current_user.has_role?(:secretary)
|
299
314
|
...
|
300
315
|
end
|
301
316
|
|
302
|
-
grant_access action: :show, roles: :
|
317
|
+
grant_access action: :show, roles: :accountant, unless: -> { Invoice.find(params[:id]).total > 10_000 }
|
303
318
|
def show
|
304
319
|
...
|
305
320
|
end
|
@@ -323,7 +338,7 @@ This means that `Crm::InvoicesController` is still accessible to `admin` but is
|
|
323
338
|
|
324
339
|
## View Helpers
|
325
340
|
|
326
|
-
Rabarber also provides a couple of helpers that can be used in views: `visible_to` and `hidden_from`. To use them, simply include `Rabarber::Helpers` in the desired helper. Usually it is `ApplicationHelper`, but it can be any helper of your choice.
|
341
|
+
Rabarber also provides a couple of helpers that can be used in views: `visible_to(*roles, &block)` and `hidden_from(*roles, &block)`. To use them, simply include `Rabarber::Helpers` in the desired helper. Usually it is `ApplicationHelper`, but it can be any helper of your choice.
|
327
342
|
|
328
343
|
```rb
|
329
344
|
module ApplicationHelper
|
@@ -346,6 +361,16 @@ The usage is straightforward:
|
|
346
361
|
<% end %>
|
347
362
|
```
|
348
363
|
|
364
|
+
## Audit Trail
|
365
|
+
|
366
|
+
Rabarber supports audit trail, which provides a record of user access control activity. This feature logs the following events:
|
367
|
+
|
368
|
+
- Role assignments to users
|
369
|
+
- Role revocations from users
|
370
|
+
- Unauthorized access attempts
|
371
|
+
|
372
|
+
The logs are written to the file `log/rabarber_audit.log` unless the `audit_trail_enabled` configuration option is set to `false`.
|
373
|
+
|
349
374
|
## Problems?
|
350
375
|
|
351
376
|
Facing a problem or want to suggest an enhancement?
|
@@ -1,15 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "singleton"
|
4
|
-
|
5
3
|
module Rabarber
|
6
4
|
class Configuration
|
7
5
|
include Singleton
|
8
6
|
|
9
|
-
attr_reader :cache_enabled, :current_user_method, :must_have_roles,
|
7
|
+
attr_reader :audit_trail_enabled, :cache_enabled, :current_user_method, :must_have_roles,
|
10
8
|
:when_actions_missing, :when_roles_missing, :when_unauthorized
|
11
9
|
|
12
10
|
def initialize
|
11
|
+
@audit_trail_enabled = default_audit_trail_enabled
|
13
12
|
@cache_enabled = default_cache_enabled
|
14
13
|
@current_user_method = default_current_user_method
|
15
14
|
@must_have_roles = default_must_have_roles
|
@@ -18,6 +17,12 @@ module Rabarber
|
|
18
17
|
@when_unauthorized = default_when_unauthorized
|
19
18
|
end
|
20
19
|
|
20
|
+
def audit_trail_enabled=(value)
|
21
|
+
@audit_trail_enabled = Rabarber::Input::Types::Boolean.new(
|
22
|
+
value, Rabarber::ConfigurationError, "Configuration 'audit_trail_enabled' must be a Boolean"
|
23
|
+
).process
|
24
|
+
end
|
25
|
+
|
21
26
|
def cache_enabled=(value)
|
22
27
|
@cache_enabled = Rabarber::Input::Types::Boolean.new(
|
23
28
|
value, Rabarber::ConfigurationError, "Configuration 'cache_enabled' must be a Boolean"
|
@@ -56,6 +61,10 @@ module Rabarber
|
|
56
61
|
|
57
62
|
private
|
58
63
|
|
64
|
+
def default_audit_trail_enabled
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
59
68
|
def default_cache_enabled
|
60
69
|
true
|
61
70
|
end
|
@@ -70,21 +79,20 @@ module Rabarber
|
|
70
79
|
|
71
80
|
def default_when_actions_missing
|
72
81
|
-> (missing_actions, context) {
|
73
|
-
raise
|
82
|
+
raise(Rabarber::Error, "'grant_access' method called with non-existent actions: #{missing_actions}, context: '#{context[:controller]}'")
|
74
83
|
}
|
75
84
|
end
|
76
85
|
|
77
86
|
def default_when_roles_missing
|
78
87
|
-> (missing_roles, context) {
|
79
88
|
delimiter = context[:action] ? "#" : ""
|
80
|
-
message = "
|
89
|
+
message = "'grant_access' method called with non-existent roles: #{missing_roles}, context: '#{context[:controller]}#{delimiter}#{context[:action]}'"
|
81
90
|
Rabarber::Logger.log(:warn, message)
|
82
91
|
}
|
83
92
|
end
|
84
93
|
|
85
94
|
def default_when_unauthorized
|
86
95
|
-> (controller) do
|
87
|
-
Rabarber::Logger.log(:warn, "Unauthorized attempt")
|
88
96
|
if controller.request.format.html?
|
89
97
|
controller.redirect_back fallback_location: controller.main_app.root_path
|
90
98
|
else
|
@@ -28,14 +28,18 @@ module Rabarber
|
|
28
28
|
Rabarber::Missing::Actions.new(self.class).handle
|
29
29
|
Rabarber::Missing::Roles.new(self.class).handle
|
30
30
|
|
31
|
-
|
31
|
+
roleable = send(Rabarber::Configuration.instance.current_user_method)
|
32
32
|
|
33
|
-
Rabarber::
|
34
|
-
|
33
|
+
return if Rabarber::Core::Permissions.access_granted?(
|
34
|
+
roleable ? roleable.roles : [], self.class, action_name.to_sym, self
|
35
|
+
)
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
Rabarber::Logger.audit(
|
38
|
+
:warn,
|
39
|
+
"[Unauthorized Attempt] #{Rabarber::Logger.roleable_identity(roleable, with_roles: true)} attempted to access '#{request.path}'"
|
40
|
+
)
|
41
|
+
|
42
|
+
Rabarber::Configuration.instance.when_unauthorized.call(self)
|
39
43
|
end
|
40
44
|
end
|
41
45
|
end
|
data/lib/rabarber/core/access.rb
CHANGED
@@ -9,20 +9,14 @@ module Rabarber
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def controller_accessible?(roles, controller, dynamic_rule_receiver)
|
12
|
-
|
13
|
-
controller <=
|
12
|
+
controller_rules.any? do |rule_controller, rule|
|
13
|
+
controller <= rule_controller && rule.verify_access(roles, dynamic_rule_receiver)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
def action_accessible?(roles, controller, action, dynamic_rule_receiver)
|
18
18
|
action_rules[controller].any? { |rule| rule.verify_access(roles, dynamic_rule_receiver, action) }
|
19
19
|
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def accessible_controllers(roles, dynamic_rule_receiver)
|
24
|
-
controller_rules.select { |_, rule| rule.verify_access(roles, dynamic_rule_receiver) }.keys
|
25
|
-
end
|
26
20
|
end
|
27
21
|
end
|
28
22
|
end
|
data/lib/rabarber/logger.rb
CHANGED
@@ -1,11 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Rabarber
|
4
|
-
|
5
|
-
|
4
|
+
class Logger
|
5
|
+
include Singleton
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
attr_reader :rails_logger, :audit_logger
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@rails_logger = Rails.logger
|
11
|
+
@audit_logger = ::Logger.new(Rails.root.join("log/rabarber_audit.log"))
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def log(log_level, message)
|
16
|
+
instance.rails_logger.tagged("Rabarber") { instance.rails_logger.public_send(log_level, message) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def audit(log_level, message)
|
20
|
+
return unless Rabarber::Configuration.instance.audit_trail_enabled
|
21
|
+
|
22
|
+
instance.audit_logger.public_send(log_level, message)
|
23
|
+
end
|
24
|
+
|
25
|
+
def roleable_identity(roleable, with_roles:)
|
26
|
+
if roleable
|
27
|
+
model_name = roleable.model_name.human
|
28
|
+
primary_key = roleable.class.primary_key
|
29
|
+
roleable_id = roleable.public_send(primary_key)
|
30
|
+
|
31
|
+
roles = with_roles ? ", roles: #{roleable.roles}" : ""
|
32
|
+
|
33
|
+
"#{model_name} with #{primary_key}: '#{roleable_id}'#{roles}"
|
34
|
+
else
|
35
|
+
"Unauthenticated user"
|
36
|
+
end
|
37
|
+
end
|
9
38
|
end
|
10
39
|
end
|
11
40
|
end
|
@@ -16,9 +16,7 @@ module Rabarber
|
|
16
16
|
action_rules.each do |controller, controller_action_rules|
|
17
17
|
controller_action_rules.each do |action_rule|
|
18
18
|
missing_roles = action_rule.roles - all_roles
|
19
|
-
if missing_roles.any?
|
20
|
-
missing_list << Rabarber::Missing::Item.new(missing_roles, controller, action_rule.action)
|
21
|
-
end
|
19
|
+
missing_list << Rabarber::Missing::Item.new(missing_roles, controller, action_rule.action) if missing_roles.any?
|
22
20
|
end
|
23
21
|
end
|
24
22
|
end
|
@@ -5,9 +5,7 @@ module Rabarber
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
if defined?(@@included) && @@included != name
|
9
|
-
raise Rabarber::Error, "Rabarber::HasRoles can only be included once"
|
10
|
-
end
|
8
|
+
raise Rabarber::Error, "Rabarber::HasRoles can only be included once" if defined?(@@included) && @@included != name
|
11
9
|
|
12
10
|
@@included = name
|
13
11
|
|
@@ -27,26 +25,37 @@ module Rabarber
|
|
27
25
|
end
|
28
26
|
|
29
27
|
def assign_roles(*role_names, create_new: true)
|
30
|
-
|
28
|
+
processed_role_names = process_role_names(role_names)
|
31
29
|
|
32
|
-
create_new_roles(
|
30
|
+
create_new_roles(processed_role_names) if create_new
|
33
31
|
|
34
|
-
|
32
|
+
roles_to_assign = Rabarber::Role.where(name: processed_role_names) - rabarber_roles
|
35
33
|
|
36
|
-
if
|
34
|
+
if roles_to_assign.any?
|
37
35
|
delete_roleable_cache
|
38
|
-
rabarber_roles <<
|
36
|
+
rabarber_roles << roles_to_assign
|
37
|
+
|
38
|
+
Rabarber::Logger.audit(
|
39
|
+
:info,
|
40
|
+
"[Role Assignment] #{Rabarber::Logger.roleable_identity(self, with_roles: false)} has been assigned the following roles: #{roles_to_assign.pluck(:name).map(&:to_sym)}, current roles: #{roles}"
|
41
|
+
)
|
39
42
|
end
|
40
43
|
|
41
44
|
roles
|
42
45
|
end
|
43
46
|
|
44
47
|
def revoke_roles(*role_names)
|
45
|
-
|
48
|
+
processed_role_names = process_role_names(role_names)
|
49
|
+
roles_to_revoke = Rabarber::Role.where(name: processed_role_names.intersection(roles))
|
46
50
|
|
47
|
-
if
|
51
|
+
if roles_to_revoke.any?
|
48
52
|
delete_roleable_cache
|
49
|
-
self.rabarber_roles
|
53
|
+
self.rabarber_roles -= roles_to_revoke
|
54
|
+
|
55
|
+
Rabarber::Logger.audit(
|
56
|
+
:info,
|
57
|
+
"[Role Revocation] #{Rabarber::Logger.roleable_identity(self, with_roles: false)} has been revoked from the following roles: #{roles_to_revoke.pluck(:name).map(&:to_sym)}, current roles: #{roles}"
|
58
|
+
)
|
50
59
|
end
|
51
60
|
|
52
61
|
roles
|
data/lib/rabarber/railtie.rb
CHANGED
@@ -8,6 +8,11 @@ module Rabarber
|
|
8
8
|
app.config.after_initialize do
|
9
9
|
Rabarber::Missing::Actions.new.handle
|
10
10
|
Rabarber::Missing::Roles.new.handle if Rabarber::Role.table_exists?
|
11
|
+
|
12
|
+
Rabarber::Logger.log(
|
13
|
+
:warn,
|
14
|
+
"DEPRECATION WARNING: Configurations 'when_actions_missing' and 'when_roles_missing' are deprecated and will be removed in v2.0.0"
|
15
|
+
)
|
11
16
|
end
|
12
17
|
end
|
13
18
|
end
|
data/lib/rabarber/version.rb
CHANGED
data/lib/rabarber.rb
CHANGED
data/rabarber.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
|
|
7
7
|
spec.version = Rabarber::VERSION
|
8
8
|
spec.authors = ["enjaku4", "trafium"]
|
9
9
|
spec.email = ["rabarber_gem@icloud.com"]
|
10
|
-
|
10
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
11
11
|
spec.summary = "Simple role-based authorization library for Ruby on Rails."
|
12
12
|
spec.homepage = "https://github.com/enjaku4/rabarber"
|
13
13
|
spec.license = "MIT"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rabarber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- enjaku4
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-04-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -65,7 +65,8 @@ files:
|
|
65
65
|
homepage: https://github.com/enjaku4/rabarber
|
66
66
|
licenses:
|
67
67
|
- MIT
|
68
|
-
metadata:
|
68
|
+
metadata:
|
69
|
+
rubygems_mfa_required: 'true'
|
69
70
|
post_install_message:
|
70
71
|
rdoc_options: []
|
71
72
|
require_paths:
|
@@ -81,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
81
82
|
- !ruby/object:Gem::Version
|
82
83
|
version: '0'
|
83
84
|
requirements: []
|
84
|
-
rubygems_version: 3.
|
85
|
+
rubygems_version: 3.2.33
|
85
86
|
signing_key:
|
86
87
|
specification_version: 4
|
87
88
|
summary: Simple role-based authorization library for Ruby on Rails.
|