ae_declarative_authorization 0.12.1 → 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.
data/README.rdoc DELETED
@@ -1,597 +0,0 @@
1
- = Declarative Authorization
2
-
3
- The declarative authorization plugin offers an authorization mechanism inspired
4
- by _RBAC_. The most notable distinction to other authorization plugins is the
5
- declarative approach. That is, authorization rules are not defined
6
- programmatically in between business logic but in an authorization configuration.
7
-
8
- With programmatic authorization rules, the developer needs to specify which roles are
9
- allowed to access a specific controller action or a part of a view, which is
10
- not DRY. With a growing application code base roles' permissions often
11
- change and new roles are introduced. Then, at several places of the source code
12
- the changes have to be implemented, possibly leading to omissions and thus hard
13
- to find errors. In these cases, a declarative approach as offered by decl_auth
14
- increases the development and maintenance efficiency.
15
-
16
-
17
- Plugin features
18
- * Authorization at controller action level
19
- * Authorization helpers for Views
20
- * Authorization at model level
21
- * Authorize CRUD (Create, Read, Update, Delete) activities
22
- * Query rewriting to automatically only fetch authorized records
23
- * DSL for specifying Authorization rules in an authorization configuration
24
- * Support for Rails 4 and 5
25
-
26
-
27
- Requirements
28
- * An authentication mechanism
29
- * User object in Controller#current_user
30
- * (For model security) Setting Authorization.current_user
31
- * User objects need to respond to a method :role_symbols that returns an
32
- array of role symbols
33
- See below for installation instructions.
34
-
35
-
36
- There is a decl_auth screencast by Ryan Bates, nicely introducing the main concepts:
37
- http://railscasts.com/episodes/188-declarative-authorization
38
-
39
-
40
- = Quick Start
41
-
42
- === Installer
43
-
44
- Declarative Authorization comes with an installer to make setup easy.
45
-
46
- First, include declarative_authorization in your gemfile.
47
-
48
- #! Gemfile
49
- gem 'declarative_authorization'
50
-
51
- Next, bundle and install.
52
-
53
- $ bundle
54
- $ rails g authorization:install [UserModel=User] [field:type field:type ...] [--create-user --commit --user-belongs-to-role]
55
-
56
- This installer will create a Role model, an admin and a user role, and set a
57
- has_and_belongs_to_many relationship between the User model and the Role model.
58
- It will also add a +role_symbols+ method to the user model to meet
59
- declarative_authorization's requirements. The default User model is User. You can override this by simply typing the name of a model as above.
60
-
61
- You can create the model with the fields provided by using the +--create-user+ option.
62
-
63
- The +--commit+ option will run +rake db:migrate+ and +rake db:seed+.
64
-
65
- The +--user-belongs-to-role+ option will set up a one-to-many relationship between Users and Roles.
66
- That is, each user has a role_id column and can only have one role. Role inheritance can be used
67
- in authorization rules.
68
-
69
- Finally, the installer also copies default authorization rules, as below.
70
-
71
- === Generate Authorization Rules
72
-
73
- To copy a default set of authorization rules which includes CRUD priveleges, run:
74
-
75
- $ rails g authorization:rules
76
-
77
- This command will copy the following to +config/authorization_rules.rb+. Remember
78
- to implement the requirements of this gem as described in the Installation section
79
- at the end of this README if you do not use the above installer.
80
-
81
- authorization do
82
- role :guest do
83
- # add permissions for guests here, e.g.
84
- # has_permission_on :conferences, :to => :read
85
- end
86
-
87
- # permissions on other roles, such as
88
- # role :admin do
89
- # has_permission_on :conferences, :to => :manage
90
- # end
91
- # role :user do
92
- # has_permission_on :conferences, :to => [:read, :create]
93
- # has_permission_on :conferences, :to => [:update, :delete] do
94
- # if_attribute :user_id => is {user.id}
95
- # end
96
- # end
97
- # See the readme or GitHub for more examples
98
- end
99
-
100
- privileges do
101
- # default privilege hierarchies to facilitate RESTful Rails apps
102
- privilege :manage, :includes => [:create, :read, :update, :delete]
103
- privilege :create, :includes => :new
104
- privilege :read, :includes => [:index, :show]
105
- privilege :update, :includes => :edit
106
- privilege :delete, :includes => :destroy
107
- end
108
-
109
- === Controller Authorization
110
-
111
- For RESTful controllers, add +filter_resource_access+:
112
-
113
- class MyRestfulController < ApplicationController
114
- filter_resource_access
115
- ...
116
- end
117
-
118
- For a non-RESTful controller, you can use +filter_access_to+:
119
-
120
- class MyOtherController < ApplicationController
121
- filter_access_to :all
122
- # or a group: filter_access_to [:action1, :action2]
123
- ...
124
- end
125
-
126
- === View Authorization
127
-
128
- Declarative Authorization will use +current_user+ to check authorization.
129
-
130
- <%= link_to 'Edit Post', edit_post_path(@post) if permitted_to? :update, @post %>
131
-
132
-
133
- = Authorization Data Model
134
-
135
- ----- App domain ----|-------- Authorization conf ---------|------- App domain ------
136
-
137
- includes includes
138
- .--. .---.
139
- | v | v
140
- .------. can_play .------. has_permission .------------. requires .----------.
141
- | User |----------->| Role |----------------->| Permission |<-----------| Activity |
142
- '------' * * '------' * * '------------' 1 * '----------'
143
- |
144
- .-------+------.
145
- 1 / | 1 \ *
146
- .-----------. .---------. .-----------.
147
- | Privilege | | Context | | Attribute |
148
- '-----------' '---------' '-----------'
149
-
150
- In the application domain, each *User* may be assigned to *Roles* that should
151
- define the users' job in the application, such as _Administrator_. On the
152
- right-hand side of this diagram, application developers specify which *Permissions*
153
- are necessary for users to perform activities, such as calling a controller action,
154
- viewing parts of a View or acting on records in the database. Note that
155
- Permissions consist of an *Privilege* that is to be performed, such as _read_,
156
- and a *Context* in that the Operation takes place, such as _companies_.
157
-
158
- In the authorization configuration, Permissions are assigned to Roles and Role
159
- and Permission hierarchies are defined. *Attributes* may be employed to allow
160
- authorization according to dynamic information about the context and the
161
- current user, e.g. "only allow access on employees that belong to the
162
- current user's branch."
163
-
164
-
165
- = Examples
166
-
167
- A fully functional example application can be found at
168
- http://github.com/stffn/decl_auth_demo_app
169
-
170
- == Controller
171
-
172
- If authentication is in place, there are two ways to enable user-specific
173
- access control on controller actions. For resource controllers, which more
174
- or less follow the CRUD pattern, +filter_resource_access+ is the simplest
175
- approach. It sets up instance variables in before filters and calls
176
- filter_access_to with the appropriate parameters to protect the CRUD methods.
177
-
178
- class EmployeesController < ApplicationController
179
- filter_resource_access
180
- ...
181
- end
182
-
183
- See Authorization::Controller::DSL for options on
184
- nested resources and custom member and collection actions.
185
-
186
- By default, declarative_authorization will enable filter_resource_access compatibility with strong_parameters in Rails 4. If you want to disable this behavior, you can use the +:strong_parameters+ option.
187
-
188
- class EmployeesController < ApplicationController
189
- filter_resource_access :strong_parameters => false
190
- ...
191
- end
192
-
193
- Simalarly, you can use +:strong_parameters => true+ if you are using strong_parameters in Rails 3.
194
-
195
- If you prefer less magic or your controller has no resemblance with the resource
196
- controllers, directly calling filter_access_to may be the better option. Examples
197
- are given in the following. E.g. the privilege index users is required for
198
- action index. This works as a first default configuration for RESTful
199
- controllers, with these privileges easily handled in the authorization
200
- configuration, which will be described below.
201
-
202
- class EmployeesController < ApplicationController
203
- filter_access_to :all
204
- def index
205
- ...
206
- end
207
- ...
208
- end
209
-
210
- When custom actions are added to such a controller, it helps to define more
211
- clearly which privileges are the respective requirements. That is when the
212
- filter_access_to call may become more verbose:
213
-
214
- class EmployeesController < ApplicationController
215
- filter_access_to :all
216
- # this one would be included in :all, but :read seems to be
217
- # a more suitable privilege than :auto_complete_for_user_name
218
- filter_access_to :auto_complete_for_employee_name, :require => :read
219
- def auto_complete_for_employee_name
220
- ...
221
- end
222
- ...
223
- end
224
-
225
- For some actions it might be necessary to check certain attributes of the
226
- object the action is to be acting on. Then, the object needs to be loaded
227
- before the action's access control is evaluated. On the other hand, some actions
228
- might prefer the authorization to ignore specific attribute checks as the object is
229
- unknown at checking time, so attribute checks and thus automatic loading of
230
- objects needs to be enabled explicitly.
231
-
232
- class EmployeesController < ApplicationController
233
- filter_access_to :update, :attribute_check => true
234
- def update
235
- # @employee is already loaded from param[:id] because of :attribute_check
236
- end
237
- end
238
-
239
- You can provide the needed object through before_actions. This way, you have
240
- full control over the object that the conditions are checked against. Just make
241
- sure, your before_actions occur before any of the filter_access_to calls.
242
-
243
- class EmployeesController < ApplicationController
244
- before_action :new_employee_from_params, :only => :create
245
- before_action :new_employee, :only => [:index, :new]
246
- filter_access_to :all, :attribute_check => true
247
-
248
- def create
249
- @employee.save!
250
- end
251
-
252
- protected
253
- def new_employee_from_params
254
- @employee = Employee.new(params[:employee])
255
- end
256
- end
257
-
258
- If the access is denied, a +permission_denied+ method is called on the
259
- current_controller, if defined, and the issue is logged.
260
- For further customization of the filters and object loading, have a look at
261
- the complete API documentation of filter_access_to in
262
- Authorization::Controller::DSL.
263
-
264
-
265
- == Views
266
-
267
- In views, a simple permitted_to? helper makes showing blocks according to the
268
- current user's privileges easy:
269
-
270
- <% permitted_to? :create, :employees do %>
271
- <%= link_to 'New', new_employee_path %>
272
- <% end %>
273
-
274
- Only giving a symbol :employees as context prevents any checks of attributes
275
- as there is no object to check against. For example, in case of nested resources
276
- a new object may come in handy:
277
-
278
- <% permitted_to? :create, Branch.new(:company => @company) do
279
- # or @company.branches.new
280
- # or even @company.branches %>
281
- <%= link_to 'New', new_company_branch_path(@company) %>
282
- <% end %>
283
-
284
- Lists are straight-forward:
285
-
286
- <% for employee in @employees %>
287
- <%= link_to 'Edit', edit_employee_path(employee) if permitted_to? :update, employee %>
288
- <% end %>
289
-
290
- See also Authorization::AuthorizationHelper.
291
-
292
-
293
- == Models
294
-
295
- There are two distinct features for model security built into this plugin:
296
- authorizing CRUD operations on objects as well as query rewriting to limit
297
- results according to certain privileges.
298
-
299
- See also Authorization::AuthorizationInModel.
300
-
301
- === Model security for CRUD operations
302
- To activate model security, all it takes is an explicit enabling for each
303
- model that model security should be enforced on, i.e.
304
-
305
- class Employee < ActiveRecord::Base
306
- using_access_control
307
- ...
308
- end
309
-
310
- Thus,
311
- Employee.create(...)
312
- fails, if the current user is not allowed to :create :employees according
313
- to the authorization rules. For the application to find out about what
314
- happened if an operation is denied, the filters throw
315
- Authorization::NotAuthorized exceptions.
316
-
317
- As access control on read are costly, with possibly lots of objects being
318
- loaded at a time in one query, checks on read need to be activated explicitly by
319
- adding the :include_read option.
320
-
321
- === Query rewriting through named scopes
322
- When retrieving large sets of records from databases, any authorization needs
323
- to be integrated into the query in order to prevent inefficient filtering
324
- afterwards and to use LIMIT and OFFSET in SQL statements. To keep authorization
325
- rules out of the source code, this plugin offers query rewriting mechanisms
326
- through named scopes. Thus,
327
-
328
- Employee.with_permissions_to(:read)
329
-
330
- returns all employee records that the current user is authorized to read. In
331
- addition, just like normal named scopes, query rewriting may be chained with
332
- the usual find method:
333
-
334
- Employee.with_permissions_to(:read).find(:all, :conditions => ...)
335
-
336
- If the current user is completely missing the permissions, an
337
- Authorization::NotAuthorized exception is raised. Through
338
- Model.obligation_conditions, application developers may retrieve
339
- the conditions for manual rewrites.
340
-
341
-
342
- == Authorization Rules
343
-
344
- Authorization rules are defined in config/authorization_rules.rb
345
- (Or redefine rules files path via +Authorization::AUTH_DSL_FILES+). E.g.
346
-
347
- authorization do
348
- role :admin do
349
- has_permission_on :employees, :to => [:create, :read, :update, :delete]
350
- end
351
- end
352
-
353
- There is a default role :+guest+ that is used if a request is not associated
354
- with any user or with a user without any roles. So, if your application has
355
- public pages, :+guest+ can be used to allow access for users that are not
356
- logged in. All other roles are application defined and need to be associated
357
- with users by the application.
358
-
359
- If you need to change the default role, you can do so by adding an initializer
360
- that contains the following statement:
361
-
362
- Authorization.default_role = :anonymous
363
-
364
- Privileges, such as :create, may be put into hierarchies to simplify
365
- maintenance. So the example above has the same meaning as
366
-
367
- authorization do
368
- role :admin do
369
- has_permission_on :employees, :to => :manage
370
- end
371
- end
372
-
373
- privileges do
374
- privilege :manage do
375
- includes :create, :read, :update, :delete
376
- end
377
- end
378
-
379
- Privilege hierarchies may be context-specific, e.g. applicable to :employees.
380
-
381
- privileges do
382
- privilege :manage, :employees, :includes => :increase_salary
383
- end
384
-
385
- For more complex use cases, authorizations need to be based on attributes. Note
386
- that you then also need to set :attribute_check => true in controllers for filter_access_to.
387
- E.g. if a branch admin should manage only employees of his branch (see
388
- Authorization::Reader in the API docs for a full list of available operators):
389
-
390
- authorization do
391
- role :branch_admin do
392
- has_permission_on :employees do
393
- to :manage
394
- # user refers to the current_user when evaluating
395
- if_attribute :branch => is {user.branch}
396
- end
397
- end
398
- end
399
-
400
- To reduce redundancy in has_permission_on blocks, a rule may depend on
401
- permissions on associated objects:
402
-
403
- authorization do
404
- role :branch_admin do
405
- has_permission_on :branches, :to => :manage do
406
- if_attribute :managers => contains {user}
407
- end
408
-
409
- has_permission_on :employees, :to => :manage do
410
- if_permitted_to :manage, :branch
411
- # instead of
412
- #if_attribute :branch => {:managers => contains {user}}
413
- end
414
- end
415
- end
416
-
417
- Lastly, not only privileges may be organized in a hierarchy but roles as well.
418
- Here, project manager inherit the permissions of employees.
419
-
420
- role :project_manager do
421
- includes :employee
422
- end
423
-
424
- See also Authorization::Reader.
425
-
426
- == Testing
427
-
428
- declarative_authorization provides a few helpers to ease the testing with
429
- authorization in mind.
430
-
431
- In your test_helper.rb, to enable the helpers add
432
-
433
- require 'declarative_authorization/maintenance'
434
-
435
- class Test::Unit::TestCase
436
- include Authorization::TestHelper
437
- ...
438
- end
439
-
440
- For using the test helpers with RSpec, just add the following lines to your
441
- spec_helper.rb (somewhere after require 'spec/rails'):
442
-
443
- require 'declarative_authorization/maintenance'
444
- include Authorization::TestHelper
445
-
446
- Now, in unit tests, you may deactivate authorization if needed e.g. for test
447
- setup and assume certain identities for tests:
448
-
449
- class EmployeeTest < ActiveSupport::TestCase
450
- def test_should_read
451
- without_access_control do
452
- Employee.create(...)
453
- end
454
- assert_nothing_raised do
455
- with_user(admin) do
456
- Employee.find(:first)
457
- end
458
- end
459
- end
460
- end
461
-
462
- Or, with RSpec, it would work like this:
463
-
464
- describe Employee do
465
- it "should read" do
466
- without_access_control do
467
- Employee.create(...)
468
- end
469
- with_user(admin) do
470
- Employee.find(:first)
471
- end
472
- end
473
- end
474
-
475
- In functional tests, get, posts, etc. may be tested in the name of certain users:
476
-
477
- get_with admin, :index
478
- post_with admin, :update, :employee => {...}
479
-
480
- See Authorization::TestHelper for more information.
481
-
482
-
483
- = Installation of declarative_authorization
484
-
485
- One of three options to install the plugin:
486
- * Install by Gem: Add to your environment.rb in the initializer block:
487
- config.gem "declarative_authorization"
488
- Note: you need gemcutter support in place, i.e. call
489
- gem install gemcutter
490
- gem tumble
491
- And call from your application's root directory
492
- rake gems:install
493
- * Alternatively, in Rails 2, to install from github, execute in your application's root directory
494
- cd vendor/plugins && git clone git://github.com/stffn/declarative_authorization.git
495
-
496
- Then,
497
- * provide the requirements as noted below,
498
- * create a basic config/authorization_rules.rb--you might want to take the
499
- provided example authorization_rules.dist.rb in the plugin root as a starting
500
- point,
501
- * add +filter_access_to+, +permitted_to+? and model security as needed.
502
-
503
- == Providing the Plugin's Requirements
504
- The requirements are
505
- * Rails >= 4.2.5.2 and Ruby >= 2.3.3
506
- * An authentication mechanism
507
- * A user object returned by Controller#current_user
508
- * An array of role symbols returned by User#role_symbols
509
- * (For model security) Setting Authorization.current_user to the request's user
510
-
511
- Of the various ways to provide these requirements, here is one way employing
512
- restful_authentication.
513
-
514
- * Install restful_authentication
515
- cd vendor/plugins && git clone git://github.com/technoweenie/restful-authentication.git restful_authentication
516
- cd ../.. && ruby script/generate authenticated user sessions
517
- * Move "include AuthenticatedSystem" to ApplicationController
518
- * Add +filter_access_to+ calls as described above.
519
- * If you'd like to use model security, add a before_action that sets the user
520
- globally to your ApplicationController. This is thread-safe.
521
- before_action :set_current_user
522
- protected
523
- def set_current_user
524
- Authorization.current_user = current_user
525
- end
526
-
527
- * Add roles field to the User model through a :+has_many+ association
528
- (this is just one possible approach; you could just as easily use
529
- :+has_many+ :+through+ or a serialized roles array):
530
- * create a migration for table roles
531
- class CreateRoles < ActiveRecord::Migration
532
- def self.up
533
- create_table "roles" do |t|
534
- t.column :title, :string
535
- t.references :user
536
- end
537
- end
538
-
539
- def self.down
540
- drop_table "roles"
541
- end
542
- end
543
-
544
- * create a model Role,
545
- class Role < ActiveRecord::Base
546
- belongs_to :user
547
- end
548
-
549
- * add +has_many+ :+roles+ to the User model and a roles method that returns the roles
550
- as an Array of Symbols, e.g.
551
- class User < ActiveRecord::Base
552
- has_many :roles
553
- def role_symbols
554
- (roles || []).map {|r| r.title.to_sym}
555
- end
556
- end
557
-
558
- * add roles to your User objects using e.g.
559
- user.roles.create(:title => "admin")
560
-
561
- Note: If you choose to generate an Account model for restful_authentication
562
- instead of a User model as described above, you have to customize the
563
- examples and create a ApplicationController#current_user method.
564
-
565
-
566
- == Debugging Authorization
567
-
568
- Currently, the main means of debugging authorization decisions is logging and
569
- exceptions. Denied access to actions is logged to +warn+ or +info+, including
570
- some hints about what went wrong.
571
-
572
- All bang methods throw exceptions which may be used to retrieve more
573
- information about a denied access than a Boolean value.
574
-
575
-
576
- = Help and Contact
577
-
578
- We have an issue tracker[http://github.com/appfolio/ae_declarative_authorization/issues]
579
- for bugs and feature requests.
580
- You are very welcome to contribute. Just fork the git repository and send a pull request.
581
-
582
-
583
- = Contributors
584
-
585
- Thanks to John Joseph Bachir, Dennis Blöte, Eike Carls, Damian Caruso, Kai Chen, Erik Dahlstrand,
586
- Jeroen van Dijk, Alexander Dobriakov, Sebastian Dyck, Ari Epstein, Jeremy Friesen,
587
- Tim Harper, John Hawthorn, hollownest, Daniel Kristensen, Jeremy Kleindl, Joel Kociolek,
588
- Benjamin ter Kuile, Brad Langhorst, Brian Langenfeld,
589
- Georg Ledermann, Geoff Longman, Olly Lylo, Mark Mansour, Thomas Maurer, Kevin Moore,
590
- Tyler Pickett, Edward Rudd, Sharagoz,
591
- TJ Singleton, Mike Vincent, Joel Westerberg
592
-
593
-
594
- = License
595
-
596
- Copyright (c) 2008 Steffen Bartsch, TZI, Universität Bremen, Germany
597
- released under the MIT license
data/Rakefile DELETED
@@ -1,35 +0,0 @@
1
- require 'rubygems'
2
- require 'bundler'
3
-
4
- begin
5
- Bundler.setup(:default, :development)
6
- rescue Bundler::BundlerError => e
7
- $stderr.puts e.message
8
- $stderr.puts "Run `bundle install` to install missing gems"
9
- exit e.status_code
10
- end
11
-
12
- require 'rake'
13
- require 'rake/testtask'
14
- require 'rdoc/task'
15
-
16
- require 'bundler/gem_tasks'
17
-
18
- task default: :test
19
-
20
- Rake::TestTask.new(:test) do |t|
21
- t.libs << 'lib' << 'test'
22
- t.pattern = 'test/**/*_test.rb'
23
- t.verbose = true
24
- t.warning = false
25
- end
26
-
27
- Rake::RDocTask.new(:rdoc) do |rdoc|
28
- rdoc.rdoc_dir = 'rdoc'
29
- rdoc.title = 'Authorization'
30
- rdoc.options << '--line-numbers' << '--inline-source'
31
- rdoc.options << '--charset' << 'utf-8'
32
- rdoc.rdoc_files.include('README.rdoc')
33
- rdoc.rdoc_files.include('CHANGELOG')
34
- rdoc.rdoc_files.include('lib/**/*.rb')
35
- end
@@ -1,20 +0,0 @@
1
- authorization do
2
- role :guest do
3
- # add permissions for guests here, e.g.
4
- #has_permission_on :conferences, :to => :read
5
- end
6
-
7
- # permissions on other roles, such as
8
- #role :admin do
9
- # has_permission_on :conferences, :to => :manage
10
- #end
11
- end
12
-
13
- privileges do
14
- # default privilege hierarchies to facilitate RESTful Rails apps
15
- privilege :manage, :includes => [:create, :read, :update, :delete]
16
- privilege :read, :includes => [:index, :show]
17
- privilege :create, :includes => :new
18
- privilege :update, :includes => :edit
19
- privilege :delete, :includes => :destroy
20
- end
data/init.rb DELETED
@@ -1,5 +0,0 @@
1
- begin
2
- require File.join(File.dirname(__FILE__), 'lib', 'declarative_authorization') # From here
3
- rescue LoadError
4
- require 'declarative_authorization' # From gem
5
- end