declarative_authorization 0.5.2 → 0.5.3
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.
- data/CHANGELOG +10 -0
- data/README.rdoc +12 -7
- data/app/views/authorization_usages/index.html.erb +1 -1
- data/lib/declarative_authorization/authorization.rb +18 -9
- data/lib/declarative_authorization/development_support/analyzer.rb +1 -1
- data/lib/declarative_authorization/development_support/change_analyzer.rb +1 -1
- data/lib/declarative_authorization/helper.rb +8 -0
- data/lib/declarative_authorization/in_controller.rb +44 -12
- data/lib/declarative_authorization/in_model.rb +49 -22
- data/lib/declarative_authorization/maintenance.rb +3 -6
- data/lib/declarative_authorization/reader.rb +6 -6
- data/test/authorization_test.rb +19 -0
- data/test/controller_test.rb +1 -1
- data/test/helper_test.rb +78 -3
- data/test/model_test.rb +28 -0
- data/test/schema.sql +2 -1
- data/test/test_helper.rb +5 -3
- metadata +3 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
** RELEASE 0.5.3 (May 25, 2011)
|
2
|
+
|
3
|
+
* Bugfixes and documentation cleanup
|
4
|
+
|
5
|
+
* Rails 3.1.rc1 compatibility [sb]
|
6
|
+
|
7
|
+
* Added has_any_role?, has_any_role_with_hierarchy? [t.pickett66]
|
8
|
+
|
9
|
+
* Allow changing the default role [dbloete]
|
10
|
+
|
1
11
|
** RELEASE 0.5.2 (Dec 31, 2010) **
|
2
12
|
|
3
13
|
* Bugfixes and documentation updates
|
data/README.rdoc
CHANGED
@@ -192,13 +192,13 @@ See also Authorization::AuthorizationHelper.
|
|
192
192
|
|
193
193
|
== Models
|
194
194
|
|
195
|
-
There are two
|
195
|
+
There are two distinct features for model security built into this plugin:
|
196
196
|
authorizing CRUD operations on objects as well as query rewriting to limit
|
197
197
|
results according to certain privileges.
|
198
198
|
|
199
199
|
See also Authorization::AuthorizationInModel.
|
200
200
|
|
201
|
-
=== Model security for CRUD
|
201
|
+
=== Model security for CRUD operations
|
202
202
|
To activate model security, all it takes is an explicit enabling for each
|
203
203
|
model that model security should be enforced on, i.e.
|
204
204
|
|
@@ -215,7 +215,7 @@ happened if an operation is denied, the filters throw
|
|
215
215
|
Authorization::NotAuthorized exceptions.
|
216
216
|
|
217
217
|
As access control on read are costly, with possibly lots of objects being
|
218
|
-
loaded at a time in one query, checks on read need to be
|
218
|
+
loaded at a time in one query, checks on read need to be activated explicitly by
|
219
219
|
adding the :include_read option.
|
220
220
|
|
221
221
|
=== Query rewriting through named scopes
|
@@ -256,6 +256,11 @@ public pages, :+guest+ can be used to allow access for users that are not
|
|
256
256
|
logged in. All other roles are application defined and need to be associated
|
257
257
|
with users by the application.
|
258
258
|
|
259
|
+
If you need to change the default role, you can do so by adding an initializer
|
260
|
+
that contains the following statement:
|
261
|
+
|
262
|
+
Authorization.default_role = :anonymous
|
263
|
+
|
259
264
|
Privileges, such as :create, may be put into hierarchies to simplify
|
260
265
|
maintenance. So the example above has the same meaning as
|
261
266
|
|
@@ -512,12 +517,12 @@ sbartsch at tzi.org
|
|
512
517
|
|
513
518
|
Thanks to John Joseph Bachir, Eike Carls, Dennis Blöte, Kai Chen, Erik Dahlstrand,
|
514
519
|
Jeroen van Dijk, Alexander Dobriakov, Sebastian Dyck, Ari Epstein, Jeremy Friesen,
|
515
|
-
Tim Harper, hollownest, Daniel Kristensen, Brad Langhorst, Brian Langenfeld,
|
516
|
-
Georg Ledermann, Geoff Longman, Olly Lylo, Mark Mansour, Thomas Maurer, Sharagoz,
|
517
|
-
TJ Singleton, Mike Vincent
|
520
|
+
Tim Harper, hollownest, Daniel Kristensen, Jeremy Kleindl, Brad Langhorst, Brian Langenfeld,
|
521
|
+
Georg Ledermann, Geoff Longman, Olly Lylo, Mark Mansour, Thomas Maurer, Tyler Pickett, Sharagoz,
|
522
|
+
TJ Singleton, Mike Vincent, Joel Westerberg
|
518
523
|
|
519
524
|
|
520
|
-
=
|
525
|
+
= License
|
521
526
|
|
522
527
|
Copyright (c) 2008 Steffen Bartsch, TZI, Universität Bremen, Germany
|
523
528
|
released under the MIT license
|
@@ -17,7 +17,7 @@
|
|
17
17
|
<% @auth_usages_by_controller.keys.sort {|c1, c2| c1.name <=> c2.name}.each do |controller| %>
|
18
18
|
<% default_context = controller.controller_name.to_sym rescue nil %>
|
19
19
|
<tr>
|
20
|
-
<th colspan="3"><%= h controller.
|
20
|
+
<th colspan="3"><%= h controller.name.underscore.sub(/_controller\Z/, '') %></th>
|
21
21
|
</tr>
|
22
22
|
<% @auth_usages_by_controller[controller].keys.sort {|c1, c2| c1.to_s <=> c2.to_s}.each do |action| %>
|
23
23
|
<% auth_info = @auth_usages_by_controller[controller][action] %>
|
@@ -9,7 +9,7 @@ module Authorization
|
|
9
9
|
# NotAuthorized is raised if the current user is not allowed to perform
|
10
10
|
# the given operation possibly on a specific object.
|
11
11
|
class NotAuthorized < AuthorizationError ; end
|
12
|
-
# AttributeAuthorizationError is more specific than NotAuthorized,
|
12
|
+
# AttributeAuthorizationError is more specific than NotAuthorized, signaling
|
13
13
|
# that the access was denied on the grounds of attribute conditions.
|
14
14
|
class AttributeAuthorizationError < NotAuthorized ; end
|
15
15
|
# AuthorizationUsageError is used whenever a situation is encountered
|
@@ -25,7 +25,7 @@ module Authorization
|
|
25
25
|
# Controller-independent method for retrieving the current user.
|
26
26
|
# Needed for model security where the current controller is not available.
|
27
27
|
def self.current_user
|
28
|
-
Thread.current["current_user"] ||
|
28
|
+
Thread.current["current_user"] || AnonymousUser.new
|
29
29
|
end
|
30
30
|
|
31
31
|
# Controller-independent method for setting the current user.
|
@@ -52,6 +52,15 @@ module Authorization
|
|
52
52
|
@@dot_path = path
|
53
53
|
end
|
54
54
|
|
55
|
+
@@default_role = :guest
|
56
|
+
def self.default_role
|
57
|
+
@@default_role
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.default_role= (role)
|
61
|
+
@@default_role = role.to_sym
|
62
|
+
end
|
63
|
+
|
55
64
|
# Authorization::Engine implements the reference monitor. It may be used
|
56
65
|
# for querying the permission and retrieving obligations under which
|
57
66
|
# a certain privilege is granted for the current user.
|
@@ -113,7 +122,7 @@ module Authorization
|
|
113
122
|
# The context part of the privilege.
|
114
123
|
# Defaults either to the tableized +class_name+ of the given :+object+, if given.
|
115
124
|
# That is, :+users+ for :+object+ of type User.
|
116
|
-
# Raises AuthorizationUsageError if context is missing and not to be
|
125
|
+
# Raises AuthorizationUsageError if context is missing and not to be inferred.
|
117
126
|
# [:+object+] An context object to test attribute checks against.
|
118
127
|
# [:+skip_attribute_test+]
|
119
128
|
# Skips those attribute checks in the
|
@@ -232,8 +241,8 @@ module Authorization
|
|
232
241
|
raise AuthorizationUsageError, "User object doesn't respond to roles (#{user.inspect})" \
|
233
242
|
if !user.respond_to?(:role_symbols) and !user.respond_to?(:roles)
|
234
243
|
|
235
|
-
|
236
|
-
"role_symbols to your User model.") if defined?(
|
244
|
+
Rails.logger.info("The use of user.roles is deprecated. Please add a method " +
|
245
|
+
"role_symbols to your User model.") if defined?(Rails) and Rails.respond_to?(:logger) and !user.respond_to?(:role_symbols)
|
237
246
|
|
238
247
|
roles = user.respond_to?(:role_symbols) ? user.role_symbols : user.roles
|
239
248
|
|
@@ -241,7 +250,7 @@ module Authorization
|
|
241
250
|
"doesn't return an Array of Symbols (#{roles.inspect})" \
|
242
251
|
if !roles.is_a?(Array) or (!roles.empty? and !roles[0].is_a?(Symbol))
|
243
252
|
|
244
|
-
(roles.empty? ? [
|
253
|
+
(roles.empty? ? [Authorization.default_role] : roles)
|
245
254
|
end
|
246
255
|
|
247
256
|
# Returns the role symbols and inherritted role symbols for the given user
|
@@ -685,10 +694,10 @@ module Authorization
|
|
685
694
|
end
|
686
695
|
end
|
687
696
|
|
688
|
-
# Represents a pseudo-user to facilitate
|
689
|
-
class
|
697
|
+
# Represents a pseudo-user to facilitate anonymous users in applications
|
698
|
+
class AnonymousUser
|
690
699
|
attr_reader :role_symbols
|
691
|
-
def initialize (roles = [
|
700
|
+
def initialize (roles = [Authorization.default_role])
|
692
701
|
@role_symbols = roles
|
693
702
|
end
|
694
703
|
end
|
@@ -32,7 +32,7 @@ module Authorization
|
|
32
32
|
|
33
33
|
# * strategy for removing: [remove privilege, add privilege to different role]
|
34
34
|
@seen_states = Set.new
|
35
|
-
# *
|
35
|
+
# * heuristic: change of failed tests; small number of policy items
|
36
36
|
strategy = case [change_action, type]
|
37
37
|
when [:remove, :permission]
|
38
38
|
[:remove_role_from_user, :remove_privilege, :add_privilege,
|
@@ -56,5 +56,13 @@ module Authorization
|
|
56
56
|
def has_role_with_hierarchy?(*roles, &block)
|
57
57
|
controller.has_role_with_hierarchy?(*roles, &block)
|
58
58
|
end
|
59
|
+
|
60
|
+
def has_any_role?(*roles,&block)
|
61
|
+
controller.has_any_role?(*roles,&block)
|
62
|
+
end
|
63
|
+
|
64
|
+
def has_any_role_with_hierarchy?(*roles, &block)
|
65
|
+
controller.has_any_role_with_hierarchy?(*roles, &block)
|
66
|
+
end
|
59
67
|
end
|
60
68
|
end
|
@@ -12,13 +12,13 @@ module Authorization
|
|
12
12
|
|
13
13
|
DEFAULT_DENY = false
|
14
14
|
|
15
|
-
# If attribute_check is set for filter_access_to,
|
15
|
+
# If attribute_check is set for filter_access_to, decl_auth_context will try to
|
16
16
|
# load the appropriate object from the current controller's model with
|
17
17
|
# the id from params[:id]. If that fails, a 404 Not Found is often the
|
18
18
|
# right way to handle the error. If you have additional measures in place
|
19
19
|
# that restricts the find scope, handling this error as a permission denied
|
20
20
|
# might be a better way. Set failed_auto_loading_is_not_found to false
|
21
|
-
# for the latter
|
21
|
+
# for the latter behavior.
|
22
22
|
@@failed_auto_loading_is_not_found = true
|
23
23
|
def self.failed_auto_loading_is_not_found?
|
24
24
|
@@failed_auto_loading_is_not_found
|
@@ -52,7 +52,7 @@ module Authorization
|
|
52
52
|
context = object = nil
|
53
53
|
if object_or_sym.nil?
|
54
54
|
context = self.class.decl_auth_context
|
55
|
-
elsif object_or_sym.is_a?(Symbol)
|
55
|
+
elsif !object_or_sym.respond_to?(:proxy_reflection) and object_or_sym.is_a?(Symbol)
|
56
56
|
context = object_or_sym
|
57
57
|
else
|
58
58
|
object = object_or_sym
|
@@ -86,6 +86,17 @@ module Authorization
|
|
86
86
|
result
|
87
87
|
end
|
88
88
|
|
89
|
+
# Intended to be used where you want to allow users with any single listed role to view
|
90
|
+
# the content in question
|
91
|
+
def has_any_role?(*roles,&block)
|
92
|
+
user_roles = authorization_engine.roles_for(current_user)
|
93
|
+
result = roles.any? do |role|
|
94
|
+
user_roles.include?(role)
|
95
|
+
end
|
96
|
+
yield if result and block_given?
|
97
|
+
result
|
98
|
+
end
|
99
|
+
|
89
100
|
# As has_role? except checks all roles included in the role hierarchy
|
90
101
|
def has_role_with_hierarchy?(*roles, &block)
|
91
102
|
user_roles = authorization_engine.roles_with_hierarchy_for(current_user)
|
@@ -96,6 +107,15 @@ module Authorization
|
|
96
107
|
result
|
97
108
|
end
|
98
109
|
|
110
|
+
# As has_any_role? except checks all roles included in the role hierarchy
|
111
|
+
def has_any_role_with_hierarchy?(*roles, &block)
|
112
|
+
user_roles = authorization_engine.roles_with_hierarchy_for(current_user)
|
113
|
+
result = roles.any? do |role|
|
114
|
+
user_roles.include?(role)
|
115
|
+
end
|
116
|
+
yield if result and block_given?
|
117
|
+
result
|
118
|
+
end
|
99
119
|
|
100
120
|
protected
|
101
121
|
def filter_access_filter # :nodoc:
|
@@ -194,7 +214,7 @@ module Authorization
|
|
194
214
|
# end
|
195
215
|
# end
|
196
216
|
#
|
197
|
-
# By default, required privileges are
|
217
|
+
# By default, required privileges are inferred from the action name and
|
198
218
|
# the controller name. Thus, in UserController :+edit+ requires
|
199
219
|
# :+edit+ +users+. To specify required privilege, use the option :+require+
|
200
220
|
# filter_access_to :new, :create, :require => :create, :context => :users
|
@@ -256,7 +276,7 @@ module Authorization
|
|
256
276
|
# to load the object. Both should return the loaded object.
|
257
277
|
# If a Proc object is given, e.g. by way of
|
258
278
|
# +lambda+, it is called in the instance of the controller.
|
259
|
-
# Example demonstrating the default
|
279
|
+
# Example demonstrating the default behavior:
|
260
280
|
# filter_access_to :show, :attribute_check => true,
|
261
281
|
# :load_method => lambda { User.find(params[:id]) }
|
262
282
|
#
|
@@ -337,7 +357,7 @@ module Authorization
|
|
337
357
|
#
|
338
358
|
# In many cases, the default seven CRUD actions are not sufficient. As in
|
339
359
|
# the resource definition for routing you may thus give additional member,
|
340
|
-
# new and collection methods. The options allow you to specify the
|
360
|
+
# new and collection methods. The +options+ allow you to specify the
|
341
361
|
# required privileges for each action by providing a hash or an array of
|
342
362
|
# pairs. By default, for each action the action name is taken as privilege
|
343
363
|
# (action search in the example below requires the privilege :index
|
@@ -348,7 +368,19 @@ module Authorization
|
|
348
368
|
# :additional_member => {:mark_as_key_company => :update}
|
349
369
|
# end
|
350
370
|
# The +additional_+* options add to the respective CRUD actions,
|
351
|
-
# the other options
|
371
|
+
# the other options (:+member+, :+collection+, :+new+) replace their
|
372
|
+
# respective CRUD actions.
|
373
|
+
# filter_resource_access :member => { :toggle_open => :update }
|
374
|
+
# Would declare :toggle_open as the only member action in the controller and
|
375
|
+
# require that permission :update is granted for the current user.
|
376
|
+
# filter_resource_access :additional_member => { :toggle_open => :update }
|
377
|
+
# Would add a member action :+toggle_open+ to the default members, such as :+show+.
|
378
|
+
#
|
379
|
+
# If :+collection+ is an array of method names filter_resource_access will
|
380
|
+
# associate a permission with the method that is the same as the method
|
381
|
+
# name and no attribute checks will be performed unless
|
382
|
+
# :attribute_check => true
|
383
|
+
# is added in the options.
|
352
384
|
#
|
353
385
|
# You can override the default object loading by implementing any of the
|
354
386
|
# following instance methods on the controller. Examples are given for the
|
@@ -390,7 +422,7 @@ module Authorization
|
|
390
422
|
# +nested_in+, attribute check is deactivated for these actions. By
|
391
423
|
# default, collection is set to :+index+.
|
392
424
|
# [:+additional_collection+]
|
393
|
-
# Allows to add additional
|
425
|
+
# Allows to add additional collection actions to the default resource +collection+
|
394
426
|
# actions.
|
395
427
|
# [:+new+]
|
396
428
|
# +new+ methods are actions such as +new+ and +create+, which don't
|
@@ -422,7 +454,7 @@ module Authorization
|
|
422
454
|
# +additional_member+ or rather the default member actions (:+show+, :+edit+,
|
423
455
|
# :+update+, :+destroy+).
|
424
456
|
# [:+no_attribute_check+]
|
425
|
-
# Allows to set actions for which no attribute check should be
|
457
|
+
# Allows to set actions for which no attribute check should be performed.
|
426
458
|
# See filter_access_to on details. By default, with no +nested_in+,
|
427
459
|
# +no_attribute_check+ is set to all collections. If +nested_in+ is given
|
428
460
|
# +no_attribute_check+ is empty by default.
|
@@ -443,8 +475,8 @@ module Authorization
|
|
443
475
|
:nested_in => nil,
|
444
476
|
}.merge(options)
|
445
477
|
|
446
|
-
new_actions = actions_from_option(options[:new]).merge(
|
447
|
-
actions_from_option(options[:additional_new]))
|
478
|
+
new_actions = actions_from_option( options[:new] ).merge(
|
479
|
+
actions_from_option(options[:additional_new]) )
|
448
480
|
members = actions_from_option(options[:member]).merge(
|
449
481
|
actions_from_option(options[:additional_member]))
|
450
482
|
collections = actions_from_option(options[:collection]).merge(
|
@@ -609,7 +641,7 @@ module Authorization
|
|
609
641
|
unless object
|
610
642
|
begin
|
611
643
|
object = load_object_model.find(contr.params[:id])
|
612
|
-
rescue
|
644
|
+
rescue => e
|
613
645
|
contr.logger.debug("filter_access_to tried to find " +
|
614
646
|
"#{load_object_model} from params[:id] " +
|
615
647
|
"(#{contr.params[:id].inspect}), because attribute_check is enabled " +
|
@@ -34,29 +34,31 @@ module Authorization
|
|
34
34
|
def self.included(base) # :nodoc:
|
35
35
|
#base.extend(ClassMethods)
|
36
36
|
base.module_eval do
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
options[:context]
|
44
|
-
|
45
|
-
parent_scope.proxy_reflection
|
46
|
-
|
47
|
-
parent_scope.decl_auth_context
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
user = options[:user] || Authorization.current_user
|
37
|
+
if Rails.version < "3.1"
|
38
|
+
scopes[:with_permissions_to] = lambda do |parent_scope, *args|
|
39
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
40
|
+
privilege = (args[0] || :read).to_sym
|
41
|
+
privileges = [privilege]
|
42
|
+
context =
|
43
|
+
if options[:context]
|
44
|
+
options[:context]
|
45
|
+
elsif parent_scope.respond_to?(:proxy_reflection)
|
46
|
+
parent_scope.proxy_reflection.klass.name.tableize.to_sym
|
47
|
+
elsif parent_scope.respond_to?(:decl_auth_context)
|
48
|
+
parent_scope.decl_auth_context
|
49
|
+
else
|
50
|
+
parent_scope.name.tableize.to_sym
|
51
|
+
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
user = options[:user] || Authorization.current_user
|
54
|
+
|
55
|
+
engine = options[:engine] || Authorization::Engine.instance
|
56
|
+
engine.permit!(privileges, :user => user, :skip_attribute_test => true,
|
57
|
+
:context => context)
|
57
58
|
|
58
|
-
|
59
|
-
|
59
|
+
obligation_scope_for( privileges, :user => user,
|
60
|
+
:context => context, :engine => engine, :model => parent_scope)
|
61
|
+
end
|
60
62
|
end
|
61
63
|
|
62
64
|
# Builds and returns a scope with joins and conditions satisfying all obligations.
|
@@ -96,7 +98,32 @@ module Authorization
|
|
96
98
|
# current user.
|
97
99
|
#
|
98
100
|
def self.with_permissions_to (*args)
|
99
|
-
|
101
|
+
if Rails.version < "3.1"
|
102
|
+
scopes[:with_permissions_to].call(self, *args)
|
103
|
+
else
|
104
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
105
|
+
privilege = (args[0] || :read).to_sym
|
106
|
+
privileges = [privilege]
|
107
|
+
|
108
|
+
parent_scope = scoped
|
109
|
+
context =
|
110
|
+
if options[:context]
|
111
|
+
options[:context]
|
112
|
+
elsif parent_scope.klass.respond_to?(:decl_auth_context)
|
113
|
+
parent_scope.klass.decl_auth_context
|
114
|
+
else
|
115
|
+
parent_scope.klass.name.tableize.to_sym
|
116
|
+
end
|
117
|
+
|
118
|
+
user = options[:user] || Authorization.current_user
|
119
|
+
|
120
|
+
engine = options[:engine] || Authorization::Engine.instance
|
121
|
+
engine.permit!(privileges, :user => user, :skip_attribute_test => true,
|
122
|
+
:context => context)
|
123
|
+
|
124
|
+
obligation_scope_for( privileges, :user => user,
|
125
|
+
:context => context, :engine => engine, :model => parent_scope.klass)
|
126
|
+
end
|
100
127
|
end
|
101
128
|
|
102
129
|
# Activates model security for the current model. Then, CRUD operations
|
@@ -55,17 +55,14 @@ module Authorization
|
|
55
55
|
def self.usages_by_controller
|
56
56
|
# load each application controller
|
57
57
|
begin
|
58
|
-
Dir.
|
59
|
-
|
60
|
-
require File.join(::Rails.root, %w{app controllers}, entry)
|
61
|
-
end
|
58
|
+
Dir.glob(File.join(::Rails.root, 'app', 'controllers', '**', '*_controller\.rb')) do |entry|
|
59
|
+
require entry
|
62
60
|
end
|
63
61
|
rescue Errno::ENOENT
|
64
62
|
end
|
65
63
|
controllers = []
|
66
64
|
ObjectSpace.each_object(Class) do |obj|
|
67
|
-
controllers << obj if obj.ancestors.include?(ActionController::Base) and
|
68
|
-
!%w{ActionController::Base ApplicationController}.include?(obj.name)
|
65
|
+
controllers << obj if obj.ancestors.include?(ActionController::Base) and obj != ActionController::Base and obj.name.demodulize != 'ApplicationController'
|
69
66
|
end
|
70
67
|
|
71
68
|
controllers.inject({}) do |memo, controller|
|
@@ -6,7 +6,7 @@ module Authorization
|
|
6
6
|
# Parses an authorization configuration file in the authorization DSL and
|
7
7
|
# constructs a data model of its contents.
|
8
8
|
#
|
9
|
-
# For examples and the
|
9
|
+
# For examples and the modeled data model, see the
|
10
10
|
# README[link:files/README_rdoc.html].
|
11
11
|
#
|
12
12
|
# Also, see role definition methods
|
@@ -381,12 +381,12 @@ module Authorization
|
|
381
381
|
#
|
382
382
|
# role :branch_manager
|
383
383
|
# has_permission_on :branches, :to => :manage do
|
384
|
-
# if_attribute :employees =>
|
384
|
+
# if_attribute :employees => contains { user }
|
385
385
|
# end
|
386
386
|
# has_permission_on :employees, :to => :read do
|
387
387
|
# if_permitted_to :read, :branch
|
388
388
|
# # instead of
|
389
|
-
# # if_attribute :branch => { :employees =>
|
389
|
+
# # if_attribute :branch => { :employees => contains { user } }
|
390
390
|
# end
|
391
391
|
# end
|
392
392
|
#
|
@@ -404,19 +404,19 @@ module Authorization
|
|
404
404
|
# To check permissions based on the current object, the attribute has to
|
405
405
|
# be left out:
|
406
406
|
# has_permission_on :branches, :to => :manage do
|
407
|
-
# if_attribute :employees =>
|
407
|
+
# if_attribute :employees => contains { user }
|
408
408
|
# end
|
409
409
|
# has_permission_on :branches, :to => :paint_green do
|
410
410
|
# if_permitted_to :update
|
411
411
|
# end
|
412
|
-
# Normally, one would merge those rules into one.
|
412
|
+
# Normally, one would merge those rules into one. Dividing makes sense
|
413
413
|
# if additional if_attribute are used in the second rule or those rules
|
414
414
|
# are applied to different roles.
|
415
415
|
#
|
416
416
|
# Options:
|
417
417
|
# [:+context+]
|
418
418
|
# When using with_permissions_to, the target context of the if_permitted_to
|
419
|
-
# statement is
|
419
|
+
# statement is inferred from the last reflections target class. Still,
|
420
420
|
# you may override this algorithm by setting the context explicitly.
|
421
421
|
# if_permitted_to :read, :home_branch, :context => :branches
|
422
422
|
# if_permitted_to :read, :branch => :main_company, :context => :companies
|
data/test/authorization_test.rb
CHANGED
@@ -316,6 +316,25 @@ class AuthorizationTest < Test::Unit::TestCase
|
|
316
316
|
assert !engine.permit?(:test, :context => :permissions_2)
|
317
317
|
end
|
318
318
|
|
319
|
+
def test_default_role
|
320
|
+
previous_default_role = Authorization.default_role
|
321
|
+
Authorization.default_role = :anonymous
|
322
|
+
reader = Authorization::Reader::DSLReader.new
|
323
|
+
reader.parse %{
|
324
|
+
authorization do
|
325
|
+
role :anonymous do
|
326
|
+
has_permission_on :permissions, :to => :test
|
327
|
+
end
|
328
|
+
end
|
329
|
+
}
|
330
|
+
engine = Authorization::Engine.new(reader)
|
331
|
+
assert engine.permit?(:test, :context => :permissions)
|
332
|
+
assert !engine.permit?(:test, :context => :permissions,
|
333
|
+
:user => MockUser.new(:guest))
|
334
|
+
# reset the default role, so that it does not mess up other tests
|
335
|
+
Authorization.default_role = previous_default_role
|
336
|
+
end
|
337
|
+
|
319
338
|
def test_invalid_user_model
|
320
339
|
reader = Authorization::Reader::DSLReader.new
|
321
340
|
reader.parse %{
|
data/test/controller_test.rb
CHANGED
@@ -262,7 +262,7 @@ class LoadObjectControllerTest < ActionController::TestCase
|
|
262
262
|
end
|
263
263
|
}
|
264
264
|
|
265
|
-
assert_raise
|
265
|
+
assert_raise StandardError, "No id param supplied" do
|
266
266
|
request!(MockUser.new(:test_role), "show", reader)
|
267
267
|
end
|
268
268
|
|
data/test/helper_test.rb
CHANGED
@@ -113,7 +113,42 @@ class HelperTest < ActionController::TestCase
|
|
113
113
|
end
|
114
114
|
assert !block_evaled
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
|
+
def test_has_any_role
|
118
|
+
reader = Authorization::Reader::DSLReader.new
|
119
|
+
reader.parse %{
|
120
|
+
authorization do
|
121
|
+
role :test_role do
|
122
|
+
has_permission_on :mocks, :to => :show
|
123
|
+
end
|
124
|
+
end
|
125
|
+
}
|
126
|
+
user = MockUser.new(:test_role)
|
127
|
+
request!(user, :action, reader)
|
128
|
+
|
129
|
+
assert has_any_role?(:test_role)
|
130
|
+
assert !has_any_role?(:test_role2)
|
131
|
+
assert has_any_role?(:test_role, :test_role2)
|
132
|
+
|
133
|
+
block_evaled = false
|
134
|
+
has_any_role?(:test_role) do
|
135
|
+
block_evaled = true
|
136
|
+
end
|
137
|
+
assert block_evaled
|
138
|
+
|
139
|
+
block_evaled = false
|
140
|
+
has_any_role?(:test_role2) do
|
141
|
+
block_evaled = true
|
142
|
+
end
|
143
|
+
assert !block_evaled
|
144
|
+
|
145
|
+
block_evaled = false
|
146
|
+
has_any_role?(:test_role,:test_role2) do
|
147
|
+
block_evaled = true
|
148
|
+
end
|
149
|
+
assert block_evaled
|
150
|
+
end
|
151
|
+
|
117
152
|
def test_has_role_with_guest_user
|
118
153
|
reader = Authorization::Reader::DSLReader.new
|
119
154
|
reader.parse %{
|
@@ -165,8 +200,48 @@ class HelperTest < ActionController::TestCase
|
|
165
200
|
block_evaled = true
|
166
201
|
end
|
167
202
|
assert !block_evaled
|
168
|
-
|
169
203
|
end
|
170
204
|
|
171
|
-
|
205
|
+
def test_has_any_role_with_hierarchy
|
206
|
+
reader = Authorization::Reader::DSLReader.new
|
207
|
+
reader.parse %{
|
208
|
+
authorization do
|
209
|
+
role :test_role do
|
210
|
+
has_permission_on :mocks, :to => :show
|
211
|
+
end
|
212
|
+
role :other_role do
|
213
|
+
has_permission_on :another_mocks, :to => :show
|
214
|
+
end
|
215
|
+
|
216
|
+
role :root do
|
217
|
+
includes :test_role
|
218
|
+
end
|
219
|
+
end
|
220
|
+
}
|
221
|
+
|
222
|
+
user = MockUser.new(:root)
|
223
|
+
request!(user, :action, reader)
|
224
|
+
|
225
|
+
assert has_any_role_with_hierarchy?(:test_role)
|
226
|
+
assert !has_any_role_with_hierarchy?(:other_role)
|
227
|
+
assert has_any_role_with_hierarchy?(:test_role,:other_role)
|
228
|
+
|
229
|
+
block_evaled = false
|
230
|
+
has_any_role_with_hierarchy?(:test_role) do
|
231
|
+
block_evaled = true
|
232
|
+
end
|
233
|
+
assert block_evaled
|
234
|
+
|
235
|
+
block_evaled = false
|
236
|
+
has_any_role_with_hierarchy?(:test_role2) do
|
237
|
+
block_evaled = true
|
238
|
+
end
|
239
|
+
assert !block_evaled
|
240
|
+
|
241
|
+
block_evaled = false
|
242
|
+
has_any_role_with_hierarchy?(:test_role,:test_role2) do
|
243
|
+
block_evaled = true
|
244
|
+
end
|
245
|
+
assert block_evaled
|
246
|
+
end
|
172
247
|
end
|
data/test/model_test.rb
CHANGED
@@ -71,6 +71,7 @@ class TestAttr < ActiveRecord::Base
|
|
71
71
|
belongs_to :branch
|
72
72
|
belongs_to :company
|
73
73
|
has_many :test_attr_throughs
|
74
|
+
has_many :test_model_security_model_with_finds
|
74
75
|
attr_reader :role_symbols
|
75
76
|
def initialize (*args)
|
76
77
|
@role_symbols = []
|
@@ -89,6 +90,7 @@ end
|
|
89
90
|
class TestModelSecurityModelWithFind < ActiveRecord::Base
|
90
91
|
set_table_name "test_model_security_models"
|
91
92
|
has_many :test_attrs
|
93
|
+
belongs_to :test_attr
|
92
94
|
using_access_control :include_read => true,
|
93
95
|
:context => :test_model_security_models
|
94
96
|
end
|
@@ -1591,6 +1593,32 @@ class ModelTest < Test::Unit::TestCase
|
|
1591
1593
|
end
|
1592
1594
|
end
|
1593
1595
|
|
1596
|
+
def test_model_security_with_read_restrictions_and_exists
|
1597
|
+
reader = Authorization::Reader::DSLReader.new
|
1598
|
+
reader.parse %{
|
1599
|
+
authorization do
|
1600
|
+
role :test_role do
|
1601
|
+
has_permission_on :test_model_security_models do
|
1602
|
+
to :read, :create, :update, :delete
|
1603
|
+
if_attribute :test_attr => is { user.test_attr }
|
1604
|
+
end
|
1605
|
+
end
|
1606
|
+
end
|
1607
|
+
}
|
1608
|
+
Authorization::Engine.instance(reader)
|
1609
|
+
|
1610
|
+
test_attr = TestAttr.create
|
1611
|
+
Authorization.current_user = MockUser.new(:test_role, :test_attr => test_attr)
|
1612
|
+
object_with_find = TestModelSecurityModelWithFind.create :test_attr => test_attr
|
1613
|
+
assert_nothing_raised do
|
1614
|
+
object_with_find.class.find(object_with_find.id)
|
1615
|
+
end
|
1616
|
+
assert_equal 1, test_attr.test_model_security_model_with_finds.length
|
1617
|
+
|
1618
|
+
# Raises error since AR does not populate the object
|
1619
|
+
#assert test_attr.test_model_security_model_with_finds.exists?(object_with_find)
|
1620
|
+
end
|
1621
|
+
|
1594
1622
|
def test_model_security_delete_unallowed
|
1595
1623
|
reader = Authorization::Reader::DSLReader.new
|
1596
1624
|
reader.parse %{
|
data/test/schema.sql
CHANGED
@@ -28,7 +28,8 @@ CREATE TABLE 'test_attr_throughs' (
|
|
28
28
|
CREATE TABLE 'test_model_security_models' (
|
29
29
|
'id' INTEGER PRIMARY KEY NOT NULL,
|
30
30
|
'attr' integer default 1,
|
31
|
-
'attr_2' integer default 1
|
31
|
+
'attr_2' integer default 1,
|
32
|
+
'test_attr_id' integer
|
32
33
|
);
|
33
34
|
|
34
35
|
CREATE TABLE 'n_way_join_items' (
|
data/test/test_helper.rb
CHANGED
@@ -62,7 +62,7 @@ class MockDataObject
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def self.find(*args)
|
65
|
-
raise "Couldn't find #{self.name} with id #{args[0].inspect}" unless args[0]
|
65
|
+
raise StandardError, "Couldn't find #{self.name} with id #{args[0].inspect}" unless args[0]
|
66
66
|
new :id => args[0]
|
67
67
|
end
|
68
68
|
end
|
@@ -118,7 +118,8 @@ if Rails.version < "3"
|
|
118
118
|
map.connect ':controller/:action/:id'
|
119
119
|
end
|
120
120
|
else
|
121
|
-
Rails::Application.routes.draw do
|
121
|
+
#Rails::Application.routes.draw do
|
122
|
+
Rails.application.routes.draw do
|
122
123
|
match '/name/spaced_things(/:action)' => 'name/spaced_things'
|
123
124
|
match '/deep/name_spaced/things(/:action)' => 'deep/name_spaced/things'
|
124
125
|
match '/:controller(/:action(/:id))'
|
@@ -146,7 +147,8 @@ class Test::Unit::TestCase
|
|
146
147
|
|
147
148
|
unless Rails.version < "3"
|
148
149
|
def setup
|
149
|
-
|
150
|
+
#@routes = Rails::Application.routes
|
151
|
+
@routes = Rails.application.routes
|
150
152
|
end
|
151
153
|
end
|
152
154
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 5
|
8
|
-
-
|
9
|
-
version: 0.5.
|
8
|
+
- 3
|
9
|
+
version: 0.5.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Steffen Bartsch
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-05-25 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|