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 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): `authorize_actions_on YourModelNameHere` (the model that controller works with)
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
- authorize_actions_on ModelName
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
- authorize_actions_on InvisibleSwordsman, :only => :show
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** `authorize_action_on(@resource_instance, @user)`. 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.
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
- authorize_action_on(@message, current_user)
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 `authorize_actions_on`, which will get merged into the existing actions hash...
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
- authorize_actions_on Badger, :actions => {:neuter => 'update'}
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
- authorize_actions_on Badger
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
- - Test view helpers
14
- - Document how you can bypass creating an authorizer for each model - by setting authorizer name directly and having them share.
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?
@@ -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 authorize_actions_on(model_class, options = {})
20
+ def authorize_actions_for(model_class, options = {})
22
21
  self.authority_resource = model_class
23
- self.controller_action_map = Authority.configuration.controller_action_map.merge(options[:actions] || {}).symbolize_keys
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
- self.controller_action_map.merge!(action_map).symbolize_keys
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
- authorize_action_on self.class.authority_resource, send(Authority.configuration.user_method)
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 authorize_action_on(authority_resource, user)
55
- authority_action = self.class.controller_action_map[action_name.to_sym]
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, user)
77
+ Authority.enforce(authority_action, authority_resource, authority_user)
60
78
  end
61
79
 
62
80
  class MissingAction < StandardError ; end
@@ -1,3 +1,3 @@
1
1
  module Authority
2
- VERSION = "1.0.0.pre2"
2
+ VERSION = "1.0.0.pre3"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'support/ability_model'
3
- require 'support/example_controller'
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
- class DummyController < ExampleController ; end
12
- DummyController.should_receive(:rescue_from).with(Authority::SecurityTransgression, :with => :authority_forbidden)
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
- before :all do
19
- ExampleController.send(:include, Authority::Controller)
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.authorize_actions_on AbilityModel
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.authorize_actions_on AbilityModel, @options
44
+ ExampleController.authorize_actions_for AbilityModel, @options
32
45
  end
33
46
 
34
- it "should give the controller its own copy of the authority actions map" do
35
- ExampleController.authorize_actions_on AbilityModel
36
- ExampleController.controller_action_map.should be_a(Hash)
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.controller_action_map[:smite].should eq('delete')
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(:authorize_action_on).with(AbilityModel, @user)
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.pre2
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: &82931510 !ruby/object:Gem::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: *82931510
25
+ version_requirements: *2164558540
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: bundler
28
- requirement: &82931200 !ruby/object:Gem::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: *82931200
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/example_controller.rb
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.10
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
@@ -1,5 +0,0 @@
1
- class ExampleController
2
- def self.rescue_from(*args) ; end
3
-
4
- def self.before_filter(*args) ; end
5
- end