ghart-declarative_authorization 0.3.2.4
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.
- data/CHANGELOG +83 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +510 -0
- data/Rakefile +43 -0
- data/app/controllers/authorization_rules_controller.rb +259 -0
- data/app/controllers/authorization_usages_controller.rb +23 -0
- data/app/helpers/authorization_rules_helper.rb +187 -0
- data/app/views/authorization_rules/_change.erb +58 -0
- data/app/views/authorization_rules/_show_graph.erb +37 -0
- data/app/views/authorization_rules/_suggestions.erb +48 -0
- data/app/views/authorization_rules/change.html.erb +152 -0
- data/app/views/authorization_rules/graph.dot.erb +68 -0
- data/app/views/authorization_rules/graph.html.erb +40 -0
- data/app/views/authorization_rules/index.html.erb +17 -0
- data/app/views/authorization_usages/index.html.erb +36 -0
- data/authorization_rules.dist.rb +20 -0
- data/config/routes.rb +7 -0
- data/garlic_example.rb +20 -0
- data/init.rb +5 -0
- data/lib/declarative_authorization.rb +15 -0
- data/lib/declarative_authorization/authorization.rb +634 -0
- data/lib/declarative_authorization/development_support/analyzer.rb +252 -0
- data/lib/declarative_authorization/development_support/change_analyzer.rb +253 -0
- data/lib/declarative_authorization/development_support/change_supporter.rb +620 -0
- data/lib/declarative_authorization/development_support/development_support.rb +243 -0
- data/lib/declarative_authorization/helper.rb +60 -0
- data/lib/declarative_authorization/in_controller.rb +597 -0
- data/lib/declarative_authorization/in_model.rb +159 -0
- data/lib/declarative_authorization/maintenance.rb +182 -0
- data/lib/declarative_authorization/obligation_scope.rb +308 -0
- data/lib/declarative_authorization/rails_legacy.rb +14 -0
- data/lib/declarative_authorization/reader.rb +441 -0
- data/test/authorization_test.rb +827 -0
- data/test/controller_filter_resource_access_test.rb +394 -0
- data/test/controller_test.rb +386 -0
- data/test/dsl_reader_test.rb +157 -0
- data/test/helper_test.rb +171 -0
- data/test/maintenance_test.rb +46 -0
- data/test/model_test.rb +1308 -0
- data/test/schema.sql +54 -0
- data/test/test_helper.rb +118 -0
- metadata +106 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
* Change Support: Suggestion grouping, sort by affected users [sb]
|
2
|
+
|
3
|
+
* Changed context derived from objects to #class.name.tableize to fix STI [sb]
|
4
|
+
|
5
|
+
* Simplified controller authorization with filter_resource_access [sb]
|
6
|
+
|
7
|
+
* Allow passing explicit context in addition to object in permitted_to? [Olly Lylo, sb]
|
8
|
+
|
9
|
+
* Change Supporter: suggest changes to authorization rules [sb]
|
10
|
+
|
11
|
+
* Added permitted_to!/? in model [Eike Carls]
|
12
|
+
|
13
|
+
* New test helper: should_(not_)_be_allowed_to(privilege, object_or_context) [sb]
|
14
|
+
|
15
|
+
** RELEASE 0.3 (April 20, 2009) **
|
16
|
+
|
17
|
+
* New option :join_by for has_permission_on to allow AND'ing of statements in one has_permission_on block [sb]
|
18
|
+
|
19
|
+
* Allow using_access_control to be called directly on ActiveRecord::Base, globally enabling model security [sb]
|
20
|
+
|
21
|
+
* New operator: intersects_with, comparing two Enumerables in if_attribute [sb]
|
22
|
+
|
23
|
+
* Improved if_permitted_to syntax: if the attribute is left out, permissions are checked on for the current object [sb]
|
24
|
+
|
25
|
+
* Added #has_role_with_hierarchy? method to retrieve explicit and calculated roles [jeremyf]
|
26
|
+
|
27
|
+
* Added a simple rules analyzer to help improve authorization rules [sb]
|
28
|
+
|
29
|
+
* Gemified plugin. Needed to restructure the lib path contents [sb]
|
30
|
+
|
31
|
+
* Added handling of Authorization::AuthorizationInController::ClassMethods.filter_access_to parameters that are of the form [:show, :update] instead of just :show, :update. [jeremyf]
|
32
|
+
|
33
|
+
* Added authorization usage helper for checking filter_access_to usage in controllers [sb]
|
34
|
+
|
35
|
+
* Added a authorization rules browser. See README for more information [sb]
|
36
|
+
|
37
|
+
* Added Model.using_access_control? to check if a model has model security activated [sb]
|
38
|
+
|
39
|
+
* Changed Authorization::ObligationScope#map_table_alias_for [Brian Langenfeld]
|
40
|
+
* Fixed to prevent bad aliases from being produced.
|
41
|
+
|
42
|
+
* Changed Authorization::Attribute#validate? [Brian Langenfeld]
|
43
|
+
* Encountering a nil value when evaluating an attribute now raises a NilAttributeValueError, instead of an AuthorizationError. We leave it to the caller to decide what to do about it.
|
44
|
+
|
45
|
+
* Changed Authorization::Engine#permit! [Brian Langenfeld]
|
46
|
+
* We now convert incoming privileges to symbols (e.g. 'read' is made equivalent to :read). This ensures the privileges will match those defined in the authorization rules file.
|
47
|
+
* The method now properly infers context when checking against an association (e.g. user.posts). We do this by leveraging ActiveRecord builder method 'new' to instantiate a proper object we can work with.
|
48
|
+
* When testing rules for positive results (via Authorization::Attribute#validate?), we now rescue NilAttributeValueError exceptions, simply causing the rule to return a negative result (instead of barfing).
|
49
|
+
|
50
|
+
* Changed Authorization::ObligationScope#rebuild_join_options! [Brian Langenfeld]
|
51
|
+
* If we're dealing with multiple obligations we have to check (i.e. ones that result in OR'd conditions), we now use :include instead of :joins for our generated scope. This does seem like a kludge, but until ActiveRecord scopes support unions (for checking obligations individually and consolidating the results), we don't have much choice. Something to revisit later, for sure.
|
52
|
+
|
53
|
+
** RELEASE 0.2 (February 2, 2009) **
|
54
|
+
|
55
|
+
* added negative operators: is_not, not_in, does_not_contain [sb]
|
56
|
+
|
57
|
+
* changed user.roles to user.role_symbols to reduce interferance with associations [sb]
|
58
|
+
|
59
|
+
* Ruby 1.9 and Rails 2.3 compatibility [sb]
|
60
|
+
|
61
|
+
* if_permitted_to for has_permission_on blocks for DRYer auth rules [sb]
|
62
|
+
|
63
|
+
* ObligationScope rewrite of query rewriting [Brian Langenfeld]
|
64
|
+
|
65
|
+
* changed exception hierarchy to begin at StandardError [sb]
|
66
|
+
|
67
|
+
* :is_in operator [sb]
|
68
|
+
|
69
|
+
* added has_role? helper [sb]
|
70
|
+
|
71
|
+
* made plugin thread-safe [sb]
|
72
|
+
|
73
|
+
* added maintenance and test helpers [sb]
|
74
|
+
|
75
|
+
* changed default permission denied response to 403 Forbidden [sb]
|
76
|
+
|
77
|
+
* descriptions for titles and roles [sb]
|
78
|
+
|
79
|
+
* fixed for PostgreSQL [Mark Mansour]
|
80
|
+
|
81
|
+
* improved DSL syntax: allow for array of contexts in has_permission_on [sb]
|
82
|
+
|
83
|
+
** RELEASE 0.1 (August 22, 2008) **
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,510 @@
|
|
1
|
+
= Declarative Authorization
|
2
|
+
|
3
|
+
The declarative authorization plugin offers an authorization mechanism inspired
|
4
|
+
by _RBAC_. The most notable distinction to existing authorization plugins is the
|
5
|
+
declarative authorization approach. That is, authorization rules are not
|
6
|
+
programmatically in between business logic but in an authorization configuration.
|
7
|
+
|
8
|
+
Currently, Rails authorization plugins only provide for programmatic
|
9
|
+
authorization rules. That is, the developer needs to specify which roles are
|
10
|
+
allowed to access a specific controller action or a part of a view, which is
|
11
|
+
not DRY. With a growing application code base and functions, as it happens
|
12
|
+
especially in agile development processes, it may be decided to introduce new
|
13
|
+
roles. Then, at several places of the source code the new group needs to be
|
14
|
+
added, possibly leading to omissions and thus hard to test errors. Another
|
15
|
+
aspect are changing authorization requirements in development or
|
16
|
+
even after taking the application into production. Then, privileges of
|
17
|
+
certain roles need to be easily adjusted when the original assumptions
|
18
|
+
concerning access control prove unrealistic. In these situations, a
|
19
|
+
declarative approach as offered by this plugin increases the development
|
20
|
+
and maintenance efficiency.
|
21
|
+
|
22
|
+
Plugin features
|
23
|
+
* Authorization at controller action level
|
24
|
+
* Authorization helpers for Views
|
25
|
+
* Authorization at model level
|
26
|
+
* Authorize CRUD (Create, Read, Update, Delete) activities
|
27
|
+
* Query rewriting to automatically only fetch authorized records
|
28
|
+
* DSL for specifying Authorization rules in an authorization configuration
|
29
|
+
|
30
|
+
|
31
|
+
Requirements
|
32
|
+
* An authentication mechanism
|
33
|
+
* User object in Controller#current_user
|
34
|
+
* (For model security) Setting Authorization.current_user
|
35
|
+
* User objects need to respond to a method :role_symbols that returns an
|
36
|
+
array of role symbols
|
37
|
+
See below for installation instructions.
|
38
|
+
|
39
|
+
|
40
|
+
= Authorization Data Model
|
41
|
+
|
42
|
+
----- App domain ----|-------- Authorization conf ---------|------- App domain ------
|
43
|
+
|
44
|
+
includes includes
|
45
|
+
.--. .---.
|
46
|
+
| v | v
|
47
|
+
.------. can_play .------. has_permission .------------. requires .----------.
|
48
|
+
| User |----------->| Role |----------------->| Permission |<-----------| Activity |
|
49
|
+
'------' * * '------' * * '------------' 1 * '----------'
|
50
|
+
|
|
51
|
+
.-------+------.
|
52
|
+
1 / | 1 \ *
|
53
|
+
.-----------. .---------. .-----------.
|
54
|
+
| Privilege | | Context | | Attribute |
|
55
|
+
'-----------' '---------' '-----------'
|
56
|
+
|
57
|
+
In the application domain, each *User* may be assigned to *Roles* that should
|
58
|
+
define the users' job in the application, such as _Administrator_. On the
|
59
|
+
right-hand side of this diagram, application developers specify which *Permissions*
|
60
|
+
are necessary for users to perform activities, such as calling a controller action,
|
61
|
+
viewing parts of a View or acting on records in the database. Note that
|
62
|
+
Permissions consist of an *Privilege* that is to be performed, such as _read_,
|
63
|
+
and a *Context* in that the Operation takes place, such as _companies_.
|
64
|
+
|
65
|
+
In the authorization configuration, Permissions are assigned to Roles and Role
|
66
|
+
and Permission hierarchies are defined. *Attributes* may be employed to allow
|
67
|
+
authorization according to dynamic information about the context and the
|
68
|
+
current user, e.g. "only allow access on employees that belong to the
|
69
|
+
current user's branch."
|
70
|
+
|
71
|
+
|
72
|
+
= Examples
|
73
|
+
|
74
|
+
A fully functional example application can be found at
|
75
|
+
http://github.com/stffn/decl_auth_demo_app
|
76
|
+
|
77
|
+
Details on the demonstrated methods can be found in the API docs, either
|
78
|
+
generated yourself or at http://www.tzi.org/~sbartsch/declarative_authorization
|
79
|
+
|
80
|
+
== Controller
|
81
|
+
|
82
|
+
If authentication is in place, there are two ways to enable user-specific
|
83
|
+
access control on controller actions. For resource controllers, which more
|
84
|
+
or less follow the CRUD pattern, +filter_resource_access+ is the simplest
|
85
|
+
approach. It sets up instance variables in before filters and calls
|
86
|
+
filter_access_to with the appropriate parameters to protect the CRUD methods.
|
87
|
+
|
88
|
+
class EmployeesController < ApplicationController
|
89
|
+
filter_resource_access
|
90
|
+
...
|
91
|
+
end
|
92
|
+
|
93
|
+
See Authorization::AuthorizationInController::ClassMethods for options on
|
94
|
+
nested resources and custom member and collection actions.
|
95
|
+
|
96
|
+
If you prefer less magic or your controller has no resemblance with the resource
|
97
|
+
controllers, directly calling filter_access_to may be the better option. Examples
|
98
|
+
are given in the following. E.g. the privilege index users is required for
|
99
|
+
action index. This works as a first default configuration for RESTful
|
100
|
+
controllers, with these privileges easily handled in the authorization
|
101
|
+
configuration, which will be described below.
|
102
|
+
|
103
|
+
class EmployeesController < ApplicationController
|
104
|
+
filter_access_to :all
|
105
|
+
def index
|
106
|
+
...
|
107
|
+
end
|
108
|
+
...
|
109
|
+
end
|
110
|
+
|
111
|
+
When custom actions are added to such a controller, it helps to define more
|
112
|
+
clearly which privileges are the respective requirements. That is when the
|
113
|
+
filter_access_to call may become more verbose:
|
114
|
+
|
115
|
+
class EmployeesController < ApplicationController
|
116
|
+
filter_access_to :all
|
117
|
+
# this one would be included in :all, but :read seems to be
|
118
|
+
# a more suitable privilege than :auto_complete_for_user_name
|
119
|
+
filter_access_to :auto_complete_for_employee_name, :require => :read
|
120
|
+
def auto_complete_for_employee_name
|
121
|
+
...
|
122
|
+
end
|
123
|
+
...
|
124
|
+
end
|
125
|
+
|
126
|
+
For some actions it might be necessary to check certain attributes of the
|
127
|
+
object the action is to be acting on. Then, the object needs to be loaded
|
128
|
+
before the action's access control is evaluated. On the other hand, some actions
|
129
|
+
might prefer the authorization to ignore specific attribute checks as the object is
|
130
|
+
unknown at checking time, so attribute checks and thus automatic loading of
|
131
|
+
objects needs to be enabled explicitly.
|
132
|
+
|
133
|
+
class EmployeesController < ApplicationController
|
134
|
+
filter_access_to :update, :attribute_check => true
|
135
|
+
def update
|
136
|
+
# @employee is already loaded from param[:id] because of :attribute_check
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
You can provide the needed object through before_filters. This way, you have
|
141
|
+
full control over the object that the conditions are checked against. Just make
|
142
|
+
sure, your before_filters occur before any of the filter_access_to calls.
|
143
|
+
|
144
|
+
class EmployeesController < ApplicationController
|
145
|
+
before_filter :new_employee_from_params, :only => :create
|
146
|
+
before_filter :new_employee, :only => [:index, :new]
|
147
|
+
filter_access_to :all, :attribute_check => true
|
148
|
+
|
149
|
+
def create
|
150
|
+
@employee.save!
|
151
|
+
end
|
152
|
+
|
153
|
+
protected
|
154
|
+
def new_employee_from_params
|
155
|
+
@employee = Employee.new(params[:employee])
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
If the access is denied, a +permission_denied+ method is called on the
|
160
|
+
current_controller, if defined, and the issue is logged.
|
161
|
+
For further customization of the filters and object loading, have a look at
|
162
|
+
the complete API documentation of filter_access_to in
|
163
|
+
Authorization::AuthorizationInController::ClassMethods.
|
164
|
+
|
165
|
+
|
166
|
+
== Views
|
167
|
+
|
168
|
+
In views, a simple permitted_to? helper makes showing blocks according to the
|
169
|
+
current user's privileges easy:
|
170
|
+
|
171
|
+
<% permitted_to? :create, :employees do %>
|
172
|
+
<%= link_to 'New', new_employee_path %>
|
173
|
+
<% end %>
|
174
|
+
|
175
|
+
Only giving a symbol :employees as context prevents any checks of attributes
|
176
|
+
as there is no object to check against. For example, in case of nested resources
|
177
|
+
a new object may come in handy:
|
178
|
+
|
179
|
+
<% permitted_to? :create, Branch.new(:company => @company) do
|
180
|
+
# or @company.branches.new
|
181
|
+
# or even @company.branches %>
|
182
|
+
<%= link_to 'New', new_company_branch_path(@company) %>
|
183
|
+
<% end %>
|
184
|
+
|
185
|
+
Lists are straight-forward:
|
186
|
+
|
187
|
+
<% for employee in @employees %>
|
188
|
+
<%= link_to 'Edit', edit_employee_path(employee) if permitted_to? :update, employee %>
|
189
|
+
<% end %>
|
190
|
+
|
191
|
+
See also Authorization::AuthorizationHelper.
|
192
|
+
|
193
|
+
|
194
|
+
== Models
|
195
|
+
|
196
|
+
There are two destinct features for model security built into this plugin:
|
197
|
+
authorizing CRUD operations on objects as well as query rewriting to limit
|
198
|
+
results according to certain privileges.
|
199
|
+
|
200
|
+
See also Authorization::AuthorizationInModel.
|
201
|
+
|
202
|
+
=== Model security for CRUD opterations
|
203
|
+
To activate model security, all it takes is an explicit enabling for each
|
204
|
+
model that model security should be enforced on, i.e.
|
205
|
+
|
206
|
+
class Employee < ActiveRecord::Base
|
207
|
+
using_access_control
|
208
|
+
...
|
209
|
+
end
|
210
|
+
|
211
|
+
Thus,
|
212
|
+
Employee.create(...)
|
213
|
+
fails, if the current user is not allowed to :create :employees according
|
214
|
+
to the authorization rules. For the application to find out about what
|
215
|
+
happened if an operation is denied, the filters throw
|
216
|
+
Authorization::NotAuthorized exceptions.
|
217
|
+
|
218
|
+
As access control on read are costly, with possibly lots of objects being
|
219
|
+
loaded at a time in one query, checks on read need to be actived explicitly by
|
220
|
+
adding the :include_read option.
|
221
|
+
|
222
|
+
=== Query rewriting using named scopes
|
223
|
+
When retrieving large sets of records from databases, any authorization needs
|
224
|
+
to be integrated into the query in order to prevent inefficient filtering
|
225
|
+
afterwards and to use LIMIT and OFFSET in SQL statements. To keep authorization
|
226
|
+
rules out of the source code, this plugin offers query rewriting mechanisms
|
227
|
+
through named scopes. Thus,
|
228
|
+
|
229
|
+
Employee.with_permissions_to(:read)
|
230
|
+
|
231
|
+
returns all employee records that the current user is authorized to read. In
|
232
|
+
addition, just like normal named scopes, query rewriting may be chained with
|
233
|
+
the usual find method:
|
234
|
+
|
235
|
+
Employee.with_permissions_to(:read).find(:all, :conditions => ...)
|
236
|
+
|
237
|
+
If the current user is completely missing the permissions, an
|
238
|
+
Authorization::NotAuthorized exception is raised. Through
|
239
|
+
Model.obligation_conditions, application developers may retrieve
|
240
|
+
the conditions for manual rewrites.
|
241
|
+
|
242
|
+
|
243
|
+
== Authorization Rules
|
244
|
+
|
245
|
+
Authorization rules are defined in config/authorization_rules.rb. E.g.
|
246
|
+
|
247
|
+
authorization do
|
248
|
+
role :admin do
|
249
|
+
has_permission_on :employees, :to => [:create, :read, :update, :delete]
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
There is a default role :+guest+ that is used if a request is not associated
|
254
|
+
with any user or with a user without any roles. So, if your application has
|
255
|
+
public pages, :+guest+ can be used to allow access for users that are not
|
256
|
+
logged in. All other roles are application defined and need to be associated
|
257
|
+
with users by the application.
|
258
|
+
|
259
|
+
Privileges, such as :create, may be put into hierarchies to simplify
|
260
|
+
maintenance. So the example above has the same meaning as
|
261
|
+
|
262
|
+
authorization do
|
263
|
+
role :admin do
|
264
|
+
has_permission_on :employees, :to => :manage
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
privileges do
|
269
|
+
privilege :manage do
|
270
|
+
includes :create, :read, :update, :delete
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
Privilege hierarchies may be context-specific, e.g. applicable to :employees.
|
275
|
+
|
276
|
+
privileges do
|
277
|
+
privilege :manage, :employees, :includes => :increase_salary
|
278
|
+
end
|
279
|
+
|
280
|
+
For more complex use cases, authorizations need to be based on attributes. E.g.
|
281
|
+
if a branch admin should manage only employees of his branch (see
|
282
|
+
Authorization::Reader in the API docs for a full list of available operators):
|
283
|
+
|
284
|
+
authorization do
|
285
|
+
role :branch_admin do
|
286
|
+
has_permission_on :employees do
|
287
|
+
to :manage
|
288
|
+
# user refers to the current_user when evaluating
|
289
|
+
if_attribute :branch => is {user.branch}
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
To reduce redundancy in has_permission_on blocks, a rule may depend on
|
295
|
+
permissions on associated objects:
|
296
|
+
|
297
|
+
authorization do
|
298
|
+
role :branch_admin do
|
299
|
+
has_permission_on :branches, :to => :manage do
|
300
|
+
if_attribute :managers => contains {user}
|
301
|
+
end
|
302
|
+
|
303
|
+
has_permission_on :employees, :to => :manage do
|
304
|
+
if_permitted_to :manage, :branch
|
305
|
+
# instead of
|
306
|
+
#if_attribute :branch => {:managers => contains {user}}
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
Lastly, not only privileges may be organized in a hierarchy but roles as well.
|
312
|
+
Here, project manager inherit the permissions of employees.
|
313
|
+
|
314
|
+
role :project_manager do
|
315
|
+
includes :employee
|
316
|
+
end
|
317
|
+
|
318
|
+
See also Authorization::Reader.
|
319
|
+
|
320
|
+
== Testing
|
321
|
+
|
322
|
+
declarative_authorization provides a few helpers to ease the testing with
|
323
|
+
authorization in mind.
|
324
|
+
|
325
|
+
In your test_helper.rb, to enable the helpers add
|
326
|
+
|
327
|
+
require File.expand_path(File.dirname(__FILE__) +
|
328
|
+
"/../vendor/plugins/declarative_authorization/lib/maintenance")
|
329
|
+
|
330
|
+
class Test::Unit::TestCase
|
331
|
+
include Authorization::TestHelper
|
332
|
+
...
|
333
|
+
end
|
334
|
+
|
335
|
+
Now, in unit tests, you may deactivate authorization if needed e.g. for test
|
336
|
+
setup and assume certain identities for tests:
|
337
|
+
|
338
|
+
class EmployeeTest < ActiveSupport::TestCase
|
339
|
+
def test_should_read
|
340
|
+
without_access_control do
|
341
|
+
Employee.create(...)
|
342
|
+
end
|
343
|
+
assert_nothing_raised do
|
344
|
+
with_user(admin) do
|
345
|
+
Employee.find(:first)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
In functional tests, get, posts, etc. may be tested in the name of certain users:
|
352
|
+
|
353
|
+
get_with admin, :index
|
354
|
+
post_with admin, :update, :employee => {...}
|
355
|
+
|
356
|
+
See Authorization::TestHelper for more information.
|
357
|
+
|
358
|
+
|
359
|
+
= Installation of declarative_authorization
|
360
|
+
|
361
|
+
One of three options to install the plugin:
|
362
|
+
* Install by Gem: Add to your environment.rb in the initializer block:
|
363
|
+
config.gem "declarative_authorization"
|
364
|
+
Note: you need gemcutter support in place, i.e. call
|
365
|
+
gem install gemcutter
|
366
|
+
gem tumble
|
367
|
+
And call from your application's root directory
|
368
|
+
rake gems:install
|
369
|
+
* Alternatively, to install from github, execute in your application's root directory
|
370
|
+
cd vendor/plugins && git clone git://github.com/stffn/declarative_authorization.git
|
371
|
+
* Or, download one of the released versions from Github at
|
372
|
+
http://github.com/stffn/declarative_authorization/downloads
|
373
|
+
|
374
|
+
Then,
|
375
|
+
* provide the requirements as noted below,
|
376
|
+
* create a basic config/authorization_rules.rb--you might want to take the
|
377
|
+
provided example authorization_rules.dist.rb in the plugin root as a starting
|
378
|
+
point,
|
379
|
+
* add +filter_access_to+, +permitted_to+? and model security as needed.
|
380
|
+
|
381
|
+
== Providing the Plugin's Requirements
|
382
|
+
The requirements are
|
383
|
+
* Rails >= 2.1 and Ruby >= 1.8.6, including 1.9
|
384
|
+
* An authentication mechanism
|
385
|
+
* A user object returned by Controller#current_user
|
386
|
+
* An array of role symbols returned by User#role_symbols
|
387
|
+
* (For model security) Setting Authorization.current_user to the request's user
|
388
|
+
|
389
|
+
Of the various ways to provide these requirements, here is one way employing
|
390
|
+
restful_authentication.
|
391
|
+
|
392
|
+
* Install restful_authentication
|
393
|
+
cd vendor/plugins && git clone git://github.com/technoweenie/restful-authentication.git restful_authentication
|
394
|
+
cd ../.. && ruby script/generate authenticated user sessions
|
395
|
+
* Move "include AuthenticatedSystem" to ApplicationController
|
396
|
+
* Add +filter_access_to+ calls as described above.
|
397
|
+
* If you'd like to use model security, add a before_filter that sets the user
|
398
|
+
globally to your ApplicationController. This is thread-safe.
|
399
|
+
before_filter :set_current_user
|
400
|
+
protected
|
401
|
+
def set_current_user
|
402
|
+
Authorization.current_user = current_user
|
403
|
+
end
|
404
|
+
|
405
|
+
* Add roles field to the User model through a :+has_many+ association
|
406
|
+
(this is just one possible approach; you could just as easily use
|
407
|
+
:+has_many+ :+through+ or a serialized roles array):
|
408
|
+
* create a migration for table roles
|
409
|
+
class CreateRoles < ActiveRecord::Migration
|
410
|
+
def self.up
|
411
|
+
create_table "roles" do |t|
|
412
|
+
t.column :title, :string
|
413
|
+
t.references :user
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def self.down
|
418
|
+
drop_table "roles"
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
* create a model Role,
|
423
|
+
class Role < ActiveRecord::Base
|
424
|
+
belongs_to :user
|
425
|
+
end
|
426
|
+
|
427
|
+
* add +has_many+ :+roles+ to the User model and a roles method that returns the roles
|
428
|
+
as an Array of Symbols, e.g.
|
429
|
+
class User < ActiveRecord::Base
|
430
|
+
has_many :roles
|
431
|
+
def role_symbols
|
432
|
+
(roles || []).map {|r| r.title.to_sym}
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
* add roles to your User objects using e.g.
|
437
|
+
user.roles.create(:title => "admin")
|
438
|
+
|
439
|
+
Note: If you choose to generate an Account model for restful_authentication
|
440
|
+
instead of a User model as described above, you have to customize the
|
441
|
+
examples and create a ApplicationController#current_user method.
|
442
|
+
|
443
|
+
|
444
|
+
== Debugging Authorization
|
445
|
+
|
446
|
+
Currently, the main means of debugging authorization decisions is logging and
|
447
|
+
exceptions. Denied access to actions is logged to +warn+ or +info+, including
|
448
|
+
some hints about what went wrong.
|
449
|
+
|
450
|
+
All bang methods throw exceptions which may be used to retrieve more
|
451
|
+
information about a denied access than a Boolean value.
|
452
|
+
|
453
|
+
|
454
|
+
== Authorization Browser
|
455
|
+
|
456
|
+
If your authorization rules become more complex, you might be glad to use
|
457
|
+
the authorization rules browser that comes with declarative_authorization.
|
458
|
+
It has a syntax-highlighted and a graphical view with filtering of the current
|
459
|
+
authorization rules.
|
460
|
+
|
461
|
+
By default, it will only be available in development mode. To use it, add
|
462
|
+
the following lines to your authorization_rules.rb for the appropriate role:
|
463
|
+
|
464
|
+
has_permission_on :authorization_rules, :to => :read
|
465
|
+
|
466
|
+
Then, point your browser to
|
467
|
+
http://localhost/authorization_rules
|
468
|
+
|
469
|
+
The browser needs Rails 2.3 (for Engine support). The graphical view requires
|
470
|
+
Graphviz (which e.g. can be installed through the graphviz package under Debian
|
471
|
+
and Ubuntu) and has only been tested under Linux.
|
472
|
+
|
473
|
+
|
474
|
+
= Help and Contact
|
475
|
+
|
476
|
+
We have an issue tracker[http://github.com/stffn/declarative_authorization/issues]
|
477
|
+
for bugs and feature requests as well as a
|
478
|
+
Google Group[http://groups.google.com/group/declarative_authorization] for
|
479
|
+
discussions on the usage of the plugin. You are very welcome to contribute.
|
480
|
+
Just fork the git repository and create a new issue, send a pull request or
|
481
|
+
contact me personally.
|
482
|
+
|
483
|
+
Maintained by
|
484
|
+
|
485
|
+
Steffen Bartsch
|
486
|
+
TZI, Universität Bremen, Germany
|
487
|
+
sbartsch at tzi.org
|
488
|
+
|
489
|
+
|
490
|
+
= Contributors
|
491
|
+
|
492
|
+
Thanks to
|
493
|
+
* Eike Carls
|
494
|
+
* Erik Dahlstrand
|
495
|
+
* Jeroen van Dijk
|
496
|
+
* Jeremy Friesen
|
497
|
+
* Brian Langenfeld
|
498
|
+
* Georg Ledermann
|
499
|
+
* Geoff Longman
|
500
|
+
* Olly Lylo
|
501
|
+
* Mark Mansour
|
502
|
+
* Thomas Maurer
|
503
|
+
* Mike Vincent
|
504
|
+
|
505
|
+
|
506
|
+
= Licence
|
507
|
+
|
508
|
+
Copyright (c) 2008 Steffen Bartsch, TZI, Universität Bremen, Germany
|
509
|
+
released under the MIT license
|
510
|
+
|