rabarber 1.4.1 → 2.1.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: 23a3e2a6c83a827ad3cd468761de12d2124cdd2f1b022e18661fdf97f21302e7
4
- data.tar.gz: 1b56b41289ce816796856832f07e76453ecfa0c290f1cd8f37f4a83690227abc
3
+ metadata.gz: 2cf7603eb6340263f349ffd661101f6428d210982b2a4dfb0d121f19814db3b7
4
+ data.tar.gz: e31584352b9ea5565bfbc4e9a9f53084c6b9123643eb6919557ef52b9dfb3efb
5
5
  SHA512:
6
- metadata.gz: ac4af855dc20a41b78633fa4c4e946d1c54fad1df93e5f8505954bc4ff2cd43307fc94789718e1f9a563b44a57d3266660b84057f9de1d61afdab1111eb5b506
7
- data.tar.gz: 17408ae706718e23ac594cd7c3144413c78aa69ce1ae0d0a230e5f62400917e1d5a82a22bd727df19391c7cbf235510cbaea8bbf6edc7aba47b8bcab06e6de81
6
+ metadata.gz: 757631f95940e95d1640d16101b1fafe049808178ade0d0d97aac3163d0c31c581043bbeeab5b94da9ba4ed28e9edf890aba9adc845e80e9ab1b39ae22c6d66b
7
+ data.tar.gz: 0eb8500deced87bea565d146de0dcd236ffeacac86e025bd6c5cd484fad94cb8594158575c88e31c69fec1f9d0a83f5328029ee261a343603505f847cad5e989
data/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ ## v2.1.0
2
+
3
+ ### Features:
4
+
5
+ - Added `Rabarber::Authorization.skip_authorization` method to skip authorization checks
6
+
7
+ ## v2.0.0
8
+
9
+ ### Breaking:
10
+
11
+ - Removed `when_actions_missing` and `when_roles_missing` configuration options
12
+ - Replaced `when_unauthorized` configuration option with an overridable controller method
13
+ - Renamed `Rabarber::Role.assignees_for` method to `Rabarber::Role.assignees`
14
+
15
+ To upgrade to v2.0.0, please refer to the [migration guide](https://github.com/enjaku4/rabarber/discussions/52).
16
+
17
+ ### Features:
18
+
19
+ - Added support for UUID primary keys
20
+
21
+ ### Bugs:
22
+
23
+ - Fixed the issue where an error would occur when using view helpers if the user was not authenticated
24
+
25
+ ### Misc:
26
+
27
+ - Significant refactoring and code improvements
28
+
1
29
  ## v1.4.1
2
30
 
3
31
  - Fix an issue where an error could be raised when using controller-wide dynamic rules
data/README.md CHANGED
@@ -9,7 +9,7 @@ Rabarber is a role-based authorization library for Ruby on Rails, primarily desi
9
9
 
10
10
  **Example of Usage**:
11
11
 
12
- Consider a CRM where users with different roles have distinct access levels. For instance, the role `accountant` can interact with invoices but cannot access marketing information, while the role `marketer` has access to marketing-related data. Such authorization rules can be easily defined with Rabarber.
12
+ Consider a CRM system where users with different roles have distinct access levels. For instance, the role `accountant` can interact with invoices but cannot access marketing information, while the role `marketer` has access to marketing-related data. Such authorization rules can be easily defined with Rabarber.
13
13
 
14
14
  ---
15
15
 
@@ -21,39 +21,66 @@ class TicketsController < ApplicationController
21
21
 
22
22
  grant_access action: :index, roles: :manager
23
23
  def index
24
- ...
24
+ # ...
25
25
  end
26
26
 
27
27
  def delete
28
- ...
28
+ # ...
29
29
  end
30
30
  end
31
31
  ```
32
32
  This means that `admin` users can access everything in `TicketsController`, while `manager` role can access only `index` action.
33
33
 
34
+ ## Table of Contents
35
+
36
+ **Gem usage:**
37
+ - [Installation](#installation)
38
+ - [Configuration](#configuration)
39
+ - [Roles](#roles)
40
+ - [Authorization Rules](#authorization-rules)
41
+ - [Dynamic Authorization Rules](#dynamic-authorization-rules)
42
+ - [When Unauthorized](#when-unauthorized)
43
+ - [Skip Authorization](#skip-authorization)
44
+ - [View Helpers](#view-helpers)
45
+ - [Audit Trail](#audit-trail)
46
+
47
+ **Community Resources:**
48
+ - [Problems?](#problems)
49
+ - [Contributing](#contributing)
50
+ - [Code of Conduct](#code-of-conduct)
51
+
52
+ **Legal:**
53
+ - [License](#license)
54
+
34
55
  ## Installation
35
56
 
36
57
  Add the Rabarber gem to your Gemfile:
37
58
 
38
- ```
59
+ ```rb
39
60
  gem "rabarber"
40
61
  ```
41
62
 
42
63
  Install the gem:
43
64
 
44
- ```
65
+ ```shell
45
66
  bundle install
46
67
  ```
47
68
 
48
69
  Next, generate a migration to create tables for storing roles in the database. Make sure to specify the table name of the model representing users in your application as an argument. For instance, if the table name is `users`, run:
49
70
 
50
- ```
71
+ ```shell
51
72
  rails g rabarber:roles users
52
73
  ```
53
74
 
54
- Finally, run the migration to apply the changes to the database:
75
+ Rabarber supports UUIDs as primary keys. If your application uses UUIDs, add `--uuid` option to the generator:
55
76
 
77
+ ```shell
78
+ rails g rabarber:roles users --uuid
56
79
  ```
80
+
81
+ Finally, run the migration to apply the changes to the database:
82
+
83
+ ```shell
57
84
  rails db:migrate
58
85
  ```
59
86
 
@@ -67,28 +94,13 @@ Rabarber.configure do |config|
67
94
  config.cache_enabled = true
68
95
  config.current_user_method = :current_user
69
96
  config.must_have_roles = false
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
- }
77
97
  end
