authority 1.0.0.pre2 → 1.0.0.pre3
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/.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
|