[Zope-Checkins] CVS: Zope2 - User.py:1.146
Brian Lloyd
brian@digicool.com
Tue, 17 Apr 2001 10:46:09 -0400 (EDT)
Update of /cvs-repository/Zope2/lib/python/AccessControl
In directory korak:/home/brian/temp/mainline_test/lib/python/AccessControl
Modified Files:
User.py
Log Message:
Changes to allowed() implementation to reduce overhead of local roles
matching and resolve one of PJE's issues in the UserProgrammableSecurityObjects
proposal.
--- Updated File User.py in package Zope2 --
--- User.py 2001/03/14 19:05:51 1.145
+++ User.py 2001/04/17 14:46:09 1.146
@@ -218,57 +218,81 @@
parent=parent.aq_parent
else: return r
+ def _check_context(self, object):
+ # Check that 'object' exists in the acquisition context of
+ # the parent of the acl_users object containing this user,
+ # to prevent "stealing" access through acquisition tricks.
+ # Return true if in context, false if not or if context
+ # cannot be determined (object is not wrapped).
+ parent = getattr(self, 'aq_parent', None)
+ context = getattr(parent, 'aq_parent', None)
+ if context is not None:
+ if object is None:
+ return 1
+ if not hasattr(object, 'aq_inContextOf'):
+ if hasattr(object, 'im_self'):
+ # This is a method. Grab its self.
+ object=object.im_self
+ if not hasattr(object, 'aq_inContextOf'):
+ # Object is not wrapped, so return false.
+ return 0
+ if object.aq_inContextOf(context, 1):
+ return 1
+ return 0
def allowed(self, object, object_roles=None):
- """Check whether the user has access to object, assuming that
- object.__roles__ is the given roles."""
+ """Check whether the user has access to object. The user must
+ have one of the roles in object_roles to allow access."""
+
+ # Short-circuit the common case of anonymous access.
if object_roles is None or 'Anonymous' in object_roles:
return 1
- usr_roles=self.getRolesInContext(object)
- for role in object_roles:
- if role in usr_roles:
- # The user apparently has one of the necessary
- # roles, but first make sure the object exists
- # in the context of the parent of the acl_users
- # folder.
- ufolder = getattr(self, 'aq_parent', None)
- ucontext = getattr(ufolder, 'aq_parent', None)
- if ucontext is not None:
- if object is None:
- # This is a strange rule, though
- # it doesn't cause any security holes. SDH
- return 1
- if not hasattr(object, 'aq_inContextOf'):
- if hasattr(object, 'im_self'):
- # This is a method. Grab its self.
- object=object.im_self
- if not hasattr(object, 'aq_inContextOf'):
- # object is not wrapped, therefore we
- # can't determine context.
- # Fail the access attempt. Otherwise
- # this would be a security hole.
- return None
- if not object.aq_inContextOf(ucontext, 1):
- if 'Shared' in object_roles:
- # Damn, old role setting. Waaa
- object_roles=self._shared_roles(object)
- if 'Anonymous' in object_roles: return 1
- return None
- # Note that if self were not wrapped, it would
- # not be possible to determine the user's context
- # and this method would return 1.
- # However, as long as user folders always return
- # wrapped user objects, this is safe.
+ # Check for ancient role data up front, convert if found.
+ # This should almost never happen, and should probably be
+ # deprecated at some point.
+ if 'Shared' in object_roles:
+ object_roles = self._shared_roles(object)
+ if object_roles is None or 'Anonymous' in object_roles:
return 1
- if 'Shared' in object_roles:
- # Damn, old role setting. Waaa
- object_roles=self._shared_roles(object)
- if object_roles is None or 'Anonymous' in object_roles: return 1
- while 'Shared' in object_roles: object_roles.remove('Shared')
- return self.allowed(object,object_roles)
+ # Check for a role match with the normal roles given to
+ # the user, then with local roles only if necessary. We
+ # want to avoid as much overhead as possible.
+ user_roles = self.getRoles()
+ for role in object_roles:
+ if role in user_roles:
+ if self._check_context(object):
+ return 1
+ return None
+ # Still have not found a match, so check local roles. We do
+ # this manually rather than call getRolesInContext so that
+ # we can incur only the overhead required to find a match.
+ inner_obj = getattr(object, 'aq_inner', object)
+ user_name = self.getUserName()
+ while 1:
+ local_roles = getattr(inner_obj, '__ac_local_roles__', None)
+ if local_roles:
+ if callable(local_roles):
+ local_roles = local_roles()
+ dict = local_roles or {}
+ local_roles = dict.get(user_name, [])
+ for role in object_roles:
+ if role in local_roles:
+ if self._check_context(object):
+ return 1
+ return 0
+ inner = getattr(inner_obj, 'aq_inner', inner_obj)
+ parent = getattr(inner, 'aq_parent', None)
+ if parent is not None:
+ inner_obj = parent
+ continue
+ if hasattr(inner_obj, 'im_self'):
+ inner_obj=inner_obj.im_self
+ inner_obj=getattr(inner_obj, 'aq_inner', inner_obj)
+ continue
+ break
return None
hasRole=allowed