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.
- data/.gitignore +5 -0
- data/.yardopts +3 -0
- data/MIT-LICENSE +20 -0
- data/README.mkd +238 -0
- data/Rakefile +69 -0
- data/VERSION.yml +5 -0
- data/generators/permit/USAGE +40 -0
- data/generators/permit/permit_generator.rb +25 -0
- data/generators/permit/templates/authorization.rb +2 -0
- data/generators/permit/templates/initializer.rb +37 -0
- data/generators/permit/templates/migration.rb +28 -0
- data/generators/permit/templates/role.rb +2 -0
- data/init.rb +1 -0
- data/install.rb +1 -0
- data/lib/models/association.rb +89 -0
- data/lib/models/authorizable.rb +31 -0
- data/lib/models/authorization.rb +54 -0
- data/lib/models/person.rb +148 -0
- data/lib/models/role.rb +59 -0
- data/lib/permit/controller.rb +132 -0
- data/lib/permit/permit_rule.rb +198 -0
- data/lib/permit/permit_rules.rb +141 -0
- data/lib/permit/support.rb +67 -0
- data/lib/permit.rb +134 -0
- data/permit.gemspec +91 -0
- data/rails/init.rb +7 -0
- data/spec/models/alternate_models_spec.rb +54 -0
- data/spec/models/authorizable_spec.rb +78 -0
- data/spec/models/authorization_spec.rb +77 -0
- data/spec/models/person_spec.rb +278 -0
- data/spec/models/role_spec.rb +121 -0
- data/spec/permit/controller_spec.rb +308 -0
- data/spec/permit/permit_rule_spec.rb +452 -0
- data/spec/permit/permit_rules_spec.rb +273 -0
- data/spec/permit_spec.rb +58 -0
- data/spec/spec_helper.rb +73 -0
- data/spec/support/helpers.rb +13 -0
- data/spec/support/models.rb +38 -0
- data/spec/support/permits_controller.rb +7 -0
- data/tasks/permit_tasks.rake +4 -0
- data/uninstall.rb +1 -0
- metadata +107 -0
data/.yardopts
ADDED
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,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,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
|
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
|