permit 0.9.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.
Files changed (42) hide show
  1. data/.gitignore +5 -0
  2. data/.yardopts +3 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.mkd +238 -0
  5. data/Rakefile +69 -0
  6. data/VERSION.yml +5 -0
  7. data/generators/permit/USAGE +40 -0
  8. data/generators/permit/permit_generator.rb +25 -0
  9. data/generators/permit/templates/authorization.rb +2 -0
  10. data/generators/permit/templates/initializer.rb +37 -0
  11. data/generators/permit/templates/migration.rb +28 -0
  12. data/generators/permit/templates/role.rb +2 -0
  13. data/init.rb +1 -0
  14. data/install.rb +1 -0
  15. data/lib/models/association.rb +89 -0
  16. data/lib/models/authorizable.rb +31 -0
  17. data/lib/models/authorization.rb +54 -0
  18. data/lib/models/person.rb +148 -0
  19. data/lib/models/role.rb +59 -0
  20. data/lib/permit/controller.rb +132 -0
  21. data/lib/permit/permit_rule.rb +198 -0
  22. data/lib/permit/permit_rules.rb +141 -0
  23. data/lib/permit/support.rb +67 -0
  24. data/lib/permit.rb +134 -0
  25. data/permit.gemspec +91 -0
  26. data/rails/init.rb +7 -0
  27. data/spec/models/alternate_models_spec.rb +54 -0
  28. data/spec/models/authorizable_spec.rb +78 -0
  29. data/spec/models/authorization_spec.rb +77 -0
  30. data/spec/models/person_spec.rb +278 -0
  31. data/spec/models/role_spec.rb +121 -0
  32. data/spec/permit/controller_spec.rb +308 -0
  33. data/spec/permit/permit_rule_spec.rb +452 -0
  34. data/spec/permit/permit_rules_spec.rb +273 -0
  35. data/spec/permit_spec.rb +58 -0
  36. data/spec/spec_helper.rb +73 -0
  37. data/spec/support/helpers.rb +13 -0
  38. data/spec/support/models.rb +38 -0
  39. data/spec/support/permits_controller.rb +7 -0
  40. data/tasks/permit_tasks.rake +4 -0
  41. data/uninstall.rb +1 -0
  42. metadata +107 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .yardoc