78
98
  ```
79
99
 
80
- - `audit_trail_enabled` must be a boolean determining whether the audit trail functionality is enabled. _The audit trail is enabled by default._
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.
82
- - `current_user_method` must be a symbol representing the method that returns the currently authenticated user. _The default value is `:current_user`._
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._
85
-
86
- ### Deprecated Configuration Options
87
-
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)):
89
-
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._
100
+ - `audit_trail_enabled` determines whether the audit trail functionality is enabled. The audit trail is enabled by default.
101
+ - `cache_enabled` determines whether roles are cached to avoid unnecessary database queries. Roles are cached by default. If you need to clear the cache, use `Rabarber::Cache.clear` method.
102
+ - `current_user_method` represents the method that returns the currently authenticated user. The default value is `:current_user`.
103
+ - `must_have_roles` determines whether a user with no roles can access endpoints permitted to everyone. The default value is `false` (allowing users without roles to access such endpoints).
92
104
 
93
105
  ## Roles
94
106
 
@@ -97,7 +109,7 @@ Include `Rabarber::HasRoles` module in your model representing users in your app
97
109
  ```rb
98
110
  class User < ApplicationRecord
99
111
  include Rabarber::HasRoles
100
- ...
112
+ # ...
101
113
  end
102
114
  ```
103
115
 
@@ -123,7 +135,7 @@ To revoke roles, use:
123
135
  ```rb
124
136
  user.revoke_roles(:accountant, :marketer)
125
137
  ```
126
- If any of the specified roles doesn't exist or the user doesn't have the role you want to revoke, it will be ignored.
138
+ If the user doesn't have the role you want to revoke, it will be ignored.
127
139
 
128
140
  The method returns an array of roles assigned to the user.
129
141
 
@@ -139,7 +151,7 @@ It returns `true` if the user has at least one role and `false` otherwise.
139
151
 
140
152
  **`#roles`**
141
153
 
142
- To view all the roles assigned to the user, use:
154
+ To get all the roles assigned to the user, use:
143
155
 
144
156
  ```rb
145
157
  user.roles
@@ -149,7 +161,7 @@ user.roles
149
161
 
150
162
  To manipulate roles directly, you can use `Rabarber::Role` methods:
151
163
 
152
- **`.add(role)`**
164
+ **`.add(role_name)`**
153
165
 
154
166
  To add a new role, use:
155
167
 
@@ -166,14 +178,14 @@ To rename a role, use:
166
178
  ```rb
