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 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
@@ -192,13 +192,13 @@ See also Authorization::AuthorizationHelper.
192
192
 
193
193
  == Models
194
194
 
195
- There are two destinct features for model security built into this plugin:
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 opterations
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 actived explicitly by
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
- = Licence
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.controller_name %></th>
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, signalling
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"] || GuestUser.new
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 infered.
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
- RAILS_DEFAULT_LOGGER.info("The use of user.roles is deprecated. Please add a method " +
236
- "role_symbols to your User model.") if defined?(RAILS_DEFAULT_LOGGER) and !user.respond_to?(:role_symbols)
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? ? [:guest] : roles)
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 guest users in applications
689
- class GuestUser
697
+ # Represents a pseudo-user to facilitate anonymous users in applications
698
+ class AnonymousUser
690
699
  attr_reader :role_symbols
691
- def initialize (roles = [:guest])
700
+ def initialize (roles = [Authorization.default_role])
692
701
  @role_symbols = roles
693
702
  end
694
703
  end
@@ -18,7 +18,7 @@ module Authorization
18
18
  # * merging roles
19
19
  # * role hierarchy
20
20
  #
21
- # Mergeable Rules: respect if_permitted_to hash
21
+ # Merge-able Rules: respect if_permitted_to hash
22
22
  #
23
23
  class Analyzer < AbstractAnalyzer
24
24
  def analyze (rules)
@@ -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
- # * heurisic: change of failed tests; small number of policy items
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, decl_auth will try 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 behaviour.
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 infered from the action name and
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 behaviour:
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 replace the respective CRUD actions.
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 collaction actions to the default resource +collection+
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 perfomed.
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 RuntimeError => e
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
- scopes[:with_permissions_to] = lambda do |parent_scope, *args|
38
- options = args.last.is_a?(Hash) ? args.pop : {}
39
- privilege = (args[0] || :read).to_sym
40
- privileges = [privilege]
41
- context =
42
- if options[:context]
43
- options[:context]
44
- elsif parent_scope.respond_to?(:proxy_reflection)
45
- parent_scope.proxy_reflection.klass.name.tableize.to_sym
46
- elsif parent_scope.respond_to?(:decl_auth_context)
47
- parent_scope.decl_auth_context
48
- else
49
- parent_scope.name.tableize.to_sym
50
- end
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
- engine = options[:engine] || Authorization::Engine.instance
55
- engine.permit!(privileges, :user => user, :skip_attribute_test => true,
56
- :context => context)
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
- obligation_scope_for( privileges, :user => user,
59
- :context => context, :engine => engine, :model => parent_scope)
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
- scopes[:with_permissions_to].call(self, *args)
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.foreach(File.join(::Rails.root, %w{app controllers})) do |entry|
59
- if entry =~ /^\w+_controller\.rb$/
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 modelled data model, see 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 => includes { user }
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 => includes { user } }
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 => includes { user }
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. Deviding makes sense
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 infered from the last reflections target class. Still,
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
@@ -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 %{
@@ -262,7 +262,7 @@ class LoadObjectControllerTest < ActionController::TestCase
262
262
  end
263
263
  }
264
264
 
265
- assert_raise RuntimeError, "No id param supplied" do
265
+ assert_raise StandardError, "No id param supplied" do
266
266
  request!(MockUser.new(:test_role), "show", reader)
267
267
  end
268
268
 
@@ -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
@@ -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 %{
@@ -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' (
@@ -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
- @routes = Rails::Application.routes
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
- - 2
9
- version: 0.5.2
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: 2010-12-31 00:00:00 +01:00
17
+ date: 2011-05-25 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20