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