ae_declarative_authorization 1.7.0 → 2.1.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.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d3a61732493a7f1dfa8698fa016e257e119204c7bf878397b5caa62080c360b
|
4
|
+
data.tar.gz: 5d05fbeb9f859e393a42aa86108278037377225ddbe02160a5a6ad5ef4f199fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01ec7768b90fcdb701456f254519acce547a635cc6b49a0fad4080c41cc3d72901bf6443c44de132a5f10df63d7c7bf866189f8d1f6a3e79a4e11e51bfa92547
|
7
|
+
data.tar.gz: 7bf88799408d3883d41ecbb5e5616d1d12323e6f2e535c9d39ada2bea149ce349e6696750c57901d0059e930863e0f4b7a4caab2b7c770c683d1c7ac64f1fd91
|
@@ -21,6 +21,24 @@ module Authorization
|
|
21
21
|
# The exception is raised to ensure that the entire rule is invalidated.
|
22
22
|
class NilAttributeValueError < AuthorizationError; end
|
23
23
|
|
24
|
+
class Config
|
25
|
+
# A function that takes one argument:
|
26
|
+
# - event details (hash)
|
27
|
+
attr_accessor :authorization_denied_callback
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@authorization_denied_callback = nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.config
|
35
|
+
@config ||= Config.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.configure
|
39
|
+
yield config
|
40
|
+
end
|
41
|
+
|
24
42
|
AUTH_DSL_FILES = [Pathname.new(Rails.root || '').join("config", "authorization_rules.rb").to_s] unless defined? AUTH_DSL_FILES
|
25
43
|
|
26
44
|
# Controller-independent method for retrieving the current user.
|
@@ -192,6 +210,24 @@ module Authorization
|
|
192
210
|
end
|
193
211
|
|
194
212
|
if options[:bang]
|
213
|
+
# Call authorization_denied_callback if configured
|
214
|
+
if Authorization.config.authorization_denied_callback
|
215
|
+
action = if options[:controller]&.respond_to?(:action_name)
|
216
|
+
options[:controller].action_name
|
217
|
+
elsif options[:controller]&.respond_to?(:route) # Grape API
|
218
|
+
options[:controller].route&.request_method
|
219
|
+
end
|
220
|
+
|
221
|
+
Authorization.config.authorization_denied_callback&.call(
|
222
|
+
{
|
223
|
+
action: action,
|
224
|
+
path: options[:controller]&.respond_to?(:request) ? options[:controller].request&.path : nil,
|
225
|
+
context: options[:context].to_s,
|
226
|
+
attribute_check_denial: !rules.empty?
|
227
|
+
}
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
195
231
|
if rules.empty?
|
196
232
|
raise NotAuthorized, "No matching rules found for #{privilege} for User with id #{user.try(:id)} " +
|
197
233
|
"(roles #{roles.inspect}, privileges #{privileges.inspect}, " +
|
@@ -23,6 +23,8 @@ module DeclarativeAuthorization
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def allowed(options)
|
26
|
+
return unless @test_class.run_assertion?(options)
|
27
|
+
|
26
28
|
role, privileges, actions, params_name = extract_options(options)
|
27
29
|
|
28
30
|
actions.each do |action|
|
@@ -38,6 +40,8 @@ module DeclarativeAuthorization
|
|
38
40
|
end
|
39
41
|
|
40
42
|
def denied(options)
|
43
|
+
return unless @test_class.run_assertion?(options)
|
44
|
+
|
41
45
|
role, privileges, actions, params_name = extract_options(options)
|
42
46
|
|
43
47
|
actions.each do |action|
|
@@ -89,6 +93,8 @@ module DeclarativeAuthorization
|
|
89
93
|
end
|
90
94
|
|
91
95
|
def allowed(options)
|
96
|
+
return unless @test_class.run_assertion?(options)
|
97
|
+
|
92
98
|
if options[:when]
|
93
99
|
privilege(options[:when]) { allowed(options) }
|
94
100
|
else
|
@@ -97,6 +103,8 @@ module DeclarativeAuthorization
|
|
97
103
|
end
|
98
104
|
|
99
105
|
def denied(options)
|
106
|
+
return unless @test_class.run_assertion?(options)
|
107
|
+
|
100
108
|
if options[:when]
|
101
109
|
privilege(options[:when]) { denied(options) }
|
102
110
|
else
|
@@ -119,21 +127,54 @@ module DeclarativeAuthorization
|
|
119
127
|
|
120
128
|
def role(role, &block)
|
121
129
|
raise "Role cannot be blank!" if role.blank?
|
122
|
-
|
130
|
+
|
131
|
+
Blockenspiel.invoke(block, RoleTestGenerator.new(@test_class, role)) if @test_class.run_role_test?(role)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class AccessTestParser
|
136
|
+
include Blockenspiel::DSL
|
137
|
+
|
138
|
+
def initialize(test_class)
|
139
|
+
@test_class = test_class
|
140
|
+
end
|
141
|
+
|
142
|
+
def params(_name, &_block);end
|
143
|
+
|
144
|
+
def role(role, &block)
|
145
|
+
Blockenspiel.invoke(block, self) if @test_class.run_role_test?(role)
|
123
146
|
end
|
124
147
|
|
148
|
+
def privilege(_privilege, &block)
|
149
|
+
Blockenspiel.invoke(block, self)
|
150
|
+
end
|
151
|
+
|
152
|
+
def allowed(options)
|
153
|
+
if options[:only]
|
154
|
+
@test_class.run_all_assertions = false
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def denied(options)
|
159
|
+
if options[:only]
|
160
|
+
@test_class.run_all_assertions = false
|
161
|
+
end
|
162
|
+
end
|
125
163
|
end
|
126
164
|
|
127
165
|
module ClassMethods
|
128
|
-
attr_reader :access_tests_defined
|
166
|
+
attr_reader :access_tests_defined, :only_run_roles
|
167
|
+
attr_accessor :run_all_assertions
|
129
168
|
|
130
169
|
def skip_access_tests_for_actions(*actions)
|
131
170
|
@skipped_access_test_actions ||= []
|
132
171
|
@skipped_access_test_actions += actions.map(&:to_sym)
|
133
172
|
end
|
134
173
|
|
135
|
-
def access_tests(&block)
|
174
|
+
def access_tests(only_run_roles: nil, &block)
|
136
175
|
@access_tests_defined = true
|
176
|
+
@run_all_assertions = true
|
177
|
+
@only_run_roles = only_run_roles
|
137
178
|
file_output ||= [ Dir.tmpdir + '/test/profiles/access_checking', ENV['TEST_ENV_NUMBER'] ].compact.join('.')
|
138
179
|
unless File.exist?(file_output)
|
139
180
|
FileUtils.mkdir_p(File.dirname(file_output))
|
@@ -142,6 +183,7 @@ module DeclarativeAuthorization
|
|
142
183
|
file.puts self.controller_class.name
|
143
184
|
end
|
144
185
|
|
186
|
+
Blockenspiel.invoke(block, AccessTestParser.new(self))
|
145
187
|
Blockenspiel.invoke(block, AccessTestGenerator.new(self))
|
146
188
|
end
|
147
189
|
|
@@ -192,6 +234,14 @@ module DeclarativeAuthorization
|
|
192
234
|
define_method("access_test_params_for_#{name}", &block)
|
193
235
|
end
|
194
236
|
|
237
|
+
def run_role_test?(role)
|
238
|
+
@only_run_roles.nil? || @only_run_roles.include?(role)
|
239
|
+
end
|
240
|
+
|
241
|
+
def run_assertion?(assertion_options)
|
242
|
+
@run_all_assertions || assertion_options[:only]
|
243
|
+
end
|
244
|
+
|
195
245
|
end
|
196
246
|
|
197
247
|
protected
|
@@ -248,15 +298,27 @@ module DeclarativeAuthorization
|
|
248
298
|
errors_to_reraise << Mocha::ExpectationError if defined?(Mocha::ExpectationError)
|
249
299
|
|
250
300
|
begin
|
301
|
+
if options[:debug]
|
302
|
+
puts "Debug: Sending request - role: #{role}, action: #{action}, privilege: #{privilege}, params: #{params.inspect}, http_method: #{http_method}, xhr: #{xhr}"
|
303
|
+
end
|
251
304
|
send *send_args, **send_kwargs
|
305
|
+
if options[:debug]
|
306
|
+
puts "Debug: Response status: #{response.status}" if response.status
|
307
|
+
puts "Debug: flash[:error]: #{flash[:error]}" if flash[:error]
|
308
|
+
puts "Debug: flash[:alert]: #{flash[:alert]}" if flash[:alert]
|
309
|
+
end
|
252
310
|
return response_forbidden?
|
253
311
|
rescue *errors_to_reraise => e
|
254
312
|
raise e
|
255
313
|
rescue => e
|
256
|
-
|
257
|
-
|
258
|
-
puts
|
259
|
-
puts
|
314
|
+
# Exceptions are expected from controllers as complete requests are not always made in access tests
|
315
|
+
if options[:debug]
|
316
|
+
puts "Debug: Exception raised from controller, not considered as an error for access tests as response is not coming from the declarative authorization framework."
|
317
|
+
puts "Debug: Response status: #{response.status}" if response.status
|
318
|
+
puts "Debug: flash[:error]: #{flash[:error]}" if flash[:error]
|
319
|
+
puts "Debug: flash[:alert]: #{flash[:alert]}" if flash[:alert]
|
320
|
+
puts "Debug: Exception: #{e.class} - #{e.message}"
|
321
|
+
puts e.backtrace.join("\n") if e.backtrace
|
260
322
|
end
|
261
323
|
return false
|
262
324
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ae_declarative_authorization
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AppFolio
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: blockenspiel
|
@@ -77,7 +77,6 @@ files:
|
|
77
77
|
- lib/generators/authorization/install/install_generator.rb
|
78
78
|
- lib/generators/authorization/rules/rules_generator.rb
|
79
79
|
- lib/generators/authorization/rules/templates/authorization_rules.rb
|
80
|
-
- lib/rubocop/cop/decl_auth/before_actions_precede_access_filter.rb
|
81
80
|
- lib/tasks/authorization_tasks.rake
|
82
81
|
- rubocop-decl-auth.yml
|
83
82
|
homepage: https://github.com/appfolio/ae_declarative_authorization
|
@@ -99,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
98
|
- !ruby/object:Gem::Version
|
100
99
|
version: '0'
|
101
100
|
requirements: []
|
102
|
-
rubygems_version: 3.
|
101
|
+
rubygems_version: 3.7.2
|
103
102
|
specification_version: 4
|
104
103
|
summary: Rails gem for maintainable authorization based on readable authorization
|
105
104
|
rules.
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module RuboCop
|
4
|
-
module Cop
|
5
|
-
module DeclAuth
|
6
|
-
# Enforces placing all `before_action` statements prior to the first `filter_access_to` statement.
|
7
|
-
# This ensures that any data required by the access filters is available before the filter is applied.
|
8
|
-
# See the documentation above the `filter_access_to` method in Authorization::Controller::DSL for more information
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# # bad
|
12
|
-
# before_action: :do_something
|
13
|
-
# filter_access_to :all
|
14
|
-
# before_action :find_object
|
15
|
-
#
|
16
|
-
# # good
|
17
|
-
# before_action: :do_something
|
18
|
-
# before_action :find_object
|
19
|
-
#
|
20
|
-
# filter_access_to :all
|
21
|
-
#
|
22
|
-
class BeforeActionsPrecedeAccessFilter < RuboCop::Cop::Base
|
23
|
-
def_node_search :before_actions, '(send nil? :before_action ...)'
|
24
|
-
def_node_search :access_filters, '(send nil? :filter_access_to ...)'
|
25
|
-
|
26
|
-
MSG = '`:filter_access_to` statements should be placed after all other `:before_action` statements.'
|
27
|
-
|
28
|
-
def on_class(node)
|
29
|
-
before_actions = before_actions(node)
|
30
|
-
access_filters = access_filters(node)
|
31
|
-
|
32
|
-
return if before_actions.count.zero? || access_filters.count.zero?
|
33
|
-
|
34
|
-
last_before_action = before_actions.to_a.last
|
35
|
-
first_access_filter = access_filters.to_a.first
|
36
|
-
|
37
|
-
return if last_before_action.sibling_index < first_access_filter.sibling_index
|
38
|
-
|
39
|
-
add_offense(access_filters.first, message: MSG)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|