authority 2.2.0 → 2.3.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.
@@ -1,17 +1,14 @@
1
1
  require 'spec_helper'
2
- require 'support/example_model'
3
- require 'support/user'
2
+ require 'support/example_classes'
4
3
 
5
4
  describe Authority::Authorizer do
6
5
 
7
- before :each do
8
- @example_model = ExampleModel.new
9
- @authorizer = @example_model.authorizer
10
- @user = User.new
11
- end
6
+ let(:model_instance) { ExampleResource.new }
7
+ let(:authorizer) { model_instance.authorizer }
8
+ let(:user) { ExampleUser.new }
12
9
 
13
- it "should take a resource instance in its initializer" do
14
- @authorizer.resource.should eq(@example_model)
10
+ it "takes a resource instance in its initializer" do
11
+ expect(authorizer.resource).to eq(model_instance)
15
12
  end
16
13
 
17
14
  describe "instance methods" do
@@ -19,25 +16,28 @@ describe Authority::Authorizer do
19
16
  Authority.adjectives.each do |adjective|
20
17
  method_name = "#{adjective}_by?"
21
18
 
22
- it "should respond to `#{method_name}`" do
23
- @authorizer.should respond_to(method_name)
19
+ it "responds to `#{method_name}`" do
20
+ expect(authorizer).to respond_to(method_name)
24
21
  end
25
22
 
23
+ describe "#{method_name}" do
24
+
25
+ context "when given an options hash" do
26
26
 
27
- describe "if given an options hash" do
27
+ it "delegates `#{method_name}` to the corresponding class method, passing the options" do
28
+ authorizer.class.should_receive(method_name).with(user, :under => 'God')
29
+ authorizer.send(method_name, user, :under => 'God')
30
+ end
28
31
 
29
- it "should delegate `#{method_name}` to the corresponding class method, passing the options" do
30
- @authorizer.class.should_receive(method_name).with(@user, :under => 'God')
31
- @authorizer.send(method_name, @user, :under => 'God')
32
32
  end
33
33
 
34
- end
34
+ context "when not given an options hash" do
35
35
 
36
- describe "if not given an options hash" do
36
+ it "delegates `#{method_name}` to the corresponding class method, passing no options" do
37
+ authorizer.class.should_receive(method_name).with(user)
38
+ authorizer.send(method_name, user)
39
+ end
37
40
 
38
- it "should delegate `#{method_name}` to the corresponding class method, passing no options" do
39
- @authorizer.class.should_receive(method_name).with(@user)
40
- @authorizer.send(method_name, @user)
41
41
  end
42
42
 
43
43
  end
@@ -51,26 +51,30 @@ describe Authority::Authorizer do
51
51
  Authority.adjectives.each do |adjective|
52
52
  method_name = "#{adjective}_by?"
53
53
 
54
- it "should respond to `#{method_name}`" do
55
- Authority::Authorizer.should respond_to(method_name)
54
+ it "responds to `#{method_name}`" do
55
+ expect(Authority::Authorizer).to respond_to(method_name)
56
56
  end
57
57
 
58
- describe "if given an options hash" do
58
+ describe "#{method_name}" do
59
+
60
+ context "when given an options hash" do
61
+
62
+ it "delegates `#{method_name}` to the authorizer's `default` method, passing the options" do
63
+ able = method_name.sub('_by?', '').to_sym
64
+ Authority::Authorizer.should_receive(:default).with(able, user, :with => 'gusto')
65
+ Authority::Authorizer.send(method_name, user, :with => 'gusto')
66
+ end
59
67
 
60
- it "should delegate `#{method_name}` to the authorizer's `default` method, passing the options" do
61
- able = method_name.sub('_by?', '').to_sym
62
- Authority::Authorizer.should_receive(:default).with(able, @user, :with => 'gusto')
63
- Authority::Authorizer.send(method_name, @user, :with => 'gusto')
64
68
  end
65
69
 
66
- end
70
+ context "when not given an options hash" do
67
71
 
68
- describe "if not given an options hash" do
72
+ it "delegates `#{method_name}` to the authorizer's `default` method, passing no options" do
73
+ able = method_name.sub('_by?', '').to_sym
74
+ Authority::Authorizer.should_receive(:default).with(able, user)
75
+ Authority::Authorizer.send(method_name, user)
76
+ end
69
77
 
