authority 1.0.0.pre2 → 1.0.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/CHANGELOG.markdown +8 -0
- data/README.markdown +9 -9
- data/TODO.markdown +8 -5
- data/lib/authority/controller.rb +27 -9
- data/lib/authority/version.rb +1 -1
- data/spec/authority/controller_spec.rb +38 -19
- data/spec/support/example_controllers.rb +23 -0
- metadata +21 -8
- data/spec/support/example_controller.rb +0 -5
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/CHANGELOG.markdown
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
|
3
3
|
This is mainly to document major new features and backwards-incompatible changes.
|
4
4
|
|
5
|
+
## v1.0.0.pre3
|
6
|
+
|
7
|
+
- Rename controller methods (again):
|
8
|
+
- `authorize_actions_on` => `authorize_actions_for`
|
9
|
+
- `authorize_action_on` => `authorize_action_for`
|
10
|
+
- Cleaned up `authorize_action_for` to only accept a `resource` argument (the
|
11
|
+
current user is determined by `authority_user`)
|
12
|
+
|
5
13
|
## v1.0.0.pre2
|
6
14
|
|
7
15
|
Rename controller methods:
|
data/README.markdown
CHANGED
@@ -16,7 +16,7 @@ No time for reading! Reading is for chumps! Here's the skinny:
|
|
16
16
|
- Add instance methods to that authorizer to set rules that need to look at a resource instance, like "a user can only edit a Lolcat if it belongs to that user and has not been marked as 'classic'".
|
17
17
|
- Wire up your user, models and controllers to work with your authorizers:
|
18
18
|
- In your [user class](#users), `include Authority::UserAbilities`.
|
19
|
-
- Put this in your [controllers](#controllers): `
|
19
|
+
- Put this in your [controllers](#controllers): `authorize_actions_for YourModelNameHere` (the model that controller works with)
|
20
20
|
- Put this in your [models](#models): `include Authority::Abilities`
|
21
21
|
|
22
22
|
## Overview
|
@@ -182,17 +182,17 @@ That's it! All your authorizer classes could be left empty.
|
|
182
182
|
|
183
183
|
In your controllers, add this method call:
|
184
184
|
|
185
|
-
|
185
|
+
authorize_actions_for ModelName
|
186
186
|
|
187
187
|
That sets up a `before_filter` that **calls your class-level methods before each action**. For instance, before running the `update` action, it will check whether the current user (determined using the configurable `user_method`) `can_update?(ModelName)` at a class level. A return value of false means "this user can never update models of this class."
|
188
188
|
|
189
189
|
By the way, any options you pass in will be used on the `before_filter` that gets created, so you can do things like this:
|
190
190
|
|
191
|
-
|
191
|
+
authorize_actions_for InvisibleSwordsman, :only => :show
|
192
192
|
|
193
193
|
#### Usage within a controller action
|
194
194
|
|
195
|
-
If you need to check some attributes of a model instance to decide if an action is permissible, you can use the **singular** `
|
195
|
+
If you need to check some attributes of a model instance to decide if an action is permissible, you can use the **singular** `authorize_action_for(@resource_instance)`. This method will determine which controller action it was called from, look at the controller action map, determine which method should be checked on the model, and check it.
|
196
196
|
|
197
197
|
The default controller action map is as follows:
|
198
198
|
|
@@ -213,25 +213,25 @@ So, for example, if you did this:
|
|
213
213
|
|
214
214
|
def edit
|
215
215
|
@message = Message.find(params[:id])
|
216
|
-
|
216
|
+
authorize_action_for(@message)
|
217
217
|
end
|
218
218
|
...
|
219
219
|
|
220
220
|
end
|
221
221
|
|
222
|
-
... Authority would determine that it was called from within `edit`, that the `edit` controller action requires permission to `update`, and check whether the user `can_update?(@message)`.
|
222
|
+
... Authority would determine that it was called from within `edit`, that the `edit` controller action requires permission to `update`, and check whether the current user `can_update?(@message)`.
|
223
223
|
|
224
|
-
Each controller gets its own copy of the controller action map. If you want to edit a **single** controller's action map, you can either pass a hash into `
|
224
|
+
Each controller gets its own copy of the controller action map. If you want to edit a **single** controller's action map, you can either pass a hash into `authorize_actions_for`, which will get merged into the existing actions hash...
|
225
225
|
|
226
226
|
class BadgerController < ApplicationController
|
227
|
-
|
227
|
+
authorize_actions_for Badger, :actions => {:neuter => 'update'}
|
228
228
|
...
|
229
229
|
end
|
230
230
|
|
231
231
|
...or you can use a separate method call:
|
232
232
|
|
233
233
|
class BadgerController < ApplicationController
|
234
|
-
|
234
|
+
authorize_actions_for Badger
|
235
235
|
|
236
236
|
authority_action :neuter => 'update'
|
237
237
|
|
data/TODO.markdown
CHANGED
@@ -3,12 +3,15 @@
|
|
3
3
|
## Design
|
4
4
|
|
5
5
|
- Carefully think through names of all public methods & see if they could be clearer or more intuitive
|
6
|
-
- Consider making empty authorizers unnecessary: if one isn't defined, automatically define it as empty. This would reduce setup but slightly increase obfuscation of the workings.
|
7
|
-
- Decide whether there's any reason why `authorizer_action_on` needs a user argument, when we already know the method to call to get the current user.
|
8
6
|
|
9
7
|
## Chores
|
10
8
|
|
11
|
-
- Add separate generator to make an empty authorizer for each file in `app/models`
|
9
|
+
- Add separate generator to make an empty authorizer for each file in `app/models` (prompt for each one)
|
12
10
|
- Test generators
|
13
|
-
|
14
|
-
|
11
|
+
|
12
|
+
## Documentation
|
13
|
+
|
14
|
+
- Make README more concise, or at least more navigable.
|
15
|
+
- How to bypass creating an authorizer for each model - by setting authorizer name directly and having them share.
|
16
|
+
- For instance-level checks, ensuring that you don't call `update` first; use `attributes=` before calling `authorize_action_on`.
|
17
|
+
- Example of checking clean/dirty attributes in instance-level checks. For example, if I'm only allowed to update blue laser cannons, can I make them red? Maybe I need to check whether the old value was blue?
|
data/lib/authority/controller.rb
CHANGED
@@ -8,7 +8,6 @@ module Authority
|
|
8
8
|
included do
|
9
9
|
rescue_from Authority::SecurityTransgression, :with => :authority_forbidden
|
10
10
|
class_attribute :authority_resource
|
11
|
-
class_attribute :controller_action_map
|
12
11
|
end
|
13
12
|
|
14
13
|
module ClassMethods
|
@@ -18,9 +17,9 @@ module Authority
|
|
18
17
|
# @param [Class] model_class - class whose authorizer should be consulted
|
19
18
|
# @param [Hash] options - can contain :actions to be merged with existing
|
20
19
|
# ones and any other options applicable to a before_filter
|
21
|
-
def
|
20
|
+
def authorize_actions_for(model_class, options = {})
|
22
21
|
self.authority_resource = model_class
|
23
|
-
|
22
|
+
authority_action(options[:actions] || {})
|
24
23
|
before_filter :run_authorization_check, options
|
25
24
|
end
|
26
25
|
|
@@ -28,7 +27,15 @@ module Authority
|
|
28
27
|
#
|
29
28
|
# @param [Hash] action_map - controller actions and methods, to be merged with existing action_map
|
30
29
|
def authority_action(action_map)
|
31
|
-
|
30
|
+
authority_action_map.merge!(action_map.symbolize_keys)
|
31
|
+
end
|
32
|
+
|
33
|
+
# The controller action to authority action map used for determining
|
34
|
+
# which Rails actions map to which authority actions (ex: index to read)
|
35
|
+
#
|
36
|
+
# @return [Hash] A duplicated copy of the configured controller_action_map
|
37
|
+
def authority_action_map
|
38
|
+
@authority_action_map ||= Authority.configuration.controller_action_map.dup
|
32
39
|
end
|
33
40
|
end
|
34
41
|
|
@@ -42,21 +49,32 @@ module Authority
|
|
42
49
|
render :file => Rails.root.join('public', '403.html'), :status => 403, :layout => false
|
43
50
|
end
|
44
51
|
|
52
|
+
private
|
53
|
+
|
54
|
+
# The before filter that will be setup to run when the class method
|
55
|
+
# `authorize_actions_for` is called
|
45
56
|
def run_authorization_check
|
46
|
-
|
57
|
+
authorize_action_for self.class.authority_resource
|
58
|
+
end
|
59
|
+
|
60
|
+
# Convencience wrapper for sending configured user_method to extract the
|
61
|
+
# request's current user
|
62
|
+
#
|
63
|
+
# @return [Object] the user object returned from sending the user_method
|
64
|
+
def authority_user
|
65
|
+
send(Authority.configuration.user_method)
|
47
66
|
end
|
48
67
|
|
49
68
|
# To be run in a before_filter; ensure this controller action is allowed for the user
|
50
69
|
#
|
51
70
|
# @param authority_resource [Class], the model class associated with this controller
|
52
|
-
# @param user, object representing the current user of the application
|
53
71
|
# @raise [MissingAction] if controller action isn't a key in `config.controller_action_map`
|
54
|
-
def
|
55
|
-
authority_action = self.class.
|
72
|
+
def authorize_action_for(authority_resource)
|
73
|
+
authority_action = self.class.authority_action_map[action_name.to_sym]
|
56
74
|
if authority_action.nil?
|
57
75
|
raise MissingAction.new("No authority action defined for #{action_name}")
|
58
76
|
end
|
59
|
-
Authority.enforce(authority_action, authority_resource,
|
77
|
+
Authority.enforce(authority_action, authority_resource, authority_user)
|
60
78
|
end
|
61
79
|
|
62
80
|
class MissingAction < StandardError ; end
|
data/lib/authority/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'support/ability_model'
|
3
|
-
require 'support/
|
3
|
+
require 'support/example_controllers'
|
4
4
|
require 'support/mock_rails'
|
5
5
|
require 'support/user'
|
6
6
|
|
@@ -8,43 +8,50 @@ describe Authority::Controller do
|
|
8
8
|
|
9
9
|
describe "when including" do
|
10
10
|
it "should specify rescuing security transgressions" do
|
11
|
-
|
12
|
-
|
13
|
-
DummyController.send(:include, Authority::Controller)
|
11
|
+
SampleController.should_receive(:rescue_from).with(Authority::SecurityTransgression, :with => :authority_forbidden)
|
12
|
+
SampleController.send(:include, Authority::Controller)
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
17
16
|
describe "after including" do
|
18
|
-
|
19
|
-
|
17
|
+
|
18
|
+
describe "the authority controller action map" do
|
19
|
+
|
20
|
+
it "should be created on demand" do
|
21
|
+
ExampleController.instance_variable_set(:@authority_action_map, nil)
|
22
|
+
ExampleController.authority_action_map.should be_a(Hash)
|
23
|
+
ExampleController.authority_action_map.should_not be(Authority.configuration.controller_action_map)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "when subclassing" do
|
27
|
+
it "should allow the child class to edit the controller action map without affecting the parent class" do
|
28
|
+
DummyController.authority_action :erase => 'delete'
|
29
|
+
ExampleController.authority_action_map[:erase].should be_nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
20
33
|
end
|
21
34
|
|
22
35
|
describe "DSL (class) methods" do
|
23
36
|
it "should allow specifying the model to protect" do
|
24
|
-
ExampleController.
|
37
|
+
ExampleController.authorize_actions_for AbilityModel
|
25
38
|
ExampleController.authority_resource.should eq(AbilityModel)
|
26
39
|
end
|
27
40
|
|
28
41
|
it "should pass the options provided to the before filter that is set up" do
|
29
42
|
@options = {:only => [:show, :edit, :update]}
|
30
43
|
ExampleController.should_receive(:before_filter).with(:run_authorization_check, @options)
|
31
|
-
ExampleController.
|
44
|
+
ExampleController.authorize_actions_for AbilityModel, @options
|
32
45
|
end
|
33
46
|
|
34
|
-
it "should
|
35
|
-
ExampleController.
|
36
|
-
ExampleController.
|
37
|
-
ExampleController.controller_action_map.should_not be(Authority.configuration.controller_action_map)
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should allow specifying the authority action map in the `authorize_actions_on` declaration" do
|
41
|
-
ExampleController.authorize_actions_on AbilityModel, :actions => {:eat => 'delete'}
|
42
|
-
ExampleController.controller_action_map[:eat].should eq('delete')
|
47
|
+
it "should allow specifying the authority action map in the `authorize_actions_for` declaration" do
|
48
|
+
ExampleController.authorize_actions_for AbilityModel, :actions => {:eat => 'delete'}
|
49
|
+
ExampleController.authority_action_map[:eat].should eq('delete')
|
43
50
|
end
|
44
51
|
|
45
52
|
it "should have a write into the authority actions map usuable in a DSL format" do
|
46
53
|
ExampleController.authority_action :smite => 'delete'
|
47
|
-
ExampleController.
|
54
|
+
ExampleController.authority_action_map[:smite].should eq('delete')
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
@@ -57,7 +64,7 @@ describe Authority::Controller do
|
|
57
64
|
end
|
58
65
|
|
59
66
|
it "should check authorization on the model specified" do
|
60
|
-
@controller.should_receive(:
|
67
|
+
@controller.should_receive(:authorize_action_for).with(AbilityModel)
|
61
68
|
@controller.send(:run_authorization_check)
|
62
69
|
end
|
63
70
|
|
@@ -70,6 +77,18 @@ describe Authority::Controller do
|
|
70
77
|
expect { @controller.send(:run_authorization_check) }.to raise_error(Authority::Controller::MissingAction)
|
71
78
|
end
|
72
79
|
|
80
|
+
it "should return the authority_user for the current request by using the configured user_method" do
|
81
|
+
@controller.should_receive(Authority.configuration.user_method)
|
82
|
+
@controller.send(:authority_user)
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "in controllers that inherited from a controller including authority, but don't call any class method" do
|
86
|
+
it "should automatically have a new copy of the authority_action_map" do
|
87
|
+
@controller = InstanceController.new
|
88
|
+
@controller.class.authority_action_map.should eq(Authority.configuration.controller_action_map)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
73
92
|
describe "authority_forbidden action" do
|
74
93
|
|
75
94
|
before :each do
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MockController
|
2
|
+
def rescue_from(*args) ; end
|
3
|
+
def before_filter(*args) ; end
|
4
|
+
end
|
5
|
+
|
6
|
+
# this controller will have `authority_actions_for` called on it
|
7
|
+
class ExampleController
|
8
|
+
extend MockController
|
9
|
+
include Authority::Controller
|
10
|
+
end
|
11
|
+
|
12
|
+
class DummyController < ExampleController
|
13
|
+
end
|
14
|
+
|
15
|
+
class InstanceController < ExampleController
|
16
|
+
end
|
17
|
+
|
18
|
+
# this controller will not have `authority_actions_for` called on it but will
|
19
|
+
# have `authority_action_for` called on it
|
20
|
+
class SampleController
|
21
|
+
extend MockController
|
22
|
+
end
|
23
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authority
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.pre3
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -14,7 +14,7 @@ date: 2012-03-20 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &2164558540 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 3.0.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2164558540
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: bundler
|
28
|
-
requirement: &
|
28
|
+
requirement: &2164557960 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,7 +33,7 @@ dependencies:
|
|
33
33
|
version: 1.0.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *2164557960
|
37
37
|
description: Gem for managing authorization on model actions in Rails.
|
38
38
|
email:
|
39
39
|
- nathanmlong@gmail.com
|
@@ -43,6 +43,7 @@ extensions: []
|
|
43
43
|
extra_rdoc_files: []
|
44
44
|
files:
|
45
45
|
- .gitignore
|
46
|
+
- .rspec
|
46
47
|
- .rvmrc
|
47
48
|
- .travis.yml
|
48
49
|
- CHANGELOG.markdown
|
@@ -71,7 +72,7 @@ files:
|
|
71
72
|
- spec/authority_spec.rb
|
72
73
|
- spec/spec_helper.rb
|
73
74
|
- spec/support/ability_model.rb
|
74
|
-
- spec/support/
|
75
|
+
- spec/support/example_controllers.rb
|
75
76
|
- spec/support/mock_rails.rb
|
76
77
|
- spec/support/no_authorizer_model.rb
|
77
78
|
- spec/support/user.rb
|
@@ -95,9 +96,21 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
96
|
version: 1.3.1
|
96
97
|
requirements: []
|
97
98
|
rubyforge_project:
|
98
|
-
rubygems_version: 1.8.
|
99
|
+
rubygems_version: 1.8.16
|
99
100
|
signing_key:
|
100
101
|
specification_version: 3
|
101
102
|
summary: Authority gives you a clean and easy way to say, in your Rails app, **who**
|
102
103
|
is allowed to do **what** with your models, with minimal clutter.
|
103
|
-
test_files:
|
104
|
+
test_files:
|
105
|
+
- spec/authority/abilities_spec.rb
|
106
|
+
- spec/authority/authorizer_spec.rb
|
107
|
+
- spec/authority/configuration_spec.rb
|
108
|
+
- spec/authority/controller_spec.rb
|
109
|
+
- spec/authority/user_abilities_spec.rb
|
110
|
+
- spec/authority_spec.rb
|
111
|
+
- spec/spec_helper.rb
|
112
|
+
- spec/support/ability_model.rb
|
113
|
+
- spec/support/example_controllers.rb
|
114
|
+
- spec/support/mock_rails.rb
|
115
|
+
- spec/support/no_authorizer_model.rb
|
116
|
+
- spec/support/user.rb
|