rabarber 1.3.1 → 1.4.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 +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
|
[](http://badge.fury.io/rb/rabarber)
|
4
4
|
[](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.
|