authorization-rails 1.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,170 @@
1
+ TO DO
2
+ + Add Right model generator and DB-backed way of handling rights in addition to inlined "permit" checks
3
+ + Added namespacing to @options instance variable to prevent possible name clashes
4
+ + Add test generator instead of handling tests in test apps
5
+ + Add support for groups
6
+ + Extend grammar to allow "(admin or moderator or some_role) of some_model" (?) [Chris Hapgood]
7
+ + Extend coverage to models. Look at Bruce Perens's ModelSecurity and access with_scope. (9/3006 - Recently investigated extension to model and the most programmer-friendly DSLs may require too much hacking on ActiveRecord.)
8
+
9
+
10
+ CHANGES (from most recent to oldest)
11
+
12
+
13
+ === 1.0.10 release (February 27, 2008)
14
+
15
+ * Patch Series : Granular redirection configuration submitted by Thomas Weibel
16
+
17
+ WARNING : If you are upgrading from a previous install you may need
18
+ to change some configuration settings in your environment.rb file.
19
+
20
+ Remove DEFAULT_REDIRECTION_HASH config
21
+ Added granular LOGIN_REQUIRED_REDIRECTION hash or path config
22
+ Added granular PERMISSION_DENIED_REDIRECTION hash or path config
23
+ Added STORE_LOCATION_METHOD config
24
+ Support custom flash messages for each redirection type
25
+ Updated README.txt to provide instructions.
26
+ Enhanced support for integration with restful_authentication plugin.
27
+
28
+ === 1.0.9 release (February 26, 2008)
29
+
30
+ * Patch #8571 : Add type argument to is_role_of_what submitted by Aslak Hellesøy (aslak_hellesoy)
31
+
32
+ In my RESTful index views for an AR type I often want to list all of the records *for a given type* for which the current
33
+ user has the role "show". (As opposed to getting *any* record for which the user has the role)
34
+
35
+ In order to achieve this, I have patched identity.rb so tht I can do this:
36
+
37
+ def index
38
+ if current_user.permit? 'admin'
39
+ # show all projects
40
+ @projects = Project.find(:all)
41
+ else
42
+ @projects = current_user.is_show_for_what(Project)
43
+ end
44
+ end
45
+
46
+ === 1.0.8 release (February 26, 2008)
47
+
48
+ * Patch #11352 : Fixes a bug with role_regex and simple quoted roles submitted by 'a French RoR developer'
49
+
50
+ Documentation says:
51
+
52
+ <role> ::= /\w+/ | /'.*'/
53
+
54
+ But the next permission string isn't well parsed: " 'abcd:efgh' or 'abcd:ijkl' "
55
+ You get an error because the role_regex defined in parser.rb eats every simple quote between the first and the last
56
+ simple quote in the string.
57
+
58
+ So i patched the two instances of role_regex in parser.rb, from this:
59
+ role_regex = '\s*(\'\s*(.+)\s*\'|([A-Za-z]\w*))\s*'
60
+
61
+ to this (the question mark ends the first pattern as soon as possible, avoiding the inner simple quotes to be eaten):
62
+ role_regex = '\s*(\'\s*(.+?)\s*\'|([A-Za-z]\w*))\s*'
63
+
64
+ === 1.0.7 release (February 25, 2008)
65
+
66
+ * Patch #9431 : Fixes a bug in identity.rb submitted by Michel Martens (blaumag)
67
+
68
+ If some authorizable instance accepts a role, then it responds true when queried for has_[role_name]?
69
+
70
+ Example:
71
+ country.has_kings? #=> false
72
+
73
+ user.has_role "king", country
74
+ country.has_kings? #=> true
75
+
76
+ user.has_no_role "king", country
77
+ country.has_kings? #=> true
78
+
79
+ The last time, country.has_kings? should be false.
80
+
81
+ === 1.0.6 release (February 25, 2008)
82
+
83
+ * Patch #12170 : Additional HABTM options for acts_as_authorized_user
84
+ A very simple patch that allows options to be passed to the has_and_belogs_to_many relationship. This seems necessary
85
+ if the "User" object has a different name from the table name. has_and_belong_to_many does not automatically
86
+ use the table set by the "User" object so it must be specified (along with the foreign key if applicable).
87
+
88
+ Patch submitted by Eric Anderson (eric1234)
89
+
90
+ === 1.0.5 release (February 25, 2008)
91
+
92
+ * Feature : Add additional test for current_user being set to the symbol ':false'.
93
+ This is for compatibility with the restful_authentication plugin which will
94
+ set current_user to :false on a bad login. Previously we were only testing
95
+ for current_user.nil? which was incomplete.
96
+
97
+ === 1.0.4 release (February 25, 2008)
98
+
99
+ * Bugfix : RubyForge bug #9368. Problems with about.yml
100
+ Fixes a minor bug in the about.yml plugin metadata file
101
+ so that it will parse cleanly. [GR]
102
+
103
+ === 1.0.3 release (February 17, 2008)
104
+
105
+ * Minor changes to USAGE text for ./script/generate role_model
106
+
107
+ === 1.0.2 release (February 17, 2008)
108
+
109
+ * From this release forward the plugin requires use of Ruby on Rails version 2.x. Version 1.0.1 is the final release fully compatible with Rails 1.2.x.
110
+ * Upgraded the database migration generator to create the new Rails 2.0.x style 'sexy migrations'.
111
+
112
+ === 1.0.1 release (February 17, 2008)
113
+
114
+ * Moved source code to public Git repository at GitHub.com (http://github.com/DocSavage/rails-authorization-plugin/tree/master)
115
+ * Removed attr_protected declaration from acts_as_authorized_user, acts_as_authorizable methods. These conflicted with usage of the Authorization plugin with models generated by the restful_authentication generator or any model that specified the safer attr_accessible whitelist. RA encourages the safer attr_accessible whitelisting of attributes that are accessible from its models. You cannot apply both attr_accessible and attr_protected in the same model. Users are encouraged to specify a whitelist of attr_accessible model attributes for their applications security. [grempe]
116
+
117
+ === SVN
118
+
119
+ * Performance improvement for has_role? [Sean Geoghegan]
120
+
121
+ * Allow customization of message on redirection after failed authorization (:redirect_message option) [Joey Geiger]
122
+
123
+ * Patch to allow authorizable objects that use single table inheritance (STI) [Sean Geoghegan]
124
+
125
+ === 1.0 release (Sept 13, 2006)
126
+
127
+ * Added attr_protected for habtm and has_many role ids to block security concern if developers use update_attributes(params[:auth_obj]) on an authorizable object [Michael Schuerig]
128
+
129
+ * Use before_filter rather than prepend_before_filter so necessary instance variables (and methods) can be established before trying authorization checks. This fix came about for Mephisto blog where a class-level permit "admin of site" was used. The site attribute was set in a before_filter. If you prepend your authorization filter, it will execute before any other before_filter, which is probably not a good idea.
130
+
131
+ * Add "about" yaml for future Rails plugin directory.
132
+
133
+ * Cleaned up exception handling a little [due to suggestion by Michael Schuerig]
134
+
135
+ * Add generator for role model and migration, e.g., "script/generate role_model Role".
136
+ Role model must be called "Role" at this time. More general naming as a TO DO.
137
+
138
+ * Removed simple_roles_table to simplify plugin.
139
+
140
+ * Moved all files in Authorization namespace into /publishare subdirectory
141
+ to reduce danger of clashes in load path [nod to Michael Schuerig].
142
+
143
+ * Small code refinement patch [Michael Schuerig]
144
+
145
+ * The colon preceding a model name in the authorization expression is now optional. The parser uses accepted prepositions to disambiguate models from roles.
146
+
147
+ * Change default parser from Recursive Descent parser to Eval parser.
148
+ Currently implemented recursive descent parser doesn't handle left-sided
149
+ boolean expressions well. Eval parser relies on Ruby (good thing), but
150
+ wherever there's an eval, we have to be more careful.
151
+
152
+ * Will start linking to and monitoring forum area at RubyForge
153
+ http://rubyforge.org/forum/?group_id=1797
154
+
155
+ * Added changelog :)
156
+
157
+ * Added return false to handle_redirection to short-circuit filters if
158
+ redirect occurs. This is second fix to prevent double renders.
159
+
160
+ * Changed the requires to pull files from the plugin directory. (Necessary for name conflicts between plugin and apps)
161
+
162
+ * Minor fixes to update documentation
163
+
164
+ === 1.0 rc3 (July 19, 2006)
165
+
166
+ * Fix to prevent double redirect
167
+
168
+ * Fix to migration examples
169
+
170
+ ... see svn log
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006 William T Katz
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.
@@ -0,0 +1,512 @@
1
+ = Authorization plugin
2
+
3
+ This plugin provides a flexible way to add authorization to Rails.
4
+
5
+ The authorization process decides whether a user is allowed access to some
6
+ feature. It is distinct from the authentication process, which tries to
7
+ confirm a user is authentic, not an imposter. There are many authentication
8
+ systems available for Rails, e.g., acts_as_authenticated and LoginEngine. This
9
+ authorization system will play nicely with them as long as some simple
10
+ requirements are met:
11
+
12
+ 1. User objects are available that implement a has_role?(role,
13
+ authorizable_object = nil) method. This requirement can be easily
14
+ handled by using acts_as_authorized_user in the User-like class.
15
+
16
+ 2. If you want to use "role of model" authorization expressions, like "owner of
17
+ resource" or "eligible for :award", then your models with roles must
18
+ implement an accepts_role?(role, user) method. This requirement can
19
+ be handled by using acts_as_authorizable in the model class.
20
+
21
+ The authorization plugin provides the following:
22
+
23
+ * A simple way of checking authorization at either the class or instance method
24
+ level using #permit and #permit?
25
+
26
+ * Authorization using roles for the entire application, a model class, or an
27
+ instance of a model (i.e., a particular object).
28
+
29
+ * Some english-like dynamic methods that draw on the defined roles. You will be
30
+ able to use methods like "user.is_fan_of angelina" or "angelina.has_fans?",
31
+ where a 'fan' is only defined in the roles table.
32
+
33
+ * Pick-and-choose a mixin for your desired level of database complexity. For
34
+ all the features, you will want to use "object roles table" (see below)
35
+
36
+
37
+ == Example Usage
38
+
39
+ class MeetingController < ApplicationController
40
+
41
+ permit "rubyists and wanna_be_rubyists", :except => :public_page
42
+
43
+ def public_page
44
+ render :text => "We're all in Chicago"
45
+ end
46
+
47
+ def secret_info
48
+ permit "interested in Answers and (matz or dhh)" do
49
+ render :text => "The Answer = 42"
50
+ end
51
+ end
52
+
53
+ def find_apprentice
54
+ @founder = User.find_by_name('matz')
55
+ permit "'inner circle' of :founder" do
56
+ if request.post?
57
+ apprentice = User.find_by_skillset(params[:uber_hacker])
58
+ ruby_community = Group.find_by_name('Ruby')
59
+ ruby_community.accepts_role 'yarv_builder', apprentice
60
+ end
61
+ end
62
+ end
63
+
64
+ def rails_conf
65
+ @meeting = Meeting.find_by_name('RailsConf')
66
+ permit "attendees of :meeting or swedish_mensa_supermodels" do
67
+ venue = Hotel.find_by_name("Wyndham O'Hare")
68
+ current_user.is_traveller_to venue
69
+ if permit? "traveller to :venue and not speaker"
70
+ Partay.all_night_long
71
+ @misdeeds = current_user.is_participant_in_what
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+
79
+ == Installation
80
+
81
+ Installation of the Authorization plugin is quick and easy.
82
+
83
+ === Step 1
84
+
85
+ Open a terminal and change directory to the root of your
86
+ Ruby on Rails application referred to here as 'RAILS_ROOT'. You
87
+ can choose to install the plugin using the standard Ruby on Rails tools (recommended),
88
+ as a Git sub-module, or by grabbing a tarball.
89
+
90
+ === Step 2a (Standard install, recommended)
91
+
92
+ NOTE : This assumes you are using a current (Rails 2.1.x +) version of Rails which
93
+ now has built in support for installing a plugin directly from a git repo. This also assumes
94
+ you have Git installed and working properly. You can always use the manual install shown below
95
+ if this is not true.
96
+
97
+ Run the following command in your RAILS_ROOT:
98
+
99
+ ./script/plugin install git://github.com/DocSavage/rails-authorization-plugin.git
100
+
101
+ This will install the latest version of the plugin from our GitHub master repo
102
+ into your RAILS_ROOT/vendor/plugins/rails-authorization-plugin directory.
103
+
104
+ === Step 2b (Alternative install using Git sub-module, for advanced users of the Git SCM)
105
+
106
+ The source code for this plugin is maintained in a Git SCM
107
+ repository. The Git repository will always have the latest
108
+ version of the code.
109
+
110
+ You can install the plugin using Git sub-modules (which
111
+ are akin to using SVN externals). Installing this way allows
112
+ you to update the plugin code later if needed (but note that
113
+ it will not update any generated code created earlier by this
114
+ plugin such as migrations, which you will need to update manually).
115
+ Also note that if you are deploying your code using Capistrano
116
+ this method may cause issues if you are not careful (e.g. the code
117
+ will be deployed but the sub-modules will not be updated or
118
+ installed at all).
119
+
120
+ From your RAILS_ROOT directory run:
121
+
122
+ git submodule add git://github.com/DocSavage/rails-authorization-plugin.git vendor/plugins/authorization
123
+
124
+ You should be able to update this plugin in the future with
125
+ the simple command (again from RAILS_ROOT):
126
+
127
+ git submodule update
128
+
129
+ === Step 2c (Alternative manual install from tarball)
130
+
131
+ If you like to install the old school manual way, feel free to download a copy of
132
+ latest master branch plugin code from:
133
+
134
+ http://github.com/docsavage/rails-authorization-plugin/tarball/master
135
+
136
+ Once downloaded, rename the top level dir to 'rails-authorization-plugin' and then
137
+ you can stuff that directory in your RAILS_ROOT/vendor/plugins directory.
138
+
139
+
140
+ == Configuration
141
+
142
+ These instructions will show you how to do the initial configuration
143
+ of the plugin.
144
+
145
+ === Choose a Mixin Type
146
+
147
+ ==== Hardwired Roles
148
+
149
+ This is the simplest way to use the plugin and requires no database.
150
+ Roles are assumed to be coded into the Model classes using the
151
+ <tt>has_role?(role, obj = nil)</tt> method. This method is however more
152
+ limited in the functionality available to you.
153
+
154
+ ==== Object Roles (Recommended, DB Required)
155
+
156
+ The Object Roles Table mixin provides full support for authorization
157
+ expressions within a database by add a polymorphic field to the
158
+ Role table. Because roles have polymorphic associations to an
159
+ authorizable object, we can assign a user to a role for any model
160
+ instance. So you could declare user X to be a moderator for workshop Y,
161
+ or you could make user A be the owner of resource B.
162
+
163
+ The identity module adds a number of dynamic methods that use defined
164
+ roles. The user-like model gets methods like `user.is_moderator_of
165
+ group (sets user to "moderator" of group`), user.is_moderator? (returns
166
+ true/false if user has some role "moderator"), and group.has_moderators
167
+ (returns an array of users that have role "moderator" for the group). If
168
+ you prefer not to have these dynamic methods available, you can simply
169
+ comment out the inclusion of the identity module within object_roles_table.rb.
170
+
171
+ === Initial Configuration Instructions
172
+
173
+ Choose one of the installation types identified above and make sure your
174
+ application provides a current_user method or something that returns the
175
+ current user object (resful_authentication provides this out of the box).
176
+
177
+ At the top of your RAILS_ROOT/config/environment.rb file add something
178
+ like the following (customized for your controllers and actions of course):
179
+
180
+ ...
181
+
182
+ # Authorization plugin for role based access control
183
+ # You can override default authorization system constants here.
184
+
185
+ # Can be 'object roles' or 'hardwired'
186
+ AUTHORIZATION_MIXIN = "object roles"
187
+
188
+ # NOTE : If you use modular controllers like '/admin/products' be sure
189
+ # to redirect to something like '/sessions' controller (with a leading slash)
190
+ # as shown in the example below or you will not get redirected properly
191
+ #
192
+ # This can be set to a hash or to an explicit path like '/login'
193
+ #
194
+ LOGIN_REQUIRED_REDIRECTION = { :controller => '/sessions', :action => 'new' }
195
+ PERMISSION_DENIED_REDIRECTION = { :controller => '/home', :action => 'index' }
196
+
197
+ # The method your auth scheme uses to store the location to redirect back to
198
+ STORE_LOCATION_METHOD = :store_location
199
+
200
+ # standard rails config below here
201
+ Rails::Initializer.run do |config|
202
+
203
+ ...
204
+
205
+ * Set the AUTHORIZATION_MIXIN constant to object roles or hardwired. (See init.rb in this plugin for how the role support is mixed in.)
206
+ * Set the LOGIN_REQUIRED_REDIRECTION to match the path or a hash with the :controller and :action for your applications login page.
207
+ * Set the PERMISSION_DENIED_REDIRECTION to match the path or a hash with the :controller and :action for your applications permission denied page.
208
+ * Set the STORE_LOCATION_METHOD to the method your application uses for storing the current URL that the user should return to after authentication (e.g. store_location).
209
+ * See the PLUGIN_DIR\lib\authorization.rb file for the default values of LOGIN_REQUIRED_REDIRECTION, PERMISSION_DENIED_REDIRECTION and STORE_LOCATION_METHOD.
210
+
211
+
212
+ === Create the database tables
213
+
214
+ If you plan to use the object roles method you will need to setup a few
215
+ database tables. We have provided a database migration file
216
+ (Rails 2.0+ compatible) that will make this process easy for you.
217
+ If you plan to use the hardwired mixin, no extra database tables
218
+ are required. and you can skip to the next step.
219
+
220
+ Run the following command from your RAILS_ROOT (Note : The generator
221
+ takes a model name as its argument, which at this time must be 'Role'.):
222
+
223
+ ./script/generate role_model Role
224
+
225
+ This will create:
226
+
227
+ Model: RAILS_ROOT/app/models/role.rb
228
+ Test: RAILS_ROOT/test/unit/role_test.rb
229
+ Fixtures: RAILS_ROOT/test/fixtures/roles.yml
230
+ Migration: RAILS_ROOT/db/migrate/###_add_role.rb
231
+
232
+ And now you will need to run a database migration from your RAILS_ROOT:
233
+
234
+ rake db:migrate
235
+
236
+ === Jumpstarting with a mixin
237
+
238
+ Now we need to add the methods needed by each of your models that will
239
+ participate in role based authorization. Typically these models fall into
240
+ two categories, the User model, and all other models that will have
241
+ roles available for use.
242
+
243
+ For a typical installation you would add both mixins to your User model.
244
+
245
+ class User < ActiveRecord::Base
246
+
247
+ # Authorization plugin
248
+ acts_as_authorized_user
249
+ acts_as_authorizable
250
+
251
+ ...
252
+
253
+ Then in each additional model that you want to be able to restrict based
254
+ on role you would add just the acts_as_authorizable mixin like this:
255
+
256
+ class Event < ActiveRecord::Base
257
+
258
+ acts_as_authorizable
259
+
260
+ ...
261
+
262
+ You are done with the configuration!
263
+
264
+
265
+ == The Specifics
266
+
267
+ === permit and permit?
268
+
269
+ permit and permit? take an authorization expression and a hash of options that
270
+ typically includes any objects that need to be queried:
271
+
272
+ permit <authorization expression> [, options hash ]
273
+ permit? <authorization expression> [, options hash ]
274
+
275
+ The difference between permit and permit? is redirection. permit is a
276
+ declarative statement and redirects by default. It can also be used as a class
277
+ or an instance method, gating the access to an entire controller in a
278
+ before_filter fashion.
279
+
280
+ permit? is only an instance method, can be used within expressions, does not
281
+ redirect by default.
282
+
283
+ The authorization expression is a boolean expression made up of permitted
284
+ roles, prepositions, and authorizable models. Examples include "admin" (User
285
+ model assumed), "moderator of :workshop" (looks at options hash and then
286
+ @workshop), "'top salesman' at :company" (multiword roles delimited by single
287
+ quotes), or "scheduled for Exam" (queries class method of Exam).
288
+
289
+ Note that we can use several permitted prepositions ('of', 'for', 'in', 'on',
290
+ 'to', 'at', 'by'). In the discussion below, we assume you use the "of"
291
+ preposition. You can modify the permitted prepositions by changing the constant
292
+ in Authorization::Base::Parser.
293
+
294
+ * If a specified role has no "of <model>" designation, we assume it is a user
295
+ role (i.e., the model is the user-like object).
296
+
297
+ * If an "of model" designation is given but no "model" key/value is supplied in
298
+ the hash, we check if an instance variable @model if it's available.
299
+
300
+ * If the model is capitalized, we assume it's a class and query
301
+ <tt>Model#self.accepts_role?</tt> (the class method) for the
302
+ permission. (Currently only available in ObjectRolesTable mixin.)
303
+
304
+ For each role, a query is sent to the appropriate model object.
305
+
306
+ The grammar for the authorization expression is:
307
+
308
+ <expr> ::= (<expr>) | not <expr> | <term> or <expr> | <term> and <expr> | <term>
309
+ <term> ::= <role> | <role> <preposition> <model>
310
+ <preposition> ::= of | for | in | on | to | at | by
311
+ <model> ::= /:*\w+/
312
+ <role> ::= /\w+/ | /'.*'/
313
+
314
+ Parentheses should be used to clarify permissions. Note that you may prefix the
315
+ model with an optional ":" -- the first versions of Authorization plugin made
316
+ this mandatory but it's now optional since the mandatory preposition makes
317
+ models unambiguous.
318
+
319
+ ==== Options
320
+
321
+ :allow_guests => false.
322
+
323
+ We can allow permission processing without a
324
+ current user object. The default is false.
325
+
326
+ :user => YourUserObject.
327
+
328
+ The name of your user object.
329
+
330
+ :get_user_method => method_name
331
+
332
+ The method name provided should return a user
333
+ object. Default is #current_user, which is the how
334
+ acts_as_authenticated works.
335
+
336
+ :only => [ :method1, :method2 ]
337
+
338
+ Array of methods to apply permit (not valid when used in instance methods)
339
+
340
+ :except => [ :method1, :method2 ]
341
+
342
+ Array of methods that won't have permission checking (not valid when used in instance methods)
343
+
344
+ :redirect => boolean
345
+
346
+ Default is true. If false, permit will not redirect to denied page.
347
+
348
+ :login_required_redirection => path or hash
349
+
350
+ default is "{ :controller => 'session', :action => 'new' }"
351
+
352
+ Path or Hash where user will be redirected if not logged in ()
353
+
354
+ :login_required_message => 'my message'
355
+
356
+ A string to present to your users when login is required. Default is 'Login is required to access the requested page.'
357
+
358
+ :permission_denied_redirection => path or hash
359
+
360
+ Path or Hash where user will be redirected if logged in but not authorized (default is '')
361
+
362
+ :permission_denied_message => 'my message'
363
+
364
+ Message that will be presented to the user when permission is denied. Default is 'Permission
365
+ denied. You cannot access the requested page.'
366
+
367
+ === Setting and getting the roles
368
+
369
+ Roles are set by #has_role and #accepts_role methods that are mixed into the
370
+ User-like object and the authorizable models. User objects can set roles and
371
+ optionally an object scope for that role:
372
+
373
+ user.has_role 'site_admin'
374
+ user.has_role 'moderator', group
375
+ user.has_no_role 'site_admin'
376
+ user.has_no_role 'moderator', group
377
+ user.has_role 'member', Group
378
+
379
+ Note that the last method sets role "member" on a class "Group". Roles can be
380
+ set with three scopes: entire application (no class or object specified), a
381
+ model class, or an instance of a model (i.e., a model object).
382
+
383
+ Models set roles for specific users:
384
+
385
+ a_model.accepts_role 'moderator', user
386
+ a_model.accepts_no_role 'moderator', user
387
+ Model.accepts_role 'class moderator', user
388
+
389
+ The method language has been chosen to aid memory of the argument order. A user
390
+ has a role "foo", so the role string immediately follows has_role. Similarly, a
391
+ model accepts a role "foo", so the role string immediately follows
392
+ accepts_role. Then we append the scope.
393
+
394
+ Sometimes the user-like object might be an authorizable object as well, for example, when you
395
+ allow 'friend' roles for users. In this case, the user-like object can be declared to be
396
+ <tt>acts_as_authorizable</tt> as well as <tt>acts_as_authorized_user</tt>.
397
+
398
+ Role queries follow the same pattern as the setting of roles:
399
+
400
+ user.has_role? 'moderator'
401
+ user.has_role? 'moderator', group
402
+ user.has_role? 'member', Group
403
+
404
+ a_model.accepts_role? 'moderator', user
405
+ Model.accepts_role? 'moderator', user
406
+
407
+ When a user is queried without specifying either a model class or object, it
408
+ returns true if the user has *any* matching role. For example,
409
+ <tt>user.has_role? 'moderator'</tt> returns true if the user is 'moderator' of
410
+ a class, a model object, or just a generic 'moderator'. Note that if you say
411
+ <tt>user.has_role 'moderator'</tt>, the user does not become 'moderator' for
412
+ all classes and model objects; the user simply has a generic role 'moderator'.
413
+
414
+ ==== Dynamic methods through the Identity mixin
415
+
416
+ The Object Roles Table version includes some dynamic methods that use the roles
417
+ table. For example, if you have roles like "eligible", "moderator", and
418
+ "owner", you'll be able to use the following:
419
+
420
+ user.is_eligible_for_what --> returns array of authorizable objects for which user has role "eligible"
421
+ user.is_moderator_of? group --> returns true/false
422
+ user.is_moderator_of group --> sets user to have role "moderator" for object group.
423
+ user.is_administrator --> sets user to have role "administrator" not really tied to any object.
424
+
425
+ Models get has_* methods:
426
+
427
+ group.has_moderators --> returns array of users with role "moderator" on that group
428
+ group.has_moderators? --> returns true/false
429
+
430
+ Allowed prepositions are optional in the above dynamic methods. They are simply
431
+ syntactic sugar. For example, the following are equivalent:
432
+
433
+ user.is_member_of group
434
+ user.is_member_for group
435
+ user.is_member group
436
+
437
+ Allowed prepositions are required in the authorization expressions because they
438
+ are used to distinguish "role" and "role of :model" and "role of Model".
439
+
440
+ If you prefer not to pollute your namespace with these dynamic methods, do not
441
+ include the Identity module in <tt>object_roles_table.rb</tt>.
442
+
443
+ === Pattern of use
444
+
445
+ We expect the application to provide the following methods:
446
+
447
+ ==== #current_user
448
+
449
+ Returns some user object, like an instance of my favorite class,
450
+ <tt>UserFromMars</tt>. A <tt>user</tt> object, from the Authorization
451
+ viewpoint, is simply an object that provides a <tt>has_role?</tt> method.
452
+
453
+ Note that duck typing means we don't care what else the <tt>UserFromMars</tt>
454
+ might be doing. We only care that we can get an id from whatever it is, and we
455
+ can check if a given role string is associated with it. By using
456
+ <tt>acts_as_authorized_user</tt>, we inject what we need into the user object.
457
+
458
+ If you use an authorization expression "admin of :foo", we check permission by
459
+ asking <tt>foo</tt> if it <tt>accepts_role?('admin', user)</tt>. So for each
460
+ model that is used in an expression, we assume that it provides the
461
+ <tt>accepts_role?(role, user)</tt> method.
462
+
463
+ Note that <tt>user</tt> can be <tt>nil</tt> if <tt>:allow_guests => true</tt>.
464
+
465
+ ==== #store_location (optional)
466
+
467
+ This method will be called if authorization fails and the user is about to be
468
+ redirected to the login action. This allows the application to return to the
469
+ desired page after login. If the application doesn't provide this method, the
470
+ method will not be called.
471
+
472
+ The name of the method for storing a location can be modified by changing the
473
+ constant STORE_LOCATION_METHOD in environment.rb. Also, the default login and
474
+ permission denied pages are defined by the constants LOGIN_REQUIRED_REDIRECTION
475
+ and PERMISSION_DENIED_REDIRECTION in authorization.rb and can be overriden in
476
+ your environment.rb.
477
+
478
+ === Conventions
479
+
480
+ Roles specified without the "of model" designation:
481
+
482
+ 1. We see if there is a <tt>current_user</tt> method available that will return
483
+ a user object. This method can be overridden with the <tt>:user</tt> hash.
484
+
485
+ 2. Once a user object is determined, we pass the role to
486
+ <tt>user.has_role?</tt> and expect a true return value if the user has the
487
+ given role.
488
+
489
+ Roles specified with "of model" designation:
490
+
491
+ 1. We attempt to query an object in the options hash that has a matching
492
+ key. Example: <tt>permit "knight for justice", :justice =>
493
+ @abstract_idea</tt>
494
+
495
+ 2. If there is no object with a matching key, we see if there's a matching
496
+ instance variable. Example: @meeting defined before we use <tt>permit
497
+ "moderator of meeting"</tt>
498
+
499
+ 3. Once the model object is determined, we pass the role and user (determined
500
+ in the manner above) to <tt>model.accepts_role?</tt>
501
+
502
+
503
+ == Upgrading
504
+
505
+ When upgrading this plugin, please refer to the following file:
506
+
507
+ http://github.com/DocSavage/rails-authorization-plugin/tree/master/UPGRADE.rdoc
508
+
509
+
510
+ == Developers Note : Contributing Patches
511
+
512
+ Please see the file README_developers.txt for the methods we would like you to use to submit new code features, bugfixes and patches.