70
- it "should delegate `#{method_name}` to the authorizer's `default` method, passing no options" do
71
- able = method_name.sub('_by?', '').to_sym
72
- Authority::Authorizer.should_receive(:default).with(able, @user)
73
- Authority::Authorizer.send(method_name, @user)
74
78
  end
75
79
 
76
80
  end
@@ -81,17 +85,17 @@ describe Authority::Authorizer do
81
85
 
82
86
  describe "the default method" do
83
87
 
84
- describe "if given an options hash" do
88
+ context "when given an options hash" do
85
89
 
86
- it "should return false" do
87
- Authority::Authorizer.default(:implodable, @user, {:for => "my_object"}).should be_false
90
+ it "returns false" do
91
+ expect(Authority::Authorizer.default(:implodable, user, {:for => "my_object"})).to be_false
88
92
  end
89
93
  end
90
94
 
91
- describe "if not given an options hash" do
95
+ context "when not given an options hash" do
92
96
 
93
- it "should return false" do
94
- Authority::Authorizer.default(:implodable, @user).should be_false
97
+ it "returns false" do
98
+ expect(Authority::Authorizer.default(:implodable, user)).to be_false
95
99
  end
96
100
 
97
101
  end
@@ -3,21 +3,21 @@ require 'spec_helper'
3
3
  describe Authority::Configuration do
4
4
  describe "the default configuration" do
5
5
 
6
- it "should have a default authority controller actions map" do
7
- Authority.configuration.controller_action_map.should be_a(Hash)
6
+ it "has a default authority controller actions map" do
7
+ expect(Authority.configuration.controller_action_map).to be_a(Hash)
8
8
  end
9
9
 
10
- it "should have a default controller method for accessing the user object" do
11
- Authority.configuration.user_method.should eq(:current_user)
10
+ it "has a default controller method for accessing the user object" do
11
+ expect(Authority.configuration.user_method).to eq(:current_user)
12
12
  end
13
13
 
14
14
  describe "logging security violations" do
15
15
 
16
- it "should log to standard error by default" do
16
+ it "logs to standard error by default" do
17
17
  Authority.instance_variable_set :@configuration, nil
18
18
  null = File.exists?('/dev/null') ? '/dev/null' : 'NUL:' # Allow for Windows
19
- @logger = Logger.new(null)
20
- Logger.should_receive(:new).with(STDERR).and_return(@logger)
19
+ logger = Logger.new(null)
20
+ Logger.should_receive(:new).with(STDERR).and_return(logger)
21
21
  Authority.configure
22
22
  Authority.configuration.logger
23
23
  end
@@ -40,20 +40,20 @@ describe Authority::Configuration do
40
40
 
41
41
  # This shouldn't be used during runtime, only during configuration
42
42
  # It won't do anything outside of configuration anyway
43
- it "should allow adding to the default list of abilities" do
44
- Authority.configuration.abilities[:eat].should eq('edible')
43
+ it "allows adding to the default list of abilities" do
44
+ expect(Authority.configuration.abilities[:eat]).to eq('edible')
45
45
  end
46
46
 
47
47
  end
48
48
  end
49
49
 
50
- describe "helping those upgrading to 2.0" do
50
+ describe "helping those upgrading from versions prior to 2.0" do
51
51
 
52
52
  before :all do
53
53
  Authority.instance_variable_set :@configuration, nil
54
54
  end
55
55
 
56
- it "should raise a helpful exception if `config.default_strategy` is called" do
56
+ it "raises a helpful exception if `config.default_strategy` is called" do
57
57
  expect { Authority.configure { |config| config.default_strategy = Proc.new { false }}}.to raise_error(
58
58
  ArgumentError, "`config.default_strategy=` was removed in Authority 2.0; see README and CHANGELOG"
59
59
  )
@@ -1,147 +1,212 @@
1
1
  require 'spec_helper'
2
- require 'support/example_model'
3
- require 'support/example_controllers'
2
+ require 'support/example_classes'
4
3
  require 'support/mock_rails'
5
- require 'support/user'
6
4
  require 'active_support/core_ext/proc'
7
5
 
8
6
  describe Authority::Controller do
