access_forge 0.1.0 → 1.0.0
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/Gemfile.lock +2 -1
- data/README.md +216 -13
- data/access_forge.gemspec +2 -2
- data/lib/access_forge/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ce9503a123b98c43d0627caf65f3de41581b16a41d142b00d3d00d23d5045bb
|
|
4
|
+
data.tar.gz: fb8a30a4295783dd14bd507a4a8b6c3da67b00128220b13148fe0a6030c49e76
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 640ed26fed01e313e9ed8219802dc2b12d83065a22aac5184b03594fad2a1031f1ee3a3a9d04577d4de085d7faf170e677b3c8c69b919715927486394cca09c5
|
|
7
|
+
data.tar.gz: d52746024392d65f39601b84c42cfd8ed0ed9f6be38b5efe2711f23422745fb3a3540bc3f07c3046a7a28a262c076f0be2db421a2f577168d536859a5efc3b3c
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,34 +1,237 @@
|
|
|
1
1
|
# AccessForge
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
AccessForge is a controller-oriented authorization engine with composable rule objects for Ruby on Rails.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It provides:
|
|
6
|
+
* Convention-based policy resolution
|
|
7
|
+
* Action-oriented authorization methods
|
|
8
|
+
* Composable, reusable policy rules
|
|
9
|
+
* A clean extension surface for custom authorization strategies
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
AccessForge treats authorization as an application concern at the controller boundary — explicit, testable, and decoupled from persistence.
|
|
12
|
+
|
|
13
|
+
## Why AccessForge?
|
|
14
|
+
|
|
15
|
+
AccessForge is designed around three principles:
|
|
16
|
+
1. Authorization decisions occur at the controller boundary.
|
|
17
|
+
2. Authorization should be explicit per action.
|
|
18
|
+
3. Authorization logic should be reusable and composable.
|
|
19
|
+
|
|
20
|
+
Rather than embedding complex logic directly inside policy methods, AccessForge encourages the use of Policy Rule classes — small, focused, testable units of authorization behavior.
|
|
21
|
+
|
|
22
|
+
This keeps policies readable while allowing authorization strategies to evolve independently.
|
|
23
|
+
|
|
24
|
+
## Design Philosophy
|
|
25
|
+
|
|
26
|
+
AccessForge separates policy orchestration from authorization strategy.
|
|
8
27
|
|
|
9
|
-
|
|
28
|
+
It does not impose a persistence model or assume how permissions are stored. Instead, it provides a composable rule system that allows you to implement your own authorization strategy.
|
|
10
29
|
|
|
11
|
-
|
|
30
|
+
Authorization strategies such as group-based RBAC can be implemented via extension gems without modifying your policies.
|
|
12
31
|
|
|
13
|
-
|
|
32
|
+
Policies remain stable. Strategies remain replaceable.
|
|
14
33
|
|
|
15
|
-
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Add this line to your application's Gemfile:
|
|
16
37
|
|
|
17
|
-
|
|
38
|
+
```ruby
|
|
39
|
+
gem 'access_forge'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then execute:
|
|
43
|
+
```bash
|
|
44
|
+
bundle install
|
|
45
|
+
```
|
|
18
46
|
|
|
19
47
|
## Usage
|
|
20
48
|
|
|
21
|
-
|
|
49
|
+
### Step 1: Enable policy resolution in your controllers
|
|
50
|
+
|
|
51
|
+
Include `AccessForge::ControllerHelpers` to enable convention-based policy resolution:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
class ApplicationController < ActionController::API
|
|
55
|
+
include AccessForge::ControllerHelpers
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Step 2: Register the authorization hook
|
|
60
|
+
|
|
61
|
+
Register the `authorize_user!` hook to enforce authorization before each action:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
class ApplicationController < ActionController::API
|
|
65
|
+
include AccessForge::ControllerHelpers
|
|
66
|
+
|
|
67
|
+
before_action :authorize_user!
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Step 3: Define your policy classes
|
|
72
|
+
|
|
73
|
+
AccessForge resolves policy classes using controller naming conventions.
|
|
74
|
+
|
|
75
|
+
For example:
|
|
76
|
+
* `EmployeesController` → `EmployeePolicy`
|
|
77
|
+
|
|
78
|
+
Policies should inherit from `AccessForge::Policy`, either directly or via an application-level base policy.
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
class ApplicationPolicy < AccessForge::Policy
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class EmployeePolicy < ApplicationPolicy
|
|
85
|
+
end
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If you need to override the default resolution behavior, you may define #policy_class in your controller:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
class EmployeesController < ApplicationController
|
|
92
|
+
def policy_class
|
|
93
|
+
DifferentPolicy
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Step 4: Implement policy methods
|
|
99
|
+
|
|
100
|
+
For each controller action, AccessForge calls the corresponding predicate method on the policy.
|
|
101
|
+
|
|
102
|
+
For example:
|
|
103
|
+
* `show` → `show?`
|
|
104
|
+
* `create` → `create?`
|
|
105
|
+
|
|
106
|
+
Each method should return `true` or `false`.
|
|
107
|
+
|
|
108
|
+
A false result will prevent the action from being performed and return a 401 response. A true result allows execution to proceed.
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
class EmployeePolicy < ApplicationPolicy
|
|
112
|
+
def index?
|
|
113
|
+
true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def create?
|
|
117
|
+
false
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
If multiple actions share identical logic, you may use:
|
|
123
|
+
* `can_read?` for `index` and `show`
|
|
124
|
+
* `can_write?` for `create`, `update`, and `destroy`
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
class EmployeePolicy < ApplicationPolicy
|
|
128
|
+
def can_read?
|
|
129
|
+
true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def can_write?
|
|
133
|
+
false
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Step 5: Extract reusable logic with Policy Rules
|
|
139
|
+
|
|
140
|
+
Up until now, authorization logic has lived directly inside policy methods.
|
|
141
|
+
|
|
142
|
+
For reusable or cross-cutting logic, AccessForge provides Policy Rules.
|
|
143
|
+
|
|
144
|
+
Policy Rules allow authorization behavior to be extracted, composed, and reused across policies without coupling policies to persistence or infrastructure concerns.
|
|
145
|
+
|
|
146
|
+
`AccessForge::Policy` exposes an `authorized?` helper:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
authorized?(rules, options = {})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
* `rules` — an array of Policy Rule classes
|
|
153
|
+
* `options` — optional parameters passed to each rule
|
|
154
|
+
|
|
155
|
+
If any rule returns `true`, authorization succeeds.
|
|
156
|
+
|
|
157
|
+
AccessForge includes two default rules:
|
|
158
|
+
* `OpenPolicyRule` — always grants access
|
|
159
|
+
* `ClosedPolicyRule` — always denies access
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
module AccessForge
|
|
163
|
+
class OpenPolicyRule
|
|
164
|
+
def self.authorized?(_user, _controller, _options)
|
|
165
|
+
true
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
class ClosedPolicyRule
|
|
170
|
+
def self.authorized?(_user, _controller, _options)
|
|
171
|
+
false
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
You may define custom rules:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
class PermissionPolicyRule
|
|
181
|
+
def self.authorized?(user, _controller, options)
|
|
182
|
+
permission_name = "Can #{options[:verb]} #{options[:feature]}"
|
|
183
|
+
user.permissions.exists?({ permissions: { name: permission_name } })
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
class EmployeePolicy < ApplicationPolicy
|
|
188
|
+
def index?
|
|
189
|
+
authorized?(
|
|
190
|
+
[ PermissionPolicyRule ],
|
|
191
|
+
{ feature: 'Employees', verb: :read }
|
|
192
|
+
)
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
This approach keeps policy classes focused while allowing authorization strategies to scale independently.
|
|
198
|
+
|
|
199
|
+
## Extensions
|
|
200
|
+
|
|
201
|
+
AccessForge is designed to be extended.
|
|
202
|
+
|
|
203
|
+
Official and third-party extensions may provide:
|
|
204
|
+
* Persistence-backed authorization strategies
|
|
205
|
+
* RBAC implementations
|
|
206
|
+
* Alternative rule sets
|
|
207
|
+
* Integration layers
|
|
208
|
+
|
|
209
|
+
Because policies depend only on rule interfaces, new strategies can be introduced without rewriting existing policies.
|
|
22
210
|
|
|
23
211
|
## Development
|
|
24
212
|
|
|
25
|
-
After checking out the
|
|
213
|
+
After checking out the repository:
|
|
214
|
+
```
|
|
215
|
+
bin/setup
|
|
216
|
+
rake spec
|
|
217
|
+
```
|
|
26
218
|
|
|
27
|
-
To
|
|
219
|
+
To release a new version:
|
|
220
|
+
1. Update the version number in `version.rb`
|
|
221
|
+
2. Run:
|
|
222
|
+
```
|
|
223
|
+
bundle exec rake release
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
This will tag the release, push commits, and publish the gem to RubyGems.
|
|
28
227
|
|
|
29
228
|
## Contributing
|
|
30
229
|
|
|
31
|
-
Bug reports and pull requests are welcome on GitHub
|
|
230
|
+
Bug reports and pull requests are welcome on GitHub:
|
|
231
|
+
|
|
232
|
+
[https://github.com/CodeTectonics/access_forge](https://github.com/CodeTectonics/access_forge).
|
|
233
|
+
|
|
234
|
+
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/CodeTectonics/access_forge/blob/main/CODE_OF_CONDUCT.md).
|
|
32
235
|
|
|
33
236
|
## License
|
|
34
237
|
|
|
@@ -36,4 +239,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
36
239
|
|
|
37
240
|
## Code of Conduct
|
|
38
241
|
|
|
39
|
-
Everyone interacting in the AccessForge project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
|
242
|
+
Everyone interacting in the AccessForge project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/CodeTectonics/access_forge/blob/main/CODE_OF_CONDUCT.md).
|
data/access_forge.gemspec
CHANGED
|
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
|
8
8
|
s.authors = ["Mark Harbison"]
|
|
9
9
|
s.email = ["mark@tyne-solutions.com"]
|
|
10
10
|
|
|
11
|
-
s.summary = "
|
|
12
|
-
s.description = "
|
|
11
|
+
s.summary = "Controller-oriented authorization with composable rule objects."
|
|
12
|
+
s.description = "Controller-oriented authorization with composable rule objects."
|
|
13
13
|
s.homepage = "https://github.com/CodeTectonics/access_forge"
|
|
14
14
|
s.license = "MIT"
|
|
15
15
|
s.required_ruby_version = ">= 2.6.0"
|
data/lib/access_forge/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: access_forge
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mark Harbison
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-02-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -52,7 +52,7 @@ dependencies:
|
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '1.7'
|
|
55
|
-
description:
|
|
55
|
+
description: Controller-oriented authorization with composable rule objects.
|
|
56
56
|
email:
|
|
57
57
|
- mark@tyne-solutions.com
|
|
58
58
|
executables: []
|
|
@@ -106,10 +106,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
106
106
|
- !ruby/object:Gem::Version
|
|
107
107
|
version: '0'
|
|
108
108
|
requirements: []
|
|
109
|
-
rubygems_version: 3.4.
|
|
109
|
+
rubygems_version: 3.4.19
|
|
110
110
|
signing_key:
|
|
111
111
|
specification_version: 4
|
|
112
|
-
summary:
|
|
112
|
+
summary: Controller-oriented authorization with composable rule objects.
|
|
113
113
|
test_files:
|
|
114
114
|
- spec/closed_policy_rule_spec.rb
|
|
115
115
|
- spec/dummy/dummy_controller.rb
|