rabarber 1.0.2 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +10 -14
- data/lib/rabarber/configuration.rb +4 -4
- data/lib/rabarber/models/concerns/has_roles.rb +5 -20
- data/lib/rabarber/models/role.rb +1 -1
- data/lib/rabarber/role_names.rb +20 -0
- data/lib/rabarber/rule.rb +17 -3
- data/lib/rabarber/version.rb +1 -1
- data/lib/rabarber.rb +5 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2df45030b2e771a3825eb72a544575fce977253f77ce26673f65372c9d03c06e
|
4
|
+
data.tar.gz: 3538bc9bc309f5715cdf25426d21b9353be873b2e7c25bc135403b4382342678
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50a7e4d76a49010af472916c1dfea7fd59bfc882ca67f1fd1a3742f2357e112d8fab112a75af6baf404fc02155128f928c3637ca1d7e9c71ecc238bdbe648b62
|
7
|
+
data.tar.gz: f020edd72b93678b25761df692bd3b1d361ec9caad9872952d8df79f4e21948ca46e20de2e1dbe41270a8a26d989d7394b79000429d086923dc94b1173b3a166
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -7,7 +7,7 @@ Rabarber is an authorization library for Ruby on Rails, primarily designed for u
|
|
7
7
|
|
8
8
|
---
|
9
9
|
|
10
|
-
|
10
|
+
**Example of Usage**:
|
11
11
|
|
12
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.
|
13
13
|
|
@@ -78,7 +78,7 @@ end
|
|
78
78
|
- `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).
|
79
79
|
- `when_unauthorized` must be a lambda where you can define your actions when access is not authorized (`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
80
|
|
81
|
-
##
|
81
|
+
## Roles
|
82
82
|
|
83
83
|
Include `Rabarber::HasRoles` module in your model representing users in your application:
|
84
84
|
|
@@ -89,9 +89,9 @@ class User < ApplicationRecord
|
|
89
89
|
end
|
90
90
|
```
|
91
91
|
|
92
|
-
|
92
|
+
This adds the following methods:
|
93
93
|
|
94
|
-
|
94
|
+
**`#assign_roles`**
|
95
95
|
|
96
96
|
To assign roles to the user, use:
|
97
97
|
|
@@ -110,7 +110,7 @@ Rabarber::Role.create(name: "manager")
|
|
110
110
|
```
|
111
111
|
The role names are unique.
|
112
112
|
|
113
|
-
|
113
|
+
**`#revoke_roles`**
|
114
114
|
|
115
115
|
To revoke roles, use:
|
116
116
|
|
@@ -119,7 +119,7 @@ user.revoke_roles(:accountant, :marketer)
|
|
119
119
|
```
|
120
120
|
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.
|
121
121
|
|
122
|
-
|
122
|
+
**`#has_role?`**
|
123
123
|
|
124
124
|
To check whether the user has a role, use:
|
125
125
|
|
@@ -129,7 +129,7 @@ user.has_role?(:accountant, :marketer)
|
|
129
129
|
|
130
130
|
It returns `true` if the user has at least one role and `false` otherwise.
|
131
131
|
|
132
|
-
|
132
|
+
**`#roles`**
|
133
133
|
|
134
134
|
To view all the roles assigned to the user, use:
|
135
135
|
|
@@ -147,9 +147,7 @@ Rabarber::Role.names
|
|
147
147
|
|
148
148
|
Utilize the aforementioned methods to manipulate user roles. For example, create a custom UI for managing roles or assign necessary roles during migration or runtime (e.g., when the user is created). You can also write custom authorization policies based on `#has_role?` method (e.g., to scope the data that the user can access). Adapt these methods to fit the requirements of your application.
|
149
149
|
|
150
|
-
|
151
|
-
|
152
|
-
### Authorization Rules
|
150
|
+
## Authorization Rules
|
153
151
|
|
154
152
|
Include `Rabarber::Authorization` module into the controller that needs authorization rules to be applied (authorization rules will be applied to the controller and its children). Typically, it is `ApplicationController`, but it can be any controller.
|
155
153
|
|
@@ -159,7 +157,7 @@ class ApplicationController < ActionController::Base
|
|
159
157
|
...
|
160
158
|
end
|
161
159
|
```
|
162
|
-
This adds `.grant_access` method
|
160
|
+
This adds `.grant_access` method which allows you to define the authorization rules.
|
163
161
|
|
164
162
|
The most basic usage of the method is as follows:
|
165
163
|
|
@@ -260,9 +258,7 @@ end
|
|
260
258
|
```
|
261
259
|
This means that `Crm::InvoicesController` is still accessible to `admin` but is also accessible to `accountant`.
|
262
260
|
|
263
|
-
|
264
|
-
|
265
|
-
### View Helpers
|
261
|
+
## View Helpers
|
266
262
|
|
267
263
|
Rabarber also provides a couple of helpers that can be used in views: `visible_to` and `hidden_from`. The usage is straightforward:
|
268
264
|
|
@@ -21,21 +21,21 @@ module Rabarber
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def current_user_method=(method_name)
|
24
|
-
unless
|
25
|
-
raise
|
24
|
+
unless (method_name.is_a?(Symbol) || method_name.is_a?(String)) && method_name.present?
|
25
|
+
raise ConfigurationError, "Configuration 'current_user_method' must be a Symbol or a String"
|
26
26
|
end
|
27
27
|
|
28
28
|
@current_user_method = method_name.to_sym
|
29
29
|
end
|
30
30
|
|
31
31
|
def must_have_roles=(value)
|
32
|
-
raise
|
32
|
+
raise ConfigurationError, "Configuration 'must_have_roles' must be a Boolean" unless [true, false].include?(value)
|
33
33
|
|
34
34
|
@must_have_roles = value
|
35
35
|
end
|
36
36
|
|
37
37
|
def when_unauthorized=(callable)
|
38
|
-
raise
|
38
|
+
raise ConfigurationError, "Configuration 'when_unauthorized' must be a Proc" unless callable.is_a?(Proc)
|
39
39
|
|
40
40
|
@when_unauthorized = callable
|
41
41
|
end
|
@@ -19,38 +19,23 @@ module Rabarber
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def has_role?(*role_names)
|
22
|
-
|
23
|
-
|
24
|
-
(roles & role_names).any?
|
22
|
+
(roles & RoleNames.pre_process(role_names)).any?
|
25
23
|
end
|
26
24
|
|
27
25
|
def assign_roles(*role_names, create_new: true)
|
28
|
-
|
26
|
+
roles_to_assign = RoleNames.pre_process(role_names)
|
29
27
|
|
30
|
-
create_new_roles(
|
28
|
+
create_new_roles(roles_to_assign) if create_new
|
31
29
|
|
32
|
-
rabarber_roles << Role.where(name:
|
30
|
+
rabarber_roles << Role.where(name: roles_to_assign) - rabarber_roles
|
33
31
|
end
|
34
32
|
|
35
33
|
def revoke_roles(*role_names)
|
36
|
-
|
37
|
-
|
38
|
-
self.rabarber_roles = rabarber_roles - Role.where(name: role_names)
|
34
|
+
self.rabarber_roles = rabarber_roles - Role.where(name: RoleNames.pre_process(role_names))
|
39
35
|
end
|
40
36
|
|
41
37
|
private
|
42
38
|
|
43
|
-
def validate_role_names(role_names)
|
44
|
-
return if role_names.all? do |role_name|
|
45
|
-
[Symbol, String].include?(role_name.class) && role_name.match?(/\A[a-z0-9_]+\z/)
|
46
|
-
end
|
47
|
-
|
48
|
-
raise(
|
49
|
-
ArgumentError,
|
50
|
-
"Role names must be symbols or strings and may only contain lowercase letters and underscores"
|
51
|
-
)
|
52
|
-
end
|
53
|
-
|
54
39
|
def create_new_roles(role_names)
|
55
40
|
new_roles = role_names - Role.names
|
56
41
|
new_roles.each { |role_name| Role.create!(name: role_name) }
|
data/lib/rabarber/models/role.rb
CHANGED
@@ -4,7 +4,7 @@ module Rabarber
|
|
4
4
|
class Role < ActiveRecord::Base
|
5
5
|
self.table_name = "rabarber_roles"
|
6
6
|
|
7
|
-
validates :name, presence: true, uniqueness: true
|
7
|
+
validates :name, presence: true, uniqueness: true, format: { with: RoleNames::REGEX }
|
8
8
|
|
9
9
|
def self.names
|
10
10
|
pluck(:name).map(&:to_sym)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rabarber
|
4
|
+
module RoleNames
|
5
|
+
module_function
|
6
|
+
|
7
|
+
REGEX = /\A[a-z0-9_]+\z/
|
8
|
+
|
9
|
+
def pre_process(role_names)
|
10
|
+
return role_names.map(&:to_sym) if role_names.all? do |role_name|
|
11
|
+
(role_name.is_a?(Symbol) || role_name.is_a?(String)) && role_name.to_s.match?(REGEX)
|
12
|
+
end
|
13
|
+
|
14
|
+
raise(
|
15
|
+
InvalidArgumentError,
|
16
|
+
"Role names must be Symbols or Strings and may only contain lowercase letters, numbers and underscores"
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/rabarber/rule.rb
CHANGED
@@ -5,9 +5,9 @@ module Rabarber
|
|
5
5
|
attr_reader :action, :roles, :custom
|
6
6
|
|
7
7
|
def initialize(action, roles, custom)
|
8
|
-
@action = action
|
9
|
-
@roles = Array(roles)
|
10
|
-
@custom = custom
|
8
|
+
@action = pre_process_action(action)
|
9
|
+
@roles = RoleNames.pre_process(Array(roles))
|
10
|
+
@custom = pre_process_custom_rule(custom)
|
11
11
|
end
|
12
12
|
|
13
13
|
def verify_access(user_roles, custom_rule_receiver, action_name = nil)
|
@@ -37,5 +37,19 @@ module Rabarber
|
|
37
37
|
custom_rule_receiver.send(custom)
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
def pre_process_action(action)
|
42
|
+
return action.to_sym if (action.is_a?(String) || action.is_a?(Symbol)) && action.present?
|
43
|
+
return action if action.nil?
|
44
|
+
|
45
|
+
raise InvalidArgumentError, "Action name must be a Symbol or a String"
|
46
|
+
end
|
47
|
+
|
48
|
+
def pre_process_custom_rule(custom)
|
49
|
+
return custom.to_sym if (custom.is_a?(String) || custom.is_a?(Symbol)) && action.present?
|
50
|
+
return custom if custom.nil? || custom.is_a?(Proc)
|
51
|
+
|
52
|
+
raise InvalidArgumentError, "Custom rule must be a Symbol, a String, or a Proc"
|
53
|
+
end
|
40
54
|
end
|
41
55
|
end
|
data/lib/rabarber/version.rb
CHANGED
data/lib/rabarber.rb
CHANGED
@@ -6,13 +6,12 @@ require_relative "rabarber/configuration"
|
|
6
6
|
require "active_record"
|
7
7
|
require "active_support"
|
8
8
|
|
9
|
-
require_relative "rabarber/
|
9
|
+
require_relative "rabarber/role_names"
|
10
10
|
|
11
|
+
require_relative "rabarber/controllers/concerns/authorization"
|
11
12
|
require_relative "rabarber/helpers/helpers"
|
12
|
-
|
13
|
-
require_relative "rabarber/models/role"
|
14
13
|
require_relative "rabarber/models/concerns/has_roles"
|
15
|
-
|
14
|
+
require_relative "rabarber/models/role"
|
16
15
|
require_relative "rabarber/permissions"
|
17
16
|
|
18
17
|
module Rabarber
|
@@ -23,4 +22,6 @@ module Rabarber
|
|
23
22
|
end
|
24
23
|
|
25
24
|
class Error < StandardError; end
|
25
|
+
class ConfigurationError < Error; end
|
26
|
+
class InvalidArgumentError < Error; end
|
26
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rabarber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- enjaku4
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -44,6 +44,7 @@ files:
|
|
44
44
|
- lib/rabarber/models/concerns/has_roles.rb
|
45
45
|
- lib/rabarber/models/role.rb
|
46
46
|
- lib/rabarber/permissions.rb
|
47
|
+
- lib/rabarber/role_names.rb
|
47
48
|
- lib/rabarber/rule.rb
|
48
49
|
- lib/rabarber/version.rb
|
49
50
|
- rabarber.gemspec
|