authority 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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