2
+ doc
3
+ README.html
4
+ coverage
5
+ pkg
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --protected
2
+ -
3
+ generators/permit/USAGE
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [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.mkd ADDED
@@ -0,0 +1,238 @@
1
+ # Permit
2
+ A flexible controller authorization tool for Ruby on Rails.
3
+
4
+ **Source:** [http://github.com/dnd/permit](http://github.com/dnd/permit)
5
+ **Issues:** [http://github.com/dnd/permit/issues](http://github.com/dnd/permit/issues)
6
+ **Docs:** [http://yardoc.org/docs/dnd-permit](http://yardoc.org/docs/dnd-permit)
7
+ **Author:** Steve Valaitis
8
+ **Copyright:** 2010
9
+ **License:** MIT License
10
+
11
+ * [Description](#description)
12
+ * [Installation & Setup](#setup)
13
+ * [Usage](#usage)
14
+ * [Specs & Coverage](#specs)
15
+ * [Problems](#problems)
16
+
17
+ <span id="description"></span>
18
+ ## How does it work?
19
+ Permit works by allowing you to define a series of allow or deny rules to
20
+ authorize a person. The rules that apply for the action of the current request
21
+ are then evaluated against the current person. Rule evaluation stops as soon as
22
+ a match is found. If a deny rule matches, `#access_denied` will be called, and
23
+ the person will be prevented from accessing the action. If an allow rule
24
+ matches, the person will be directed to the action as normal. If no rules
25
+ match, the person will be denied access. This can be overridden either at the
26
+ global or controller level by setting the `default_access` option to `:allow`.
27
+ Keep in mind that _deny rules are always run first_.
28
+
29
+ There are three different types of authorizations that you can use with Permit.
30
+ They are as follows:
31
+
32
+ ### Static Authorizations
33
+ These are the most basic forms of authorization and allow you to use one of
34
+ these roles by itself to authorize someone.
35
+
36
+ * `:everyone` - Exactly what it says, an authorization that applies to everyone.
37
+ * `:guest` - Indicates a guest to the application, and only matches if
38
+ `current_person#guest?` returns `true`.
39
+ * `:person` - Indicates an authorized person, and only matches if
40
+ `current_person#guest?` returns `false`.
41
+
42
+ Example:
43
+
44
+ allow :guest, :to => :index
45
+
46
+ ### Dynamic Authorization
47
+ When using the `:person` role, you can additionally specify the `:who`/`:that` and
48
+ `:of`/`:on` options. This will cause the current person object to be sent as an
49
+ argument to the method indicated by `:who`/`:that` on the target resource
50
+ indicated by `:of`/`:on`. If the method call returns `true` then the rule will be
51
+ a match.
52
+
53
+ If the symbol given to `:who`/`:that` is prefixed with `is_` some special sugar will be
54
+ applied, causing Permit to try and use various methods on the resource. You can
55
+ see these methods in the documentation for
56
+ [PermitRule#initialize](http://yardoc.org/docs/dnd-permit/Permit/PermitRule:initialize)
57
+
58
+ A dynamic authorization might look like this:
59
+
60
+ allow :person, :who => :is_owner, :of => :project, :to => :write
61
+
62
+ ### Named Authorizations
63
+ These are authorizations using custom roles that you define in the database and
64
+ are mapped to a person in an authorizations table. A person may be granted a
65
+ role for a given resource, more than one resource, or no resource at
66
+ all\(depending on what the role definition allows\).
67
+
68
+ Some named authorizations might look like:
69
+
70
+ allow :admin, :of => :team, :to => :show
71
+ allow [:project_owner, :project_manager], :of => :project, :to => :all
72
+
73
+ <span id="setup"></span>
74
+ ## How do I get it?
75
+
76
+ ### Installation
77
+ You can install Permit as a gem(make sure to add "`config.gem 'permit'`" to your
78
+ `config/environment.rb` file):
79
+
80
+ sudo gem install permit
81
+
82
+ or as a plugin:
83
+
84
+ script/plugin install git://github.com/dnd/permit.git
85
+
86
+ as a gem from source:
87
+
88
+ git clone git://github.com/dnd/permit.git
89
+ sudo rake install
90
+
91
+ ### Setup
92
+
93
+ #### Pre-requisites
94
+ You must have a `Person` model, _or_ some other model that represents an
95
+ authorized user of the system that responds to `#guest?`. Permit will not create
96
+ this model for you. You can get as fancy as you want with the `guest?` method,
97
+ but a simple example would be:
98
+
99
+ def guest?
100
+ new_record?
101
+ end
102
+
103
+ #### Generation
104
+ If you are not going to use named authorizations, run:
105
+
106
+ script/generate permit [Person] --init-only
107
+
108
+ If you are going to use named authorizations you can run:
109
+
110
+ script/generate permit [Person [Authorization [Role]]]
111
+
112
+ You are not required to pass in any arguments to the generator. The arguments
113
+ above are optional, and reflect the default names that Permit uses. These only
114
+ need to be specified if you want to use different class name(s). So if you
115
+ wanted to use an existing `Employee` class for authorization instead of the
116
+ default `Person`, run:
117
+
118
+ script/generate permit Employee
119
+
120
+ For full details on the generator take a look at the `--help`
121
+
122
+ Run the migration for the roles and authorizations:
123
+
124
+ rake db:migrate
125
+
126
+ #### Controller
127
+ Include Permit in your `ApplicationController`:
128
+
129
+ include Permit::ControllerExtensions
130
+
131
+ Create a method that returns the current authorization subject. This will by
132
+ default be inferred from the class name given to Permit for initialization, and
133
+ takes the form of `current_*`. So if the class was `Person`, Permit would look
134
+ for `current_person`. For `User` it would be `current_user`, etc... If the
135
+ method you want to use doesn't follow this convention it can be overridden in
136
+ the initializer.
137
+
138
+ Permit::Config.controller_subject_method = :logged_user
139
+
140
+ <span id="usage"></span>
141
+ ## How do I use it?
142
+
143
+ ### Controller
144
+ After you have "included" Permit into your controller, it is still not active.
145
+ For that you must define a block of rules by calling
146
+ [`permit`](http://yardoc.org/docs/dnd-permit/Permit/ControllerExtensions/PermitClassMethods:permit)
147
+ in your controller. If you want to by default protect all of your controllers,
148
+ you can just make an empty permit call in your base controller class\(such as
149
+ `ApplicationController`\).
150
+
151
+ Something to keep in mind is that when `permit` is called, a before filter is
152
+ set to check the authorizations. Any setup that you need to do for setting
153
+ the current subject, or the resource to be used in `:of`/`:on` criteria needs to
154
+ be done through before filters set prior to this call.
155
+
156
+ _**The rules defined in `permit` blocks are not additive.** When a new `permit` call
157
+ is made, it wipes out any previously set rules. It also resets the before filter
158
+ position for checking the authorizations thus allowing you to add any other
159
+ before filters you may need in your implementing controller._
160
+
161
+ You can create "allow" and "deny" rules by passing at minimum, a role, and one
162
+ or more actions that the rule applies to. The actions will be expanded using the
163
+ aliases defined in
164
+ [Permit::Config.action_aliases](http://yardoc.org/docs/dnd-permit/Permit/Config.action_aliases),
165
+ and are expanded in a non-recursive fashion. You can optionally pass `:all` for
166
+ the action, which will cause the rule to be tested for all actions. "allow"
167
+ rules accept the `:to` key for actions, and "deny" rules accept the `:from` key.
168
+
169
+ For the full documentation and description of options you can use for creating rules
170
+ see the documentation for
171
+ [PermitRule#initialize](http://yardoc.org/docs/dnd-permit/Permit/PermitRule:initialize)
172
+
173
+ permit do
174
+ deny :person, :from => [:write, :destroy], :if => Proc.new {|person, context| person.status == :on_leave}
175
+ allow :person, :who => :has_commented?, :on => :article, :to => :show
176
+ allow :person, :who => :is_author, :of => :article, :to => [:read, :write]
177
+ allow :admin, :to => :all
178
+ end
179
+
180
+ > Deny a person from new, create, edit, update, delete, and destroy if they are on leave.
181
+
182
+ > Allow a person who has commented on the article to show. `@article.has_commented?(current_person)`
183
+
184
+ > Allow person who is the author of the article to index, show, new, create,
185
+ > edit, and update. `@article.author == current_person`
186
+
187
+ > Allow a person that has the admin role for no resource to access any action.
188
+ > `current_person.authorized?(:admin, nil)
189
+
190
+ #### Helpers
191
+ The following helpers are included for use in your views, or for one off
192
+ operations in your controllers.
193
+
194
+ * `allowed?` - Returns `true` if the person matches the rule criteria
195
+ * `denied?` - Returns `true` if the person does not match the rule criteria
196
+ * `authorized?` - Calls `current_person.authorized?`
197
+
198
+ See
199
+ [Permit::ControllerExtensions::InstanceMethods](http://yardoc.org/docs/dnd-permit/Permit/ControllerExtensions/PermitInstanceMethods)
200
+ for the full documentation on these methods.
201
+
202
+
203
+ ### Models
204
+ _This aspect of Permit only applies if you are using named authorizations._
205
+
206
+ Named authorizations are setup based on the call to
207
+ `Permit::Config.set_core_models` in your initializer. This call sets up your
208
+ authorization, person, and role models by calling `permit_authorization`,
209
+ `permit_person`, and `permit_role` on them respectively.
210
+
211
+ The extensions for authorization, and role setup some basic validations to
212
+ ensure the integrity of the models.
213
+
214
+ #### Resources
215
+ To setup a model to be used as a resource for authorization, call
216
+ `permit_authorizable` inside of it.
217
+
218
+ #### Associations
219
+ The person, role, and resource models are setup with a `has_many :authorizations`
220
+ association. This association is extended with a few methods that are documented
221
+ in [AssociationExtensions](http://yardoc.org/docs/dnd-permit/Permit/Models/AssociationExtensions)
222
+
223
+ #### Person
224
+ The person model is extended with a few methods to simplify authorizing, and
225
+ revoking roles, as well as checking if the person is authorized on a given set
226
+ of roles for a resource. These methods are documented in
227
+ [PersonInstanceMethods](http://yardoc.org/docs/dnd-permit/Permit/Models/PersonExtensions/PersonInstanceMethods).
228
+
229
+ <span id="specs"></span>
230
+ ## Specs & Coverage
231
+ Permit currently has fairly high test coverage\(>95%\). To run the specs for
232
+ Permit, the plugin will most likely need to be inside of an existing Rails
233
+ application.
234
+
235
+ <span id="problems"></span>
236
+ ## Problems?
237
+ Please use the [GitHub issue tracker](http://github.com/dnd/permit/issues) for
238
+ any bugs, problems, or unexpected behavior you run across while using Permit.
data/Rakefile ADDED
@@ -0,0 +1,69 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run specs tests.'
6
+ task :default => :spec
7
+
8
+ begin
9
+ require 'spec'
10
+ require 'spec/rake/spectask'
11
+
12
+ desc 'Run all specs'
13
+ Spec::Rake::SpecTask.new 'spec' do |t|
14
+ t.spec_files = FileList['spec']
15
+ t.spec_opts = ["--colour"]
16
+ end
17
+
18
+ begin
19
+ require 'rcov'
20
+
21
+ desc 'Run all specs with rcov'
22
+ Spec::Rake::SpecTask.new 'rcov' do |t|
23
+ t.spec_files = FileList['spec']
24
+ t.rcov = true
25
+ t.rcov_opts = ['--exclude', 'spec,app/,config/,rubygems/']
26
+ end
27
+ rescue LoadError
28
+ warn "RCov is not available. To run specs with coverage `gem install rcov`."
29
+ end
30
+ rescue LoadError
31
+ warn "RSpec is not available. To run specs `gem install rspec`."
32
+ end
33
+
34
+ desc 'Generate documentation for the permit plugin.'
35
+ Rake::RDocTask.new(:rdoc) do |rdoc|
36
+ rdoc.rdoc_dir = 'rdoc'
37
+ rdoc.title = 'Permit'
38
+ rdoc.options << '--line-numbers' << '--inline-source'
39
+ rdoc.rdoc_files.include('README')
40
+ rdoc.rdoc_files.include('lib/**/*.rb')
41
+ end
42
+
43
+ begin
44
+ require 'yard'
45
+
46
+ desc 'Generate YARDocs'
47
+ YARD::Rake::YardocTask.new do |t|
48
+ t.files = ['lib/**/*.rb']
49
+ end
50
+ rescue LoadError
51
+ warn "YARD not available. To compile YARDocs `gem install yard`."
52
+ end
53
+
54
+ begin
55
+ require 'jeweler'
56
+ Jeweler::Tasks.new do |gem|
57
+ gem.name = "permit"
58
+ gem.summary = "A flexible authorization plugin for Ruby on Rails."
59
+ gem.email = "steve@digitalnothing.com"
60
+ gem.homepage = "http://github.com/dnd/permit"
61
+ gem.author = "Steve Valaitis"
62
+ gem.files.exclude 'autotest'
63
+ gem.extra_rdoc_files = ['README.mkd']
64
+ end
65
+ Jeweler::GemcutterTasks.new
66
+ rescue LoadError
67
+ warn "Jeweler not available. To install `gem install jeweler`."
68
+ end
69
+
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 9
4
+ :patch: 0
5
+ :build:
@@ -0,0 +1,40 @@
1
+ Description:
2
+ The permit generator creates the authorization and role models, as well as the
3
+ migration and an initializer.
4
+
5
+ You can optionally pass in different names for the authorization, role, and
6
+ person class that you want to use. Changing the value for Person will not
7
+ alter any existing models, but will be used to generate the proper foreign-key
8
+ in the migration.
9
+
10
+ script/generate permit [Person [Authorization [Role]]]
11
+
12
+ If you don't want to use named authorizations, and only want to generate the
13
+ initializer pass in the --init-only option. You can optionally pass the name
14
+ of the class that represents an authenticated user and the generator will set
15
+ the name of the current_* method to use to retrieve the subject for
16
+ authorization.
17
+
18
+ script/generate permit [Person] --init-only
19
+
20
+ Example:
21
+ script/generate permit
22
+
23
+ This will create:
24
+ Model: app/models/authorization.rb
25
+ Model: app/models/role.rb
26
+ Migration: db/migrate/xxx_create_permit_structure.rb
27
+ Initializer: config/initializers/permit.rb
28
+
29
+ script/generate permit Employee Access Job
30
+
31
+ This will create:
32
+ Model: app/models/access.rb
33
+ Model: app/models/job.rb
34
+ Migration: db/migrate/xxx_create_permit_structure.rb
35
+ Initializer: config/initializers/permit.rb
36
+
37
+ script/generate permit --init-only
38
+
39
+ This will create:
40
+ Initializer: config/initializers/permit.rb
@@ -0,0 +1,25 @@
1
+ class PermitGenerator < Rails::Generator::Base
2
+ default_options :setup_named_roles => true
3
+
4
+ attr_reader :authorization_class, :role_class, :person_class
5
+ def manifest
6
+ record do |m|
7
+ @person_class = (args.shift || 'Person').camelize
8
+ @authorization_class = (args.shift || 'Authorization').camelize
9
+ @role_class = (args.shift || 'Role').camelize
10
+
11
+ m.template 'initializer.rb', 'config/initializers/permit.rb'
12
+
13
+ if options[:setup_named_roles]
14
+ m.template 'role.rb', "app/models/#{role_class.underscore}.rb"
15
+ m.template 'authorization.rb', "app/models/#{authorization_class.underscore}.rb"
16
+ m.migration_template 'migration.rb', "db/migrate", :migration_file_name => "create_permit_structure"
17
+ end
18
+ end
19
+ end
20
+
21
+ protected
22
+ def add_options!(opt)
23
+ opt.on("--init-only", "Only generate the initializer file.") {|v| options[:setup_named_roles] = false}
24
+ end
25
+ end
@@ -0,0 +1,2 @@
1
+ class <%=authorization_class%> < ActiveRecord::Base
2
+ end
@@ -0,0 +1,37 @@
1
+ # Sets up the core models to be used for authorizations, people, and roles. This
2
+ # call is only required if you are using named authorizations, and may only be
3
+ # called once. If you are not using named authorizations you may leave this
4
+ # commented out.
5
+ <%if options[:setup_named_roles] -%>
6
+ Permit::Config.set_core_models(<%=authorization_class%>, <%=person_class%>, <%=role_class%>)
7
+ <%else -%>
8
+ # Permit::Config.set_core_models(Authorization, Person, Role)
9
+ <%end -%>
10
+
11
+ # Sets the method to use for retrieving the current authorization subject. Leave
12
+ # this nil and Permit will infer the method name(current_*) from the
13
+ # authorization subject model name given to #set_core_models. If named
14
+ # authorizations aren't being used then this will default to :current_person.
15
+ <%if !options[:setup_named_roles] && person_class != 'Person' -%>
16
+ Permit::Config.controller_subject_method = :current_<%=person_class.underscore %>
17
+ <%else -%>
18
+ # Permit::Config.controller_subject_method = nil
19
+ <%end -%>
20
+
21
+ # Controls the default response given by PermitRules#permitted? when no rules
22
+ # match. To automatically allow access if no rules match, set this to :allow.
23
+ # Default is :deny.
24
+ # Permit::Config.default_access = :deny
25
+
26
+ # You can modify the action_aliases hash to add your own aliases to be used for
27
+ # expansion by PermitRules. The hash key is a Symbol for the action to be
28
+ # expanded, and an array of Symbols representing the actions to expand it into.
29
+ # Alias expansion is non-rescursive. The defaults are:
30
+ # {
31
+ # :create => [:new, :create],
32
+ # :update => [:edit, :update],
33
+ # :destroy => [:delete, :destroy],
34
+ # :read => [:index, :show],
35
+ # :write => [:new, :create, :edit, :update]
36
+ # }
37
+ # Permit::Config.action_aliases
@@ -0,0 +1,28 @@
1
+ class CreatePermitStructure < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :<%=role_class.tableize%> do |t|
4
+ t.string :key, :name, :null => false
5
+ t.string :description
6
+ t.boolean :requires_resource, :authorize_resource, :null => false, :default => true
7
+ end
8
+
9
+ add_index :<%=role_class.tableize%>, :key, :unique => true
10
+
11
+ create_table :<%=authorization_class.tableize%> do |t|
12
+ t.integer :<%=person_class.underscore%>_id, :<%=role_class.underscore%>_id, :null => false
13
+ t.string :resource_type
14
+ t.integer :resource_id
15
+ t.timestamps
16
+ end
17
+
18
+ add_index :<%=authorization_class.tableize%>, :<%=person_class.underscore%>_id
19
+ add_index :<%=authorization_class.tableize%>, :<%=role_class.underscore%>_id
20
+ add_index :<%=authorization_class.tableize%>, [:<%=person_class.underscore%>_id, :<%=role_class.underscore%>_id, :resource_type, :resource_id], :unique => true, :name => '<%=authorization_class.tableize%>_idx_uniq'
21
+ end
22
+
23
+
24
+ def self.down
25
+ drop_table :<%=authorization_class.tableize%>
26
+ drop_table :<%=role_class.tableize%>
27
+ end
28
+ end
@@ -0,0 +1,2 @@
1
+ class <%=role_class%> < ActiveRecord::Base
2
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,89 @@
1
+ module Permit
2
+ module Models
3
+ # Defines a set of methods to extend the has_many :authorizations
4
+ # associations to help with querying for common cases. Some of these methods
5
+ # do not show up in the documentation because they are dynamically created
6
+ # with class_eval so that they can be explicit to the models you use for the
7
+ # Person and Role models.
8
+ module AssociationExtensions
9
+ include Permit::Support
10
+
11
+ # Finds all authorizations for the given resource
12
+ #
13
+ # @param [permit_authorizable, nil, :any] resource the resource to find
14
+ # authorizations for. :any may be given to find matches for any resource.
15
+ # @return [<permit_authorization>] the authorizations found for the resource.
16
+ def for(resource)
17
+ conditions = authorization_conditions(nil, resource)
18
+ find(:all, :conditions => conditions)
19
+ end
20
+
21
+ # Finds all authorizations for the given role(s).
22
+ #
23
+ # @param [permit_role, String, Symbol, <permit_role, String, Symbol>]
24
+ # roles the roles to find authorizations for.
25
+ # @return [<permit_authorization>] the authorizations found for the role(s).
26
+ def as(roles)
27
+ conditions = authorization_conditions(roles, :any)
28
+ find(:all, :conditions => conditions)
29
+ end
30
+
31
+ # Finds all authorizations for the given resource and role(s).
32
+ #
33
+ # @param [permit_authorizable, nil, :any] resource the resource to find
34
+ # authorizations for. :any may be given to find matches for any resource.
35
+ # @param [permit_role, String, Symbol, <permit_role, String, Symbol>]
36
+ # roles the roles to find authorizations for.
37
+ # @return [<permit_authorization>] the authorizations found for the resource and role(s)
38
+ def for_resource_as(resource, roles)
39
+ conditions = authorization_conditions(roles, resource)
40
+ find(:all, :conditions => conditions)
41
+ end
42
+
43
+ # Finds all of the resources authorized for the given role(s).
44
+ #
45
+ # @param [permit_role, String, Symbol, <permit_role, String, Symbol>]
46
+ # roles the roles to find authorizations for.
47
+ # @return [<permit_authorizable>] a unique list of resources authorized
48
+ # for the role(s).
49
+ def resources_as(roles)
50
+ as(roles).collect(&:resource).uniq
51
+ end
52
+
53
+ def self.extended(klass)
54
+ class_eval <<-END
55
+ # Finds all of the people that have authorizations for the given resource.
56
+ #
57
+ # @param [permit_authorizable, nil, :any] resource the resource to find
58
+ # authorizations for. :any may be given to find matches for any resource.
59
+ # @return [<permit_person>] a unique list of the people with
60
+ # authorizations for the resource.
61
+ def #{Permit::Config.person_class.plural_class_symbol.to_s}_for(resource)
62
+ self.for(resource).collect(&:#{Permit::Config.person_class.class_symbol.to_s}).uniq
63
+ end
64
+
65
+ # Finds all of the people that have authorizations for the given role(s).
66
+ #
67
+ # @param [permit_role, String, Symbol, <permit_role, String, Symbol>]
68
+ # roles the roles to find authorizations for.
69
+ # @return [<permit_person>] a unique list of the people with
70
+ # authorizations for the role(s).
71
+ def #{Permit::Config.person_class.plural_class_symbol.to_s}_as(roles)
72
+ as(roles).collect(&:#{Permit::Config.person_class.class_symbol.to_s}).uniq
73
+ end
74
+
75
+ # Finds all of the roles authorized for the given resource.
76
+ #
77
+ # @param [permit_authorizable, nil, :any] resource the resource to find
78
+ # authorizations for. :any may be given to find matches for any resource.
79
+ # @return [<permit_role>] a unique list of roles authorized for the
80
+ # resource.
81
+ def #{Permit::Config.role_class.plural_class_symbol.to_s}_for(resource)
82
+ self.for(resource).collect(&:#{Permit::Config.role_class.class_symbol.to_s}).uniq
83
+ end
84
+
85
+ END
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,31 @@
1
+ module Permit
2
+ module Models
3
+ module AuthorizableExtensions
4
+ def self.included(klass)
5
+ klass.extend AuthorizableClassMethods
6
+ klass.extend Permit::Support::ClassMethods
7
+ end
8
+
9
+ module AuthorizableClassMethods
10
+ def permit_authorizable
11
+ return if include? Permit::Models::AuthorizableExtensions::AuthorizableInstanceMethods
12
+
13
+ Permit::Config.authorizable_classes << self
14
+
15
+ permit_authorized_model :as => :resource
16
+
17
+ def resource_type
18
+ self.base_class.to_s
19
+ end
20
+
21
+ include Permit::Support
22
+ include Permit::Models::AuthorizableExtensions::AuthorizableInstanceMethods
23
+ end
24
+
25
+ end
26
+
27
+ module AuthorizableInstanceMethods
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,54 @@
1
+ module Permit
2
+ module Models
3
+ module AuthorizationExtensions
4
+ def self.included(klass)
5
+ klass.extend AuthorizationClassMethods
6
+ klass.extend Permit::Support::ClassMethods
7
+ end
8
+
9
+ module AuthorizationClassMethods
10
+ # Defines the current model class as handling authorizations for Permit.
11
+ def permit_authorization
12
+ return if include? Permit::Models::AuthorizationExtensions::AuthorizationInstanceMethods
13
+
14
+ belongs_to :resource, :polymorphic => true
15
+ belongs_to Permit::Config.person_class.class_symbol, :class_name => Permit::Config.person_class.name
16
+ belongs_to Permit::Config.role_class.class_symbol, :class_name => Permit::Config.role_class.name
17
+
18
+ class_eval <<-END
19
+ protected
20
+ def permit_person_proxy
21
+ #{Permit::Config.person_class.class_symbol.to_s}
22
+ end
23
+
24
+ def permit_role_proxy
25
+ #{Permit::Config.role_class.class_symbol.to_s}
26
+ end
27
+ END
28
+
29
+ validates_presence_of Permit::Config.person_class.class_symbol, Permit::Config.role_class.class_symbol
30
+ validate :resource_presence
31
+ validate :authorization_uniqueness
32
+
33
+ include Permit::Models::AuthorizationExtensions::AuthorizationInstanceMethods
34
+ end
35
+ end
36
+
37
+ module AuthorizationInstanceMethods
38
+ protected
39
+ def authorization_uniqueness
40
+ return true unless permit_person_proxy
41
+ errors.add(Permit::Config.role_class.class_symbol, "This person is already authorized for this resource") if permit_person_proxy.authorized?(permit_role_proxy, resource)
42
+ end
43
+
44
+ def resource_presence
45
+ # Don't try to do anything if role isn't present
46
+ return true unless permit_role_proxy
47
+
48
+ errors.add(:resource, :blank) if permit_role_proxy.requires_resource? && resource.nil?
49
+ errors.add(:resource, "Specific resources may not be granted for this role.") if !permit_role_proxy.authorize_resource? && !resource.nil?
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end