9
7
 
10
- describe "the security violation callback" do
11
-
12
- it "should call whatever method on the controller that the configuration specifies" do
13
- # Here be dragons!
14
- @fake_exception = Exception.new
15
- @sample_controller = SampleController.new
16
- # If a callback is passed to a controller's `rescue_from` method as the value for
17
- # the `with` option (like `SomeController.rescue_from FooException, :with => some_callback`),
18
- # Rails will use ActiveSupport's `Proc#bind` to ensure that when the proc refers to
19
- # `self`, it will be the controller, not the proc itself.
20
- # I need this callback's `self` to be the controller for the purposes of
21
- # this test, so I'm stealing that behavior.
22
- @callback = Authority::Controller.security_violation_callback.bind(@sample_controller)
23
-
24
- Authority.configuration.security_violation_handler = :fire_ze_missiles
25
- @sample_controller.should_receive(:fire_ze_missiles).with(@fake_exception)
26
- @callback.call(@fake_exception)
27
- end
8
+ class ExampleController
9
+ def self.rescue_from(*args) ; end
10
+ def self.before_filter(*args) ; end
28
11
  end
29
12
 
30
- describe "when including" do
13
+ # Get a fresh descendant class for each test, in case we've modified it
14
+ let(:controller_class) { Class.new(ExampleController) }
15
+
16
+ context "when including" do
31
17
 
32
18
  before :each do
33
19
  Authority::Controller.stub(:security_violation_callback).and_return(Proc.new {|exception| })
34
20
  end
35
21
 
36
- it "should specify rescuing security violations with a standard callback" do
37
- SampleController.should_receive(:rescue_from).with(Authority::SecurityViolation, :with => Authority::Controller.security_violation_callback)
38
- SampleController.send(:include, Authority::Controller)
22
+ after :each do
23
+ controller_class.send(:include, Authority::Controller)
24
+ end
25
+
26
+ it "specifies rescuing security violations with a standard callback" do
27
+ controller_class.should_receive(:rescue_from).with(
28
+ Authority::SecurityViolation, :with => Authority::Controller.security_violation_callback
29
+ )
39
30
  end
40
31
 
41
32
  end
42
33
 
43
- describe "after including" do
34
+ context "after including" do
35
+
36
+ let(:controller_class) do
37
+ Class.new(ExampleController).tap do |c|
38
+ c.send(:include, Authority::Controller)
39
+ end
40
+ end
41
+
42
+ let(:resource_class) { ExampleResource }
43
+
44
+ describe "the security violation callback" do
45
+
46
+ it "calls whatever method on the controller that the configuration specifies" do
47
+ # Here be dragons!
48
+ fake_exception = Exception.new
49
+ controller_instance = controller_class.new
50
+ # If a callback is passed to a controller's `rescue_from` method as the value for
51
+ # the `with` option (like `SomeController.rescue_from FooException, :with => some_callback`),
52
+ # Rails will use ActiveSupport's `Proc#bind` to ensure that when the proc refers to
53
+ # `self`, it will be the controller, not the proc itself.
54
+ # I need this callback's `self` to be the controller for the purposes of
55
+ # this test, so I'm stealing that behavior.
56
+ callback = Authority::Controller.security_violation_callback.bind(controller_instance)
57
+
58
+ Authority.configuration.security_violation_handler = :fire_ze_missiles
59
+ controller_instance.should_receive(:fire_ze_missiles).with(fake_exception)
60
+ callback.call(fake_exception)
61
+ end
62
+ end
44
63
 
45
64
  describe "the authority controller action map" do
46
65
 
47
- it "should be created on demand" do
48
- ExampleController.instance_variable_set(:@authority_action_map, nil)
49
- ExampleController.authority_action_map.should be_a(Hash)
50
- ExampleController.authority_action_map.should_not be(Authority.configuration.controller_action_map)
66
+ before(:each) { controller_class.instance_variable_set(:@authority_action_map, nil) }
67
+
68
+ it "is created on demand" do
69
+ expect(controller_class.authority_action_map).to be_a(Hash)
51
70
  end
52
71
 
