ae_declarative_authorization 0.7.0 → 0.7.1
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.
- checksums.yaml +4 -4
- data/Appraisals +21 -21
- data/CHANGELOG +189 -189
- data/Gemfile +7 -7
- data/Gemfile.lock +45 -45
- data/LICENSE.txt +20 -20
- data/README.md +620 -620
- data/README.rdoc +597 -597
- data/Rakefile +33 -33
- data/authorization_rules.dist.rb +20 -20
- data/declarative_authorization.gemspec +24 -24
- data/gemfiles/rails4252.gemfile +10 -10
- data/gemfiles/rails4271.gemfile +10 -10
- data/gemfiles/rails507.gemfile +11 -11
- data/init.rb +5 -5
- data/lib/declarative_authorization.rb +18 -18
- data/lib/declarative_authorization/authorization.rb +821 -821
- data/lib/declarative_authorization/helper.rb +78 -78
- data/lib/declarative_authorization/in_controller.rb +713 -713
- data/lib/declarative_authorization/in_model.rb +156 -156
- data/lib/declarative_authorization/maintenance.rb +215 -215
- data/lib/declarative_authorization/obligation_scope.rb +345 -345
- data/lib/declarative_authorization/railsengine.rb +5 -5
- data/lib/declarative_authorization/reader.rb +549 -549
- data/lib/declarative_authorization/test/helpers.rb +261 -261
- data/lib/declarative_authorization/version.rb +3 -3
- data/lib/generators/authorization/install/install_generator.rb +77 -77
- data/lib/generators/authorization/rules/rules_generator.rb +13 -13
- data/lib/generators/authorization/rules/templates/authorization_rules.rb +27 -27
- data/lib/tasks/authorization_tasks.rake +89 -89
- data/test/authorization_test.rb +1121 -1121
- data/test/controller_filter_resource_access_test.rb +573 -573
- data/test/controller_test.rb +478 -478
- data/test/database.yml +3 -3
- data/test/dsl_reader_test.rb +178 -178
- data/test/functional/filter_access_to_with_id_in_scope_test.rb +88 -88
- data/test/functional/no_filter_access_to_test.rb +79 -79
- data/test/functional/params_block_arity_test.rb +39 -39
- data/test/helper_test.rb +248 -248
- data/test/maintenance_test.rb +46 -46
- data/test/model_test.rb +1840 -1840
- data/test/schema.sql +60 -60
- data/test/test_helper.rb +174 -174
- data/test/test_support/minitest_compatibility.rb +26 -26
- metadata +3 -9
- data/gemfiles/rails4252.gemfile.lock +0 -126
- data/gemfiles/rails4271.gemfile.lock +0 -126
- data/gemfiles/rails507.gemfile.lock +0 -136
- data/log/test.log +0 -34715
- data/test/profiles/access_checking +0 -46
@@ -1,261 +1,261 @@
|
|
1
|
-
require 'blockenspiel'
|
2
|
-
require 'active_support/concern'
|
3
|
-
|
4
|
-
module DeclarativeAuthorization
|
5
|
-
module Test
|
6
|
-
module Helpers
|
7
|
-
extend ActiveSupport::Concern
|
8
|
-
|
9
|
-
class InvalidParamsBlockArity < StandardError
|
10
|
-
def initialize(params_block_name, params_block_arity, max_arity)
|
11
|
-
message = "Params block '#{params_block_name}' has arity of #{params_block_arity}. Max params block arity is #{max_arity}."
|
12
|
-
super(message)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class PrivilegeTestGenerator
|
17
|
-
include Blockenspiel::DSL
|
18
|
-
|
19
|
-
def initialize(test_class, role, privileges)
|
20
|
-
@test_class = test_class
|
21
|
-
@role = role
|
22
|
-
@privileges = [privileges].flatten
|
23
|
-
end
|
24
|
-
|
25
|
-
def allowed(options)
|
26
|
-
role, privileges, actions, params_name = extract_options(options)
|
27
|
-
|
28
|
-
actions.each do |action|
|
29
|
-
privileges.each do |privilege|
|
30
|
-
@test_class.send(:define_method, "test_#{action}__access_allowed__#{role}_role__#{privilege ? "#{privilege}_permissions__" : ""}with_#{params_name || 'no_params'}") do
|
31
|
-
priv_param = (privilege == :hidden ? nil : privilege)
|
32
|
-
if forbidden_with_role_and_privilege?(action, role, priv_param, params_name, options)
|
33
|
-
flunk "The '#{action}' action #{params_name ? "with '#{params_name}' parameters " : ''}should be accessible for users with #{privilege ? "'#{privilege}' permissions for " : ""}the '#{role}' role."
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def denied(options)
|
41
|
-
role, privileges, actions, params_name = extract_options(options)
|
42
|
-
|
43
|
-
actions.each do |action|
|
44
|
-
privileges.each do |privilege|
|
45
|
-
@test_class.send(:define_method, "test_#{action}__access_denied__#{role}_role__#{privilege ? "#{privilege}_permissions__" : ""}with_#{params_name || 'no_params'}") do
|
46
|
-
priv_param = (privilege == :hidden ? nil : privilege)
|
47
|
-
unless forbidden_with_role_and_privilege?(action, role, priv_param, params_name, options)
|
48
|
-
flunk "The '#{action}' action #{params_name ? "with '#{params_name}' parameters " : ''}should NOT be accessible for users with #{privilege ? "'#{privilege}' permissions for " : ""}the '#{role}' role."
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
protected
|
56
|
-
|
57
|
-
def extract_options(options)
|
58
|
-
# Can't use these instance variable from inside a method on the test class
|
59
|
-
role = @role
|
60
|
-
privileges = @privileges
|
61
|
-
|
62
|
-
actions = options[:to]
|
63
|
-
raise ':to is a required option!' unless actions
|
64
|
-
|
65
|
-
actions = [actions] unless actions.is_a?(Array)
|
66
|
-
params_name = options[:with]
|
67
|
-
|
68
|
-
[role, privileges, actions, params_name]
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
class RoleTestGenerator
|
74
|
-
include Blockenspiel::DSL
|
75
|
-
|
76
|
-
def initialize(test_class, role)
|
77
|
-
@test_class = test_class
|
78
|
-
@role = role
|
79
|
-
end
|
80
|
-
|
81
|
-
def privilege(privilege, &block)
|
82
|
-
privileges = [privilege].flatten.uniq
|
83
|
-
|
84
|
-
unless privileges.all? { |privilege| [:hidden, :read, :write].include?(privilege) }
|
85
|
-
raise "Privilege (:when) must be :hidden, :read, or :write. Found #{privilege.inspect}."
|
86
|
-
end
|
87
|
-
|
88
|
-
Blockenspiel.invoke(block, PrivilegeTestGenerator.new(@test_class, @role, privileges))
|
89
|
-
end
|
90
|
-
|
91
|
-
def allowed(options)
|
92
|
-
if options[:when]
|
93
|
-
privilege(options[:when]) { allowed(options) }
|
94
|
-
else
|
95
|
-
Blockenspiel.invoke(Proc.new {allowed(options)}, PrivilegeTestGenerator.new(@test_class, @role, nil))
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def denied(options)
|
100
|
-
if options[:when]
|
101
|
-
privilege(options[:when]) { denied(options) }
|
102
|
-
else
|
103
|
-
Blockenspiel.invoke(Proc.new {denied(options)}, PrivilegeTestGenerator.new(@test_class, @role, nil))
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
class AccessTestGenerator
|
110
|
-
include Blockenspiel::DSL
|
111
|
-
|
112
|
-
def initialize(test_class)
|
113
|
-
@test_class = test_class
|
114
|
-
end
|
115
|
-
|
116
|
-
def params(name, &block)
|
117
|
-
@test_class.define_access_test_params_method(name, &block)
|
118
|
-
end
|
119
|
-
|
120
|
-
def role(role, &block)
|
121
|
-
raise "Role cannot be blank!" if role.blank?
|
122
|
-
Blockenspiel.invoke(block, RoleTestGenerator.new(@test_class, role))
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
126
|
-
|
127
|
-
module ClassMethods
|
128
|
-
attr_reader :access_tests_defined
|
129
|
-
|
130
|
-
def skip_access_tests_for_actions(*actions)
|
131
|
-
@skipped_access_test_actions ||= []
|
132
|
-
@skipped_access_test_actions += actions.map(&:to_sym)
|
133
|
-
end
|
134
|
-
|
135
|
-
def access_tests(&block)
|
136
|
-
@access_tests_defined = true
|
137
|
-
file_output ||= [ 'test/profiles/access_checking', ENV['TEST_ENV_NUMBER'] ].compact.join('.')
|
138
|
-
unless File.exists?(file_output)
|
139
|
-
FileUtils.mkdir_p(File.dirname(file_output))
|
140
|
-
end
|
141
|
-
File.open(file_output, "a+") do |file|
|
142
|
-
file.puts self.controller_class.name
|
143
|
-
end
|
144
|
-
|
145
|
-
Blockenspiel.invoke(block, AccessTestGenerator.new(self))
|
146
|
-
end
|
147
|
-
|
148
|
-
def this_is_an_abstract_controller_so_it_needs_no_access_tests
|
149
|
-
undef_method :test_access_tests_defined if self.method_defined? :test_access_tests_defined
|
150
|
-
undef_method :test_all_public_actions_covered_by_role_tests if self.method_defined? :test_all_public_actions_covered_by_role_tests
|
151
|
-
end
|
152
|
-
|
153
|
-
alias :this_is_a_module_mixed_into_controllers_so_it_needs_no_access_tests :this_is_an_abstract_controller_so_it_needs_no_access_tests
|
154
|
-
alias :the_access_tests_are_tested_elsewhere_so_no_access_tests_are_needed :this_is_an_abstract_controller_so_it_needs_no_access_tests
|
155
|
-
alias :access_tests_not_required :this_is_an_abstract_controller_so_it_needs_no_access_tests
|
156
|
-
|
157
|
-
def all_public_actions
|
158
|
-
actions = controller_class.public_instance_methods(false)
|
159
|
-
actions += controller_class.superclass.public_instance_methods(false)
|
160
|
-
actions.reject! do |method|
|
161
|
-
method =~ /^_/ ||
|
162
|
-
method =~ /^rescue_action/ ||
|
163
|
-
(@skipped_access_test_actions.is_a?(Array) && @skipped_access_test_actions.include?(method))
|
164
|
-
end
|
165
|
-
|
166
|
-
actions.uniq
|
167
|
-
end
|
168
|
-
|
169
|
-
def inherited(child)
|
170
|
-
super
|
171
|
-
|
172
|
-
child.send(:define_method, :test_access_tests_defined) do
|
173
|
-
assert self.class.access_tests_defined, 'Access tests needed but not defined.'
|
174
|
-
end
|
175
|
-
|
176
|
-
child.send(:define_method, :test_all_public_actions_covered_by_role_tests) do
|
177
|
-
test_methods = self.public_methods(false).select { |method| method =~ /^test_/ }
|
178
|
-
untested_actions = self.class.all_public_actions.select { |action| !test_methods.any? { |method| method =~ /^test_#{action}__access_/} }
|
179
|
-
unless untested_actions.empty?
|
180
|
-
flunk "In #{self.class.name}, it appears that #{untested_actions.map(&:inspect).to_sentence} are not tested by any access_tests. Did you forget them?"
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def define_access_test_params_method(name, &block)
|
186
|
-
define_method("access_test_params_for_#{name}", &block)
|
187
|
-
end
|
188
|
-
|
189
|
-
end
|
190
|
-
|
191
|
-
protected
|
192
|
-
|
193
|
-
def response_forbidden?
|
194
|
-
flash[:error] == 'You do not have the correct permissions to access that page. Click the back button to return to your previous page.' ||
|
195
|
-
flash[:error] =~ /You do not have the correct permissions to view this/ ||
|
196
|
-
flash[:error] =~ /You do not have access to/ ||
|
197
|
-
flash[:alert] =~ /You need to sign in/ ||
|
198
|
-
(@response.location =~ /\/users\/sign_in/ && @response.code == "302")
|
199
|
-
end
|
200
|
-
|
201
|
-
def access_test_params_for_param_methods
|
202
|
-
[]
|
203
|
-
end
|
204
|
-
|
205
|
-
def access_test_params(name)
|
206
|
-
return { } unless name.present?
|
207
|
-
|
208
|
-
params = access_test_params_for_param_methods
|
209
|
-
max_arity = params.size
|
210
|
-
|
211
|
-
full_method_name = "access_test_params_for_#{name}"
|
212
|
-
method_arity = method(full_method_name).arity
|
213
|
-
|
214
|
-
unless method_arity <= max_arity
|
215
|
-
raise InvalidParamsBlockArity.new(name, method_arity, max_arity)
|
216
|
-
end
|
217
|
-
|
218
|
-
send(full_method_name, *params[0...method_arity])
|
219
|
-
end
|
220
|
-
|
221
|
-
def access_test_user(role, privilege)
|
222
|
-
raise 'MUST IMPLEMENT!!!'
|
223
|
-
end
|
224
|
-
|
225
|
-
def forbidden_with_role_and_privilege?(action, role, privilege, params_name = nil, options = {})
|
226
|
-
http_method = options[:method] || :get
|
227
|
-
xhr = options[:xhr]
|
228
|
-
|
229
|
-
user = access_test_user(role, privilege)
|
230
|
-
params = access_test_params(params_name)
|
231
|
-
|
232
|
-
send_args = [http_method, action.to_sym]
|
233
|
-
send_kwargs = { params: params }
|
234
|
-
send_kwargs[:xhr] = true if xhr
|
235
|
-
|
236
|
-
errors_to_reraise = [
|
237
|
-
ActionController::RoutingError,
|
238
|
-
ActionController::UrlGenerationError,
|
239
|
-
AbstractController::ActionNotFound
|
240
|
-
]
|
241
|
-
|
242
|
-
errors_to_reraise << Mocha::ExpectationError if defined?(Mocha::ExpectationError)
|
243
|
-
|
244
|
-
begin
|
245
|
-
send *send_args, **send_kwargs
|
246
|
-
return response_forbidden?
|
247
|
-
rescue *errors_to_reraise => e
|
248
|
-
raise e
|
249
|
-
rescue => e
|
250
|
-
if options[:print_error]
|
251
|
-
puts "\n#{e.class.name} raised in action '#{action}':"
|
252
|
-
puts e.message
|
253
|
-
puts e.backtrace.join("\n")
|
254
|
-
end
|
255
|
-
return false
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
end
|
260
|
-
end
|
261
|
-
end
|
1
|
+
require 'blockenspiel'
|
2
|
+
require 'active_support/concern'
|
3
|
+
|
4
|
+
module DeclarativeAuthorization
|
5
|
+
module Test
|
6
|
+
module Helpers
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
class InvalidParamsBlockArity < StandardError
|
10
|
+
def initialize(params_block_name, params_block_arity, max_arity)
|
11
|
+
message = "Params block '#{params_block_name}' has arity of #{params_block_arity}. Max params block arity is #{max_arity}."
|
12
|
+
super(message)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class PrivilegeTestGenerator
|
17
|
+
include Blockenspiel::DSL
|
18
|
+
|
19
|
+
def initialize(test_class, role, privileges)
|
20
|
+
@test_class = test_class
|
21
|
+
@role = role
|
22
|
+
@privileges = [privileges].flatten
|
23
|
+
end
|
24
|
+
|
25
|
+
def allowed(options)
|
26
|
+
role, privileges, actions, params_name = extract_options(options)
|
27
|
+
|
28
|
+
actions.each do |action|
|
29
|
+
privileges.each do |privilege|
|
30
|
+
@test_class.send(:define_method, "test_#{action}__access_allowed__#{role}_role__#{privilege ? "#{privilege}_permissions__" : ""}with_#{params_name || 'no_params'}") do
|
31
|
+
priv_param = (privilege == :hidden ? nil : privilege)
|
32
|
+
if forbidden_with_role_and_privilege?(action, role, priv_param, params_name, options)
|
33
|
+
flunk "The '#{action}' action #{params_name ? "with '#{params_name}' parameters " : ''}should be accessible for users with #{privilege ? "'#{privilege}' permissions for " : ""}the '#{role}' role."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def denied(options)
|
41
|
+
role, privileges, actions, params_name = extract_options(options)
|
42
|
+
|
43
|
+
actions.each do |action|
|
44
|
+
privileges.each do |privilege|
|
45
|
+
@test_class.send(:define_method, "test_#{action}__access_denied__#{role}_role__#{privilege ? "#{privilege}_permissions__" : ""}with_#{params_name || 'no_params'}") do
|
46
|
+
priv_param = (privilege == :hidden ? nil : privilege)
|
47
|
+
unless forbidden_with_role_and_privilege?(action, role, priv_param, params_name, options)
|
48
|
+
flunk "The '#{action}' action #{params_name ? "with '#{params_name}' parameters " : ''}should NOT be accessible for users with #{privilege ? "'#{privilege}' permissions for " : ""}the '#{role}' role."
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def extract_options(options)
|
58
|
+
# Can't use these instance variable from inside a method on the test class
|
59
|
+
role = @role
|
60
|
+
privileges = @privileges
|
61
|
+
|
62
|
+
actions = options[:to]
|
63
|
+
raise ':to is a required option!' unless actions
|
64
|
+
|
65
|
+
actions = [actions] unless actions.is_a?(Array)
|
66
|
+
params_name = options[:with]
|
67
|
+
|
68
|
+
[role, privileges, actions, params_name]
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
class RoleTestGenerator
|
74
|
+
include Blockenspiel::DSL
|
75
|
+
|
76
|
+
def initialize(test_class, role)
|
77
|
+
@test_class = test_class
|
78
|
+
@role = role
|
79
|
+
end
|
80
|
+
|
81
|
+
def privilege(privilege, &block)
|
82
|
+
privileges = [privilege].flatten.uniq
|
83
|
+
|
84
|
+
unless privileges.all? { |privilege| [:hidden, :read, :write, :write_without_delete].include?(privilege) }
|
85
|
+
raise "Privilege (:when) must be :hidden, :read, :write_without_delete, or :write. Found #{privilege.inspect}."
|
86
|
+
end
|
87
|
+
|
88
|
+
Blockenspiel.invoke(block, PrivilegeTestGenerator.new(@test_class, @role, privileges))
|
89
|
+
end
|
90
|
+
|
91
|
+
def allowed(options)
|
92
|
+
if options[:when]
|
93
|
+
privilege(options[:when]) { allowed(options) }
|
94
|
+
else
|
95
|
+
Blockenspiel.invoke(Proc.new {allowed(options)}, PrivilegeTestGenerator.new(@test_class, @role, nil))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def denied(options)
|
100
|
+
if options[:when]
|
101
|
+
privilege(options[:when]) { denied(options) }
|
102
|
+
else
|
103
|
+
Blockenspiel.invoke(Proc.new {denied(options)}, PrivilegeTestGenerator.new(@test_class, @role, nil))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
class AccessTestGenerator
|
110
|
+
include Blockenspiel::DSL
|
111
|
+
|
112
|
+
def initialize(test_class)
|
113
|
+
@test_class = test_class
|
114
|
+
end
|
115
|
+
|
116
|
+
def params(name, &block)
|
117
|
+
@test_class.define_access_test_params_method(name, &block)
|
118
|
+
end
|
119
|
+
|
120
|
+
def role(role, &block)
|
121
|
+
raise "Role cannot be blank!" if role.blank?
|
122
|
+
Blockenspiel.invoke(block, RoleTestGenerator.new(@test_class, role))
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
module ClassMethods
|
128
|
+
attr_reader :access_tests_defined
|
129
|
+
|
130
|
+
def skip_access_tests_for_actions(*actions)
|
131
|
+
@skipped_access_test_actions ||= []
|
132
|
+
@skipped_access_test_actions += actions.map(&:to_sym)
|
133
|
+
end
|
134
|
+
|
135
|
+
def access_tests(&block)
|
136
|
+
@access_tests_defined = true
|
137
|
+
file_output ||= [ 'test/profiles/access_checking', ENV['TEST_ENV_NUMBER'] ].compact.join('.')
|
138
|
+
unless File.exists?(file_output)
|
139
|
+
FileUtils.mkdir_p(File.dirname(file_output))
|
140
|
+
end
|
141
|
+
File.open(file_output, "a+") do |file|
|
142
|
+
file.puts self.controller_class.name
|
143
|
+
end
|
144
|
+
|
145
|
+
Blockenspiel.invoke(block, AccessTestGenerator.new(self))
|
146
|
+
end
|
147
|
+
|
148
|
+
def this_is_an_abstract_controller_so_it_needs_no_access_tests
|
149
|
+
undef_method :test_access_tests_defined if self.method_defined? :test_access_tests_defined
|
150
|
+
undef_method :test_all_public_actions_covered_by_role_tests if self.method_defined? :test_all_public_actions_covered_by_role_tests
|
151
|
+
end
|
152
|
+
|
153
|
+
alias :this_is_a_module_mixed_into_controllers_so_it_needs_no_access_tests :this_is_an_abstract_controller_so_it_needs_no_access_tests
|
154
|
+
alias :the_access_tests_are_tested_elsewhere_so_no_access_tests_are_needed :this_is_an_abstract_controller_so_it_needs_no_access_tests
|
155
|
+
alias :access_tests_not_required :this_is_an_abstract_controller_so_it_needs_no_access_tests
|
156
|
+
|
157
|
+
def all_public_actions
|
158
|
+
actions = controller_class.public_instance_methods(false)
|
159
|
+
actions += controller_class.superclass.public_instance_methods(false)
|
160
|
+
actions.reject! do |method|
|
161
|
+
method =~ /^_/ ||
|
162
|
+
method =~ /^rescue_action/ ||
|
163
|
+
(@skipped_access_test_actions.is_a?(Array) && @skipped_access_test_actions.include?(method))
|
164
|
+
end
|
165
|
+
|
166
|
+
actions.uniq
|
167
|
+
end
|
168
|
+
|
169
|
+
def inherited(child)
|
170
|
+
super
|
171
|
+
|
172
|
+
child.send(:define_method, :test_access_tests_defined) do
|
173
|
+
assert self.class.access_tests_defined, 'Access tests needed but not defined.'
|
174
|
+
end
|
175
|
+
|
176
|
+
child.send(:define_method, :test_all_public_actions_covered_by_role_tests) do
|
177
|
+
test_methods = self.public_methods(false).select { |method| method =~ /^test_/ }
|
178
|
+
untested_actions = self.class.all_public_actions.select { |action| !test_methods.any? { |method| method =~ /^test_#{action}__access_/} }
|
179
|
+
unless untested_actions.empty?
|
180
|
+
flunk "In #{self.class.name}, it appears that #{untested_actions.map(&:inspect).to_sentence} are not tested by any access_tests. Did you forget them?"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def define_access_test_params_method(name, &block)
|
186
|
+
define_method("access_test_params_for_#{name}", &block)
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
protected
|
192
|
+
|
193
|
+
def response_forbidden?
|
194
|
+
flash[:error] == 'You do not have the correct permissions to access that page. Click the back button to return to your previous page.' ||
|
195
|
+
flash[:error] =~ /You do not have the correct permissions to view this/ ||
|
196
|
+
flash[:error] =~ /You do not have access to/ ||
|
197
|
+
flash[:alert] =~ /You need to sign in/ ||
|
198
|
+
(@response.location =~ /\/users\/sign_in/ && @response.code == "302")
|
199
|
+
end
|
200
|
+
|
201
|
+
def access_test_params_for_param_methods
|
202
|
+
[]
|
203
|
+
end
|
204
|
+
|
205
|
+
def access_test_params(name)
|
206
|
+
return { } unless name.present?
|
207
|
+
|
208
|
+
params = access_test_params_for_param_methods
|
209
|
+
max_arity = params.size
|
210
|
+
|
211
|
+
full_method_name = "access_test_params_for_#{name}"
|
212
|
+
method_arity = method(full_method_name).arity
|
213
|
+
|
214
|
+
unless method_arity <= max_arity
|
215
|
+
raise InvalidParamsBlockArity.new(name, method_arity, max_arity)
|
216
|
+
end
|
217
|
+
|
218
|
+
send(full_method_name, *params[0...method_arity])
|
219
|
+
end
|
220
|
+
|
221
|
+
def access_test_user(role, privilege)
|
222
|
+
raise 'MUST IMPLEMENT!!!'
|
223
|
+
end
|
224
|
+
|
225
|
+
def forbidden_with_role_and_privilege?(action, role, privilege, params_name = nil, options = {})
|
226
|
+
http_method = options[:method] || :get
|
227
|
+
xhr = options[:xhr]
|
228
|
+
|
229
|
+
user = access_test_user(role, privilege)
|
230
|
+
params = access_test_params(params_name)
|
231
|
+
|
232
|
+
send_args = [http_method, action.to_sym]
|
233
|
+
send_kwargs = { params: params }
|
234
|
+
send_kwargs[:xhr] = true if xhr
|
235
|
+
|
236
|
+
errors_to_reraise = [
|
237
|
+
ActionController::RoutingError,
|
238
|
+
ActionController::UrlGenerationError,
|
239
|
+
AbstractController::ActionNotFound
|
240
|
+
]
|
241
|
+
|
242
|
+
errors_to_reraise << Mocha::ExpectationError if defined?(Mocha::ExpectationError)
|
243
|
+
|
244
|
+
begin
|
245
|
+
send *send_args, **send_kwargs
|
246
|
+
return response_forbidden?
|
247
|
+
rescue *errors_to_reraise => e
|
248
|
+
raise e
|
249
|
+
rescue => e
|
250
|
+
if options[:print_error]
|
251
|
+
puts "\n#{e.class.name} raised in action '#{action}':"
|
252
|
+
puts e.message
|
253
|
+
puts e.backtrace.join("\n")
|
254
|
+
end
|
255
|
+
return false
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|