167
179
  Rabarber::Role.rename(:admin, :administrator)
168
180
  ```
169
- The first argument is the old name, and the second argument is the new name. This will rename the role and return `true`. If a role with the new name already exists, it will return `false`.
181
+ The first argument is the old name, and the second argument is the new name. This will rename the role and return `true`. If the role with a new name already exists, it will return `false`.
170
182
 
171
183
  The method won't rename the role and will return `false` if it is assigned to any user. To force the rename, use the method with `force: true` argument:
172
184
  ```rb
173
185
  Rabarber::Role.rename(:admin, :administrator, force: true)
174
186
  ```
175
187
 
176
- **`.remove(role, force: false)`**
188
+ **`.remove(role_name, force: false)`**
177
189
 
178
190
  To remove a role, use:
179
191
 
@@ -196,12 +208,12 @@ If you need to list all the role names available in your application, use:
196
208
  Rabarber::Role.names
197
209
  ```
198
210
 
199
- **`.assignees_for(role)`**
211
+ **`.assignees(role_name)`**
200
212
 
201
213
  To get all the users to whom the role is assigned, use:
202
214
 
203
215
  ```rb
204
- Rabarber::Role.assignees_for(:admin)
216
+ Rabarber::Role.assignees(:admin)
205
217
  ```
206
218
 
207
219
  ## Authorization Rules
@@ -211,7 +223,7 @@ Include `Rabarber::Authorization` module into the controller that needs authoriz
211
223
  ```rb
212
224
  class ApplicationController < ActionController::Base
213
225
  include Rabarber::Authorization
214
- ...
226
+ # ...
215
227
  end
216
228
  ```
217
229
  This adds `.grant_access(action: nil, roles: nil, if: nil, unless: nil)` method which allows you to define the authorization rules.
@@ -219,17 +231,17 @@ This adds `.grant_access(action: nil, roles: nil, if: nil, unless: nil)` method
219
231
  The most basic usage of the method is as follows:
220
232
 
221
233
  ```rb
222
- class InvoicesController < ApplicationController
234
+ class Crm::InvoicesController < ApplicationController
223
235
  grant_access action: :index, roles: [:accountant, :admin]
224
236
  def index
225
237
  @invoices = Invoice.all
226
238
  @invoices = @invoices.paid if current_user.has_role?(:accountant)
227
- ...
239
+ # ...
228
240
  end
229
241
 
230
242
  grant_access action: :destroy, roles: :admin
231
243
  def destroy
232
- ...
244
+ # ...
233
245
  end
234
246
  end
235
247
  ```
@@ -243,18 +255,18 @@ class Crm::BaseController < ApplicationController
243
255
 
244
256
  grant_access action: :dashboard, roles: :marketer
245
257
  def dashboard
246
- ...
258
+ # ...
247
259
  end
248
260
  end
249
261
 
250
262
  class Crm::InvoicesController < Crm::BaseController
251
263
  grant_access roles: :accountant
252
264
  def index
253
- ...
265
+ # ...
254
266
  end
255
267
 
256
268
  def delete
257
- ...
269
+ # ...
258
270
  end
259
271
  end
260
272
  ```
@@ -265,31 +277,45 @@ Roles can also be omitted:
265
277
  ```rb
266
278
  class OrdersController < ApplicationController
267
279
  grant_access
268
- ...
280
+ # ...
269
281
  end
270
282
 
271
283
  class InvoicesController < ApplicationController
272
284
  grant_access action: :index
273
285
  def index
274
- ...
286
+ # ...
275
287
  end
276
288
  end
