public
Description: An authorization Rails plugin using a declarative DSL for specifying authorization rules in one place
Homepage:
Clone URL: git://github.com/stffn/declarative_authorization.git
034e6fce » stffn 2008-08-19 Expanded documentation 1 = Declarative Authorization
0ba24788 » stffn 2008-08-14 initial commit 2
034e6fce » stffn 2008-08-19 Expanded documentation 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.
0ba24788 » stffn 2008-08-14 initial commit 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
034e6fce » stffn 2008-08-19 Expanded documentation 32 * An authentication mechanism
33 * User object in Controller#current_user
d3c530e0 » stffn 2009-03-13 Fixing is_in short cut for ... 34 * (For model security) Setting Authorization.current_user
35 * User objects need to respond to a method :role_symbols that returns an
034e6fce » stffn 2008-08-19 Expanded documentation 36 array of role symbols
37 See below for installation instructions.
0ba24788 » stffn 2008-08-14 initial commit 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
651fe2b8 » stffn 2009-02-02 New if_attribute operators:... Comment 74 A fully functional example application can be found at
75 http://github.com/stffn/decl_auth_demo_app
76
5fb98ed9 » stffn 2009-02-25 Added hint to downloads and... 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
0ba24788 » stffn 2008-08-14 initial commit 80 == Controller
81
d763a2e6 » stffn 2009-08-12 Simplified controller autho... 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.
0ba24788 » stffn 2008-08-14 initial commit 102
6b67e37e » stffn 2009-02-12 Added information on testing 103 class EmployeesController < ApplicationController
0ba24788 » stffn 2008-08-14 initial commit 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
6b67e37e » stffn 2009-02-12 Added information on testing 115 class EmployeesController < ApplicationController
0ba24788 » stffn 2008-08-14 initial commit 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
6b67e37e » stffn 2009-02-12 Added information on testing 133 class EmployeesController < ApplicationController
0ba24788 » stffn 2008-08-14 initial commit 134 filter_access_to :update, :attribute_check => true
135 def update
a59b9dfe » stffn 2009-02-13 More information on filter_... 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])
0ba24788 » stffn 2008-08-14 initial commit 156 end
157 end
158
034e6fce » stffn 2008-08-19 Expanded documentation 159 If the access is denied, a +permission_denied+ method is called on the
a59b9dfe » stffn 2009-02-13 More information on filter_... 160 current_controller, if defined, and the issue is logged.
034e6fce » stffn 2008-08-19 Expanded documentation 161 For further customization of the filters and object loading, have a look at
162 the complete API documentation of filter_access_to in
0ba24788 » stffn 2008-08-14 initial commit 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
6b67e37e » stffn 2009-02-12 Added information on testing 171 <% permitted_to? :create, :employees do %>
0ba24788 » stffn 2008-08-14 initial commit 172 <%= link_to 'New', new_employee_path %>
173 <% end %>
6b67e37e » stffn 2009-02-12 Added information on testing 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
a59b9dfe » stffn 2009-02-13 More information on filter_... 179 <% permitted_to? :create, Branch.new(:company => @company) do
180 # or @company.branches.new
181 # or even @company.branches %>
6b67e37e » stffn 2009-02-12 Added information on testing 182 <%= link_to 'New', new_company_branch_path(@company) %>
183 <% end %>
184
185 Lists are straight-forward:
186
0ba24788 » stffn 2008-08-14 initial commit 187 <% for employee in @employees %>
6b67e37e » stffn 2009-02-12 Added information on testing 188 <%= link_to 'Edit', edit_employee_path(employee) if permitted_to? :update, employee %>
0ba24788 » stffn 2008-08-14 initial commit 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
034e6fce » stffn 2008-08-19 Expanded documentation 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
0ba24788 » stffn 2008-08-14 initial commit 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
034e6fce » stffn 2008-08-19 Expanded documentation 227 through named scopes. Thus,
0ba24788 » stffn 2008-08-14 initial commit 228
034e6fce » stffn 2008-08-19 Expanded documentation 229 Employee.with_permissions_to(:read)
0ba24788 » stffn 2008-08-14 initial commit 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
034e6fce » stffn 2008-08-19 Expanded documentation 235 Employee.with_permissions_to(:read).find(:all, :conditions => ...)
0ba24788 » stffn 2008-08-14 initial commit 236
034e6fce » stffn 2008-08-19 Expanded documentation 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.
0ba24788 » stffn 2008-08-14 initial commit 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
034e6fce » stffn 2008-08-19 Expanded documentation 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
0ba24788 » stffn 2008-08-14 initial commit 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.
6b67e37e » stffn 2009-02-12 Added information on testing 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):
0ba24788 » stffn 2008-08-14 initial commit 283
284 authorization do
285 role :branch_admin do
bbcfba75 » stffn 2008-09-19 Fixed typo in README example 286 has_permission_on :employees do
0ba24788 » stffn 2008-08-14 initial commit 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
4de68af3 » stffn 2009-01-30 Added if_permitted_to examp... 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
0ba24788 » stffn 2008-08-14 initial commit 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
6b67e37e » stffn 2009-02-12 Added information on testing 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
4de68af3 » stffn 2009-01-30 Added if_permitted_to examp... 359 = Installation of declarative_authorization
0ba24788 » stffn 2008-08-14 initial commit 360
ec3942be » stffn 2009-04-20 Documentation: installing a... 361 One of three options to install the plugin:
362 * Install by Gem: Add to your environment.rb in the initializer block:
13825829 » stffn 2009-10-12 Switching to gemcutter 363 config.gem "declarative_authorization"
364 Note: you need gemcutter support in place, i.e. call
365 gem install gemcutter
366 gem tumble
ec3942be » stffn 2009-04-20 Documentation: installing a... 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
5fb98ed9 » stffn 2009-02-25 Added hint to downloads and... 373
034e6fce » stffn 2008-08-19 Expanded documentation 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.
0ba24788 » stffn 2008-08-14 initial commit 380
034e6fce » stffn 2008-08-19 Expanded documentation 381 == Providing the Plugin's Requirements
382 The requirements are
4de68af3 » stffn 2009-01-30 Added if_permitted_to examp... 383 * Rails >= 2.1 and Ruby >= 1.8.6, including 1.9
034e6fce » stffn 2008-08-19 Expanded documentation 384 * An authentication mechanism
ec3942be » stffn 2009-04-20 Documentation: installing a... 385 * A user object returned by Controller#current_user
386 * An array of role symbols returned by User#role_symbols
d3c530e0 » stffn 2009-03-13 Fixing is_in short cut for ... 387 * (For model security) Setting Authorization.current_user to the request's user
0ba24788 » stffn 2008-08-14 initial commit 388
034e6fce » stffn 2008-08-19 Expanded documentation 389 Of the various ways to provide these requirements, here is one way employing
27e676a6 » stffn 2008-11-12 Added note about restful_au... 390 restful_authentication.
034e6fce » stffn 2008-08-19 Expanded documentation 391
392 * Install restful_authentication
393 cd vendor/plugins && git clone git://github.com/technoweenie/restful-authentication.git restful_authentication
6b67e37e » stffn 2009-02-12 Added information on testing 394 cd ../.. && ruby script/generate authenticated user sessions
034e6fce » stffn 2008-08-19 Expanded documentation 395 * Move "include AuthenticatedSystem" to ApplicationController
6b67e37e » stffn 2009-02-12 Added information on testing 396 * Add +filter_access_to+ calls as described above.
034e6fce » stffn 2008-08-19 Expanded documentation 397 * If you'd like to use model security, add a before_filter that sets the user
833b3e37 » stffn 2009-02-02 Changed user.roles to user.... Comment 398 globally to your ApplicationController. This is thread-safe.
034e6fce » stffn 2008-08-19 Expanded documentation 399 before_filter :set_current_user
400 protected
401 def set_current_user
402 Authorization.current_user = current_user
403 end
404
b7392f4c » stffn 2008-09-18 Fixed example in README 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
833b3e37 » stffn 2009-02-02 Changed user.roles to user.... Comment 430 has_many :roles
431 def role_symbols
432 (roles || []).map {|r| r.title.to_sym}
b7392f4c » stffn 2008-09-18 Fixed example in README 433 end
36ee6d9f » stffn 2008-09-09 clarified user and roles mo... 434 end
0ba24788 » stffn 2008-08-14 initial commit 435
153e38d0 » stffn 2008-09-30 Extended role model example 436 * add roles to your User objects using e.g.
833b3e37 » stffn 2009-02-02 Changed user.roles to user.... Comment 437 user.roles.create(:title => "admin")
153e38d0 » stffn 2008-09-30 Extended role model example 438
27e676a6 » stffn 2008-11-12 Added note about restful_au... 439 Note: If you choose to generate an Account model for restful_authentication
ec3942be » stffn 2009-04-20 Documentation: installing a... 440 instead of a User model as described above, you have to customize the
27e676a6 » stffn 2008-11-12 Added note about restful_au... 441 examples and create a ApplicationController#current_user method.
0ba24788 » stffn 2008-08-14 initial commit 442
833b3e37 » stffn 2009-02-02 Changed user.roles to user.... Comment 443
0ba24788 » stffn 2008-08-14 initial commit 444 == Debugging Authorization
445
034e6fce » stffn 2008-08-19 Expanded documentation 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.
0ba24788 » stffn 2008-08-14 initial commit 452
453
61b4418c » stffn 2009-02-13 Info on auth rules browser 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
781e3a4b » stffn 2009-02-13 Missing CHANGELOG entry 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
ec3942be » stffn 2009-04-20 Documentation: installing a... 471 and Ubuntu) and has only been tested under Linux.
61b4418c » stffn 2009-02-13 Info on auth rules browser 472
473
474 = Help and Contact
843d9883 » stffn 2008-12-29 Added links to the plugin's... 475
98b6850c » stffn 2009-09-13 Changed issue tracker URL i... 476 We have an issue tracker[http://github.com/stffn/declarative_authorization/issues]
843d9883 » stffn 2008-12-29 Added links to the plugin's... 477 for bugs and feature requests as well as a
478 Google Group[http://groups.google.com/group/declarative_authorization] for
d6d23817 » stffn 2009-01-20 Added a contributors section Comment 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.
843d9883 » stffn 2008-12-29 Added links to the plugin's... 482
483 Maintained by
0ba24788 » stffn 2008-08-14 initial commit 484
485 Steffen Bartsch
486 TZI, Universität Bremen, Germany
487 sbartsch at tzi.org
488
489
61b4418c » stffn 2009-02-13 Info on auth rules browser 490 = Contributors
d6d23817 » stffn 2009-01-20 Added a contributors section Comment 491
4de68af3 » stffn 2009-01-30 Added if_permitted_to examp... 492 Thanks to
e13ed8a1 » stffn 2009-07-20 Updated contributors 493 * Eike Carls
e23a48be » stffn 2009-03-24 Updated contributors 494 * Erik Dahlstrand
8477843b » stffn 2009-08-28 Updated contributors 495 * Jeroen van Dijk
e23a48be » stffn 2009-03-24 Updated contributors 496 * Jeremy Friesen
d6d23817 » stffn 2009-01-20 Added a contributors section Comment 497 * Brian Langenfeld
6116797e » stffn 2009-09-15 Updated contributors 498 * Georg Ledermann
e23a48be » stffn 2009-03-24 Updated contributors 499 * Geoff Longman
e13ed8a1 » stffn 2009-07-20 Updated contributors 500 * Olly Lylo
d6d23817 » stffn 2009-01-20 Added a contributors section Comment 501 * Mark Mansour
8477843b » stffn 2009-08-28 Updated contributors 502 * Thomas Maurer
d6d23817 » stffn 2009-01-20 Added a contributors section Comment 503 * Mike Vincent
504
505
61b4418c » stffn 2009-02-13 Info on auth rules browser 506 = Licence
0ba24788 » stffn 2008-08-14 initial commit 507
508 Copyright (c) 2008 Steffen Bartsch, TZI, Universität Bremen, Germany
509 released under the MIT license
510