53
- describe "when subclassing" do
54
- it "should allow the child class to edit the controller action map without affecting the parent class" do
55
- DummyController.authority_action :erase => 'delete'
56
- ExampleController.authority_action_map[:erase].should be_nil
57
- end
72
+ it "is created as a copy of the configured controller action map" do
73
+ expect(controller_class.authority_action_map).to eq(Authority.configuration.controller_action_map)
74
+ expect(controller_class.authority_action_map).not_to be(Authority.configuration.controller_action_map)
75
+ end
76
+
77
+ it "is unique per controller" do
78
+ child_controller = Class.new(controller_class)
79
+ expect(child_controller.authority_action_map).not_to be(
80
+ controller_class.authority_action_map
81
+ )
58
82
  end
59
83
 
60
84
  end
61
85
 
62
- describe "DSL (class) methods" do
63
- it "should allow specifying the model to protect" do
64
- ExampleController.authorize_actions_for ExampleModel
65
- ExampleController.authority_resource.should eq(ExampleModel)
66
- end
86
+ describe "class methods" do
67
87
 
68
- it "should pass the options provided to the before filter that is set up" do
69
- @options = {:only => [:show, :edit, :update]}
70
- ExampleController.should_receive(:before_filter).with(:run_authorization_check, @options)
71
- ExampleController.authorize_actions_for ExampleModel, @options
72
- end
88
+ describe "authorize_actions_for" do
89
+
90
+ it "allows specifying the model to protect" do
91
+ controller_class.authorize_actions_for(resource_class)
92
+ expect(controller_class.authority_resource).to eq(resource_class)
93
+ end
94
+
95
+ it "sets up a before_filter, passing the options it was given" do
96
+ filter_options = {:only => [:show, :edit, :update]}
97
+ controller_class.should_receive(:before_filter).with(:run_authorization_check, filter_options)
98
+ controller_class.authorize_actions_for(resource_class, filter_options)
99
+ end
100
+
101
+ it "passes the action hash to the `authority_action` method" do
102
+ child_controller = Class.new(controller_class)
103
+ new_actions = {:synthesize => :create, :annihilate => 'delete'}
104
+ child_controller.should_receive(:authority_actions).with(new_actions)
105
+ child_controller.authorize_actions_for(resource_class, :actions => new_actions)
106
+ end
73
107
 
74
- it "should allow specifying the authority action map in the `authorize_actions_for` declaration" do
75
- ExampleController.authorize_actions_for ExampleModel, :actions => {:eat => 'delete'}
76
- ExampleController.authority_action_map[:eat].should eq('delete')
77
108
  end
78
109
 
79
- it "should have a write into the authority actions map usuable in a DSL format" do
80
- ExampleController.authority_action :smite => 'delete'
81
- ExampleController.authority_action_map[:smite].should eq('delete')
110
+ describe "authority_action" do
111
+
112
+ it "modifies this controller's authority action map" do
113
+ new_actions = {:show => :display, :synthesize => :create, :annihilate => 'delete'}
114
+ controller_class.authority_actions(new_actions)
115
+ expect(controller_class.authority_action_map).to eq(
116
+ Authority.configuration.controller_action_map.merge(new_actions)
117
+ )
118
+ end
119
+
120
+ it "does not modify any other controller" do
121
+ child_controller = Class.new(controller_class)
122
+ child_controller.authority_actions(:smite => 'delete')
123
+ expect(controller_class.authority_action_map[:smite]).to eq(nil)
124
+ end
125
+
82
126
  end
127
+
83
128
  end
84
129
 
85
130
  describe "instance methods" do
86
- before :each do
87
- @user = User.new
88
- @controller = ExampleController.new
89
- @controller.stub!(:action_name).and_return(:edit)
90
- @controller.stub!(Authority.configuration.user_method).and_return(@user)
91
- end
92
131
 
93
- it "should check authorization on the model specified" do
94
- @controller.should_receive(:authorize_action_for).with(ExampleModel)
95
- @controller.send(:run_authorization_check)
132
+ let(:controller_class) do
133
+ Class.new(ExampleController).tap do |c|
134
+ c.send(:include, Authority::Controller)
135
+ c.authorize_actions_for(resource_class)
136
+ end
96
137
  end
97
138
 