277
289
  ```
278
290
 
279
- This allows everyone to access `OrdersController` and its children and also `index` action in `InvoicesController`. This extends to scenarios where there is no user present, i.e. when the method responsible for returning the currently authenticated user in your application returns `nil`.
291
+ This allows everyone to access `OrdersController` and its children and also `index` action in `InvoicesController`.
280
292
 
281
- _Be aware that if the user is not authenticated (the method responsible for returning the currently authenticated user in your application returns `nil`), Rabarber will treat this situation as if the user with no roles assigned was authenticated._
293
+ If you've set `must_have_roles` setting to `true`, then only the users with at least one role can gain access. This setting can be useful if your requirements are such that users without roles are not allowed to access anything.
282
294
 
283
- If you've set `must_have_roles` setting to `true`, then, only the users with at least one role can have access. This setting can be useful if your requirements are such that users without roles are not allowed to access anything.
295
+ Also keep in mind that rules defined in child classes don't override parent rules but rather add to them:
296
+ ```rb
297
+ class Crm::BaseController < ApplicationController
298
+ grant_access roles: :admin
299
+ # ...
300
+ end
301
+
302
+ class Crm::InvoicesController < Crm::BaseController
303
+ grant_access roles: :accountant
304
+ # ...
305
+ end
306
+ ```
307
+ This means that `Crm::InvoicesController` is still accessible to `admin` but is also accessible to `accountant`.
308
+
309
+ ## Dynamic Authorization Rules
284
310
 
285
311
  For more complex cases, Rabarber provides dynamic rules:
286
312
 
287
313
  ```rb
288
- class OrdersController < ApplicationController
314
+ class Crm::OrdersController < ApplicationController
289
315
  grant_access roles: :manager, if: :company_manager?, unless: :fired?
290
316
 
291
317
  def index
292
- ...
318
+ # ...
293
319
  end
294
320
 
295
321
  private
@@ -303,7 +329,7 @@ class OrdersController < ApplicationController
303
329
  end
304
330
  end
305
331
 
306
- class InvoicesController < ApplicationController
332
+ class Crm::InvoicesController < ApplicationController
307
333
  grant_access roles: :senior_accountant
308
334
 
309
335
  grant_access action: :index, roles: [:secretary, :accountant], if: -> { InvoicesPolicy.new(current_user).can_access?(:index) }
@@ -311,30 +337,70 @@ class InvoicesController < ApplicationController
311
337
  @invoices = Invoice.all
312
338
  @invoices = @invoices.where("total < 10000") if current_user.has_role?(:accountant)
313
339
  @invoices = @invoices.unpaid if current_user.has_role?(:secretary)
314
- ...
340
+ # ...
315
341
  end
316
342
 
317
343
  grant_access action: :show, roles: :accountant, unless: -> { Invoice.find(params[:id]).total > 10_000 }
318
344
  def show
319
- ...
345
+ # ...
320
346
  end
321
347
  end
322
348
  ```
323
- You can pass a dynamic rule as `if` or `unless` argument. It can be a symbol, in which case the method with the same name will be called. Alternatively, it can be a proc, which will be executed within the context of the controller's instance.
349
+ You can pass a dynamic rule as `if` or `unless` argument. It can be a symbol, in which case the method with that name will be called, or alternatively it can be a proc that will be executed within the context of the controller instance at request time.
324
350
 
325
- Rules defined in child classes don't override parent rules but rather add to them:
351
+ You can use only dynamic rules without specifying roles if that suits your needs:
326
352
  ```rb
327
- class Crm::BaseController < ApplicationController
328
- grant_access roles: :admin
329
- ...
353
+ class InvoicesController < ApplicationController
354
+ grant_access action: :index, if: -> { current_user.company == Company.find(params[:company_id]) }
355
+ def index
356
+ # ...
357
+ end
358
+ end
359
+ ```
360
+ This basically allows you to use Rabarber as a policy-based authorization library by calling your own custom policy within a dynamic rule:
361
+ ```rb
362
+ class InvoicesController < ApplicationController
363
+ grant_access action: :index, if: -> { InvoicesPolicy.new(current_user).can_access?(:index) }
364
+ def index
365
+ # ...
366
+ end
330
367
  end
368
+ ```
331
369
 
332
- class Crm::InvoicesController < Crm::BaseController
333
- grant_access roles: :accountant
334
- ...
370
+ ## When Unauthorized
371
+
372
+ By default, in the event of an unauthorized attempt, Rabarber redirects the user back if the request format is HTML (with fallback to the root path), and returns a 401 (Unauthorized) status code otherwise.
373
+
374
+ This behavior can be customized by overriding private `when_unauthorized` method:
375
+
376
+ ```rb
377
+ class ApplicationController < ActionController::Base
378
+ include Rabarber::Authorization
379
+
380
+ # ...
381
+
382
+ private
383
+
384
+ def when_unauthorized
385
+ head :not_found # pretend the page doesn't exist
386
+ end
335
387
  end
336
388
  ```
337
- This means that `Crm::InvoicesController` is still accessible to `admin` but is also accessible to `accountant`.
389
+
390
+ The method can be overridden in different controllers, providing flexibility in handling unauthorized access attempts.
391
+
392
+ ## Skip Authorization
393
+
394
+ To skip authorization, use `.skip_authorization(options = {})` method:
395
+
396
+ ```rb
397
+ class TicketsController < ApplicationController
398
+ skip_authorization only: :index
399
+ # ...
400
+ end
401
+ ```
402
+
403
+ This method accepts the same options as `skip_before_action` method in Rails.
338
404
 
339
405
  ## View Helpers
340
406
 
@@ -343,7 +409,7 @@ Rabarber also provides a couple of helpers that can be used in views: `visible_t
343
409
  ```rb
344
410
  module ApplicationHelper
345
411
  include Rabarber::Helpers
346
- ...
412
+ # ...
347
413
  end
348
414
  ```
349
415
 
@@ -375,7 +441,7 @@ The logs are written to the file `log/rabarber_audit.log` unless the `audit_trai
375
441
 
376
442
  Facing a problem or want to suggest an enhancement?
377
443
 
378
- - **Open a Discussion**: If you have a question, experience difficulties using the gem, or have an improvement suggestion, feel free to use the Discussions section.
444
+ - **Open a Discussion**: If you have a question, experience difficulties using the gem, or have a suggestion for improvements, feel free to use the Discussions section.
379
445
 
380
446
  Encountered a bug?
381
447
 
@@ -384,12 +450,12 @@ Encountered a bug?
384
450
 
385
451
  ## Contributing
386
452
 
387
- Before opening an issue or creating a pull request, please read the [contributing guidelines](https://github.com/enjaku4/rabarber/blob/main/CONTRIBUTING.md).
388
-
389
- ## License
390
-
391
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
453
+ Before creating an issue or a pull request, please read the [contributing guidelines](https://github.com/enjaku4/rabarber/blob/main/CONTRIBUTING.md).
392
454
 
393
455
  ## Code of Conduct
394
456
 
395
457
  Everyone interacting in the Rabarber project is expected to follow the [code of conduct](https://github.com/enjaku4/rabarber/blob/main/CODE_OF_CONDUCT.md).
458
+
459
+ ## License
460
+
461
+ The gem is available as open source under the terms of the [MIT License](https://github.com/enjaku4/rabarber/blob/main/LICENSE.txt).
@@ -10,6 +10,8 @@ module Rabarber
10
10
 
11
11
  argument :table_name, type: :string, required: true
12
12
 
13
+ class_option :uuid, type: :boolean, default: false, desc: "Use UUIDs as primary keys"
14
+
13
15
  def create_migrations
14
16
  migration_template "create_rabarber_roles.rb.erb", "db/migrate/create_rabarber_roles.rb"
15
17
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  class CreateRabarberRoles < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version.to_s %>]
4
4
  def change
5
- create_table :rabarber_roles do |t|
5
+ create_table :rabarber_roles<%= ", id: :uuid" if options[:uuid] %> do |t|
6
6
  t.string :name, null: false, index: { unique: true }
7
7
  t.timestamps
8
8
  end
9
9
 
10
10
  create_table :rabarber_roles_roleables, id: false do |t|
11
- t.belongs_to :role, null: false, index: true, foreign_key: { to_table: :rabarber_roles }
12
- t.belongs_to :roleable, null: false, index: true, foreign_key: { to_table: <%= table_name.to_sym.inspect %> }
11
+ t.belongs_to :role, null: false, index: true, foreign_key: { to_table: :rabarber_roles }<%= ", type: :uuid" if options[:uuid] %>
12
+ t.belongs_to :roleable, null: false, index: true, foreign_key: { to_table: <%= table_name.to_sym.inspect %> }<%= ", type: :uuid" if options[:uuid] %>
13
13
  end
14
14
 
15
15
  add_index :rabarber_roles_roleables, [:role_id, :roleable_id], unique: true
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../logger"
4
+
5
+ module Rabarber
6
+ module Audit
7
+ module Events
8
+ class Base
9
+ attr_reader :roleable, :specifics
10
+
11
+ def self.trigger(roleable, specifics)
12
+ new(roleable, specifics).send(:log)
13
+ end
14
+
15
+ private
16
+
17
+ def initialize(roleable, specifics)
18
+ raise ArgumentError, "Roleable is required for #{self.class} event" if roleable.nil? && !nil_roleable_allowed?
19
+
20
+ @roleable = roleable
21
+ @specifics = specifics
22
+ end
23
+
24
+ def nil_roleable_allowed?
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def log
29
+ Rabarber::Audit::Logger.log(log_level, message)
30
+ end
31
+
32
+ def log_level
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def message
37
+ raise NotImplementedError
38
+ end
39
+
40
+ def identity
41
+ roleable_identity(with_roles: identity_with_roles?)
42
+ end
43
+
44
+ def identity_with_roles?
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def roleable_identity(with_roles:)
49
+ if roleable
50
+ model_name = roleable.model_name.human
51
+ primary_key = roleable.class.primary_key
52
+ roleable_id = roleable.public_send(primary_key)
53
+
54
+ roles = with_roles ? ", roles: #{roleable.roles}" : ""
55
+
56
+ "#{model_name} with #{primary_key}: '#{roleable_id}'#{roles}"
57
+ else
58
+ "Unauthenticated #{Rabarber::HasRoles.roleable_class.model_name.human.downcase}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Audit
5
+ module Events
6
+ class RolesAssigned < Base
7
+ private
8
+
9
+ def nil_roleable_allowed?
10
+ false
11
+ end
12
+
13
+ def log_level
14
+ :info
15
+ end
16
+
17
+ def message
18
+ "[Role Assignment] #{identity} has been assigned the following roles: #{roles_to_assign}, current roles: #{current_roles}"
19
+ end
20
+
21
+ def identity_with_roles?
22
+ false
23
+ end
24
+
25
+ def roles_to_assign
26
+ specifics.fetch(:roles_to_assign)
27
+ end
28
+
29
+ def current_roles
30
+ specifics.fetch(:current_roles)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Audit
5
+ module Events
6
+ class RolesRevoked < Base
7
+ private
8
+
9
+ def nil_roleable_allowed?
10
+ false
11
+ end
12
+
13
+ def log_level
14
+ :info
15
+ end
16
+
17
+ def message
18
+ "[Role Revocation] #{identity} has been revoked from the following roles: #{roles_to_revoke}, current roles: #{current_roles}"
19
+ end
20
+
21
+ def identity_with_roles?
22
+ false
23
+ end
24
+
25
+ def roles_to_revoke
26
+ specifics.fetch(:roles_to_revoke)
27
+ end
28
+
29
+ def current_roles
30
+ specifics.fetch(:current_roles)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rabarber
4
+ module Audit
5
+ module Events
6
+ class UnauthorizedAttempt < Base
7
+ private
8
+
9
+ def nil_roleable_allowed?
10
+ true
11
+ end
12
+
13
+ def log_level
14
+ :warn
15
+ end
16
+
17
+ def message
18
+ "[Unauthorized Attempt] #{identity} attempted to access '#{path}'"
19
+ end
20
+
21
+ def identity_with_roles?
22
+ true
23
+ end
24
+
25
+ def path
26
+ specifics.fetch(:path)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "singleton"
4
+
5
+ module Rabarber
6
+ module Audit
7
+ class Logger
8
+ include Singleton
9
+
10
+ attr_reader :logger
11
+
12
+ def initialize
13
+ @logger = ::Logger.new(Rails.root.join("log/rabarber_audit.log"))
14
+ end
15
+
16
+ def self.log(log_level, message)
17
+ return unless Rabarber::Configuration.instance.audit_trail_enabled
18
+
19
+ instance.logger.public_send(log_level, message)
20
+ end
21
+ end
22
+ end
23
+ end