98
- it "should pass the options provided to `authorize_action_for` downstream" do
99
- @controller.stub!(:action_name).and_return(:destroy)
100
- Authority.should_receive(:enforce).with('delete', ExampleModel, @user, :for => 'context')
101
- @controller.send(:authorize_action_for, ExampleModel, :for => 'context')
139
+ let(:controller_instance) do
140
+ controller_class.new.tap do |cc|
141
+ cc.stub(Authority.configuration.user_method).and_return(user)
142
+ end
102
143
  end
103
144
 
104
- it "should raise a SecurityViolation if authorization fails" do
105
- expect { @controller.send(:run_authorization_check) }.to raise_error(Authority::SecurityViolation)
106
- end
145
+ let(:user) { ExampleUser.new }
146
+
147
+ describe "run_authorization_check (used as a before_filter)" do
148
+
149
+ it "checks authorization on the model specified" do
150
+ controller_instance.should_receive(:authorize_action_for).with(resource_class)
151
+ controller_instance.send(:run_authorization_check)
152
+ end
153
+
154
+ it "raises a MissingAction if there is no corresponding action for the controller" do
155
+ controller_instance.stub(:action_name).and_return('sculpt')
156
+ expect { controller_instance.send(:run_authorization_check) }.to raise_error(
157
+ Authority::Controller::MissingAction
158
+ )
159
+ end
107
160
 
108
- it "should raise a MissingAction if there is no corresponding action for the controller" do
109
- @controller.stub(:action_name).and_return('sculpt')
110
- expect { @controller.send(:run_authorization_check) }.to raise_error(Authority::Controller::MissingAction)
111
161
  end
112
162
 
113
- it "should return the authority_user for the current request by using the configured user_method" do
114
- @controller.should_receive(Authority.configuration.user_method)
115
- @controller.send(:authority_user)
163
+ describe "authorize_action_for" do
164
+
165
+ before(:each) { controller_instance.stub(:action_name).and_return(:destroy) }
166
+
167
+ it "calls Authority.enforce to authorize the action" do
168
+ Authority.should_receive(:enforce)
169
+ controller_instance.send(:authorize_action_for, resource_class)
170
+ end
171
+
172
+ it "passes along any options it was given" do
173
+ options = {:for => 'insolence'}
174
+ Authority.should_receive(:enforce).with('delete', resource_class, user, options)
175
+ controller_instance.send(:authorize_action_for, resource_class, options)
176
+ end
177
+
116
178
  end
117
179
 
118
- describe "in controllers that inherited from a controller including authority, but don't call any class method" do
119
- it "should automatically have a new copy of the authority_action_map" do
120
- @controller = InstanceController.new
121
- @controller.class.authority_action_map.should eq(Authority.configuration.controller_action_map)
180
+ describe "authority_user" do
181
+
182
+ it "gets the user for the current request from the configured user_method" do
183
+ controller_instance.should_receive(Authority.configuration.user_method)
184
+ controller_instance.send(:authority_user)
122
185
  end
186
+
123
187
  end
124
188
 
125
189
  describe "authority_forbidden action" do
126
190
 
127
- before :each do
128
- @mock_error = mock(:message => 'oh noes! an error!')
129
- end
191
+ let(:mock_error) { mock(:message => 'oh noes! an error!') }
130
192
 
131
- it "should log an error" do
193
+ it "logs an error" do
132
194
  Authority.configuration.logger.should_receive(:warn)
133
- @controller.stub(:render)
134
- @controller.send(:authority_forbidden, @mock_error)
195
+ controller_instance.stub(:render)
196
+ controller_instance.send(:authority_forbidden, mock_error)
135
197
  end
136
198
 
137
- it "should render the public/403.html file" do
199
+ it "renders the public/403.html file" do
138
200
  forbidden_page = Rails.root.join('public/403.html')
139
201
  Authority.configuration.logger.stub(:warn)
140
- @controller.should_receive(:render).with(:file => forbidden_page, :status => 403, :layout => false)
141
- @controller.send(:authority_forbidden, @mock_error)
202
+ controller_instance.should_receive(:render).with(:file => forbidden_page, :status => 403, :layout => false)
203
+ controller_instance.send(:authority_forbidden, mock_error)
142
204
  end
205
+
143
206
  end
207
+
144
208
  end
209
+
145
210
  end
146
211
 
147
212
  end