def guard(container, value, index=None): if Containers(type(container)) and Containers(type(value)): # Simple type. Short circuit. return if getSecurityManager().validate(container, container, index, value): return _error(index)
def guarded_getattr(inst, name, default=_marker): """Retrieves an attribute, checking security in the process. Raises Unauthorized if the attribute is found but the user is not allowed to access the attribute. """ if name[:1] == '_': raise Unauthorized, name # Try to get the attribute normally so that unusual # exceptions are caught early. try: v = getattr(inst, name) except AttributeError: if default is not _marker: return default raise try: container = v.im_self except AttributeError: container = aq_parent(aq_inner(v)) or inst assertion = Containers(type(container)) if isinstance(assertion, dict): # We got a table that lets us reason about individual # attrs assertion = assertion.get(name) if assertion: # There's an entry, but it may be a function. if callable(assertion): return assertion(inst, name) # Nope, it's boolean return v raise Unauthorized, name if assertion: if callable(assertion): factory = assertion(name, v) if callable(factory): return factory(inst, name) assert factory == 1 else: assert assertion == 1 return v # See if we can get the value doing a filtered acquire. # aq_acquire will either return the same value as held by # v or it will return an Unauthorized raised by validate. validate = SecurityManagement.getSecurityManager().validate aq_acquire(inst, name, aq_validate, validate) return v
def guarded_getattr(inst, name, default=_marker): """Retrieves an attribute, checking security in the process. Raises Unauthorized if the attribute is found but the user is not allowed to access the attribute. """ if name[:1] == '_': raise Unauthorized, name # Try to get the attribute normally so that unusual # exceptions are caught early. try: v = getattr(inst, name) except AttributeError: if default is not _marker: return default raise try: container = v.im_self except AttributeError: container = aq_parent(aq_inner(v)) or inst assertion = Containers(type(container)) if isinstance(assertion, dict): # We got a table that lets us reason about individual # attrs assertion = assertion.get(name) if assertion: # There's an entry, but it may be a function. if callable(assertion): return assertion(inst, name) # Nope, it's boolean return v raise Unauthorized, name if assertion: if callable(assertion): factory = assertion(name, v) if callable(factory): return factory(inst, name) assert factory == 1 else: assert assertion == 1 return v # See if we can get the value doing a filtered acquire. # aq_acquire will either return the same value as held by # v or it will return an Unauthorized raised by validate. validate = getSecurityManager().validate aq_acquire(inst, name, aq_validate, validate) return v
def testContainersContextManager(self): from AccessControl.SimpleObjectPolicies import override_containers from AccessControl.SimpleObjectPolicies import ContainerAssertions from AccessControl.SimpleObjectPolicies import Containers from types import TracebackType # Surely we have no assertions for this type: self.assertNotIn(TracebackType, ContainerAssertions) with override_containers(TracebackType, 1): self.assertIn(TracebackType, ContainerAssertions) self.assertEqual(Containers(TracebackType), 1) # Override it again. with override_containers(TracebackType, {}): self.assertEqual(Containers(TracebackType), {}) # We are outside the nested override, so the first override should # have been restored. self.assertEqual(Containers(TracebackType), 1) # We are outside all overrides, so the type should no longer be in the # assertions. self.assertNotIn(TracebackType, ContainerAssertions)
def testContainersContextManager(self): from AccessControl.SimpleObjectPolicies import override_containers from AccessControl.SimpleObjectPolicies import ContainerAssertions from AccessControl.SimpleObjectPolicies import Containers from types import EllipsisType # Surely we have no assertions for this type. There might be a good # reason to have then, but I have not even heard of this type. self.assertFalse(EllipsisType in ContainerAssertions) with override_containers(EllipsisType, 1): self.assertTrue(EllipsisType in ContainerAssertions) self.assertEqual(Containers(EllipsisType), 1) # Override it again. with override_containers(EllipsisType, {}): self.assertEqual(Containers(EllipsisType), {}) # We are outside the nested override, so the first override should # have been restored. self.assertEqual(Containers(EllipsisType), 1) # We are outside all overrides, so the type should no longer be in the # assertions. self.assertFalse(EllipsisType in ContainerAssertions)
def guarded_getitem(object, index): if type(index) is SliceType: if index.step is not None: v = object[index] else: start = index.start stop = index.stop if start is None: start = 0 if stop is None: v = object[start:] else: v = object[start:stop] # We don't guard slices. return v v = object[index] if Containers(type(object)) and Containers(type(v)): # Simple type. Short circuit. return v if getSecurityManager().validate(object, object, None, v): return v raise Unauthorized('unauthorized access to element %s' % index)
def validate(self, accessed, container, name, value, context, roles=_noroles, getattr=getattr, _noroles=_noroles, valid_aq_=('aq_parent', 'aq_inner', 'aq_explicit')): ############################################################ # Provide special rules for the acquisition attributes if isinstance(name, str): if name.startswith('aq_') and name not in valid_aq_: if self._verbose: raiseVerbose( 'aq_* names (other than %s) are not allowed' % ', '.join(valid_aq_), accessed, container, name, value, context) raise Unauthorized(name, value) containerbase = aq_base(container) accessedbase = aq_base(accessed) if accessedbase is accessed: # accessed is not a wrapper, so assume that the # value could not have been acquired. accessedbase = container ############################################################ # If roles weren't passed in, we'll try to get them from the object if roles is _noroles: roles = getRoles(container, name, value, _noroles) ############################################################ # We still might not have any roles if roles is _noroles: ############################################################ # We have an object without roles and we didn't get a list # of roles passed in. Presumably, the value is some simple # object like a string or a list. We'll try to get roles # from its container. if container is None: # Either container or a list of roles is required # for ZopeSecurityPolicy to know whether access is # allowable. if self._verbose: raiseVerbose('No container provided', accessed, container, name, value, context) raise Unauthorized(name, value) roles = getattr(container, '__roles__', roles) if roles is _noroles: if containerbase is container: # Container is not wrapped. if containerbase is not accessedbase: if self._verbose: raiseVerbose( 'Unable to find __roles__ in the container ' 'and the container is not wrapped', accessed, container, name, value, context) raise Unauthorized(name, value) else: # Try to acquire roles try: roles = aq_acquire(container, '__roles__') except AttributeError: if containerbase is not accessedbase: if self._verbose: raiseVerbose( 'Unable to find or acquire __roles__ ' 'from the container', accessed, container, name, value, context) raise Unauthorized(name, value) # We need to make sure that we are allowed to # get unprotected attributes from the container. We are # allowed for certain simple containers and if the # container says we can. Simple containers # may also impose name restrictions. p = Containers(type(container), None) if p is None: p = getattr(container, '__allow_access_to_unprotected_subobjects__', None) if p is not None: if not isinstance(p, int): # catches bool too if isinstance(p, dict): if isinstance(name, basestring): p = p.get(name) else: p = 1 else: p = p(name, value) if not p: if self._verbose: raiseVerbose('The container has no security assertions', accessed, container, name, value, context) raise Unauthorized(name, value) if roles is _noroles: return 1 # We are going to need a security-aware object to pass # to allowed(). We'll use the container. value = container # Short-circuit tests if we can: try: if roles is None or 'Anonymous' in roles: return 1 except TypeError: # 'roles' isn't a sequence LOG.error("'%s' passed as roles" " during validation of '%s' is not a sequence." % ( ` roles `, name)) raise # Check executable security stack = context.stack if stack: eo = stack[-1] # If the executable had an owner, can it execute? if self._ownerous: owner = eo.getOwner() if (owner is not None) and not owner.allowed(value, roles): # We don't want someone to acquire if they can't # get an unacquired! if self._verbose: if len(roles) < 1: raiseVerbose("The object is marked as private", accessed, container, name, value, context) elif userHasRolesButNotInContext(owner, value, roles): raiseVerbose( "The owner of the executing script is defined " "outside the context of the object being " "accessed", accessed, container, name, value, context, required_roles=roles, eo_owner=owner, eo=eo) else: raiseVerbose( "The owner of the executing script does not " "have the required permission", accessed, container, name, value, context, required_roles=roles, eo_owner=owner, eo=eo, eo_owner_roles=getUserRolesInContext( owner, value)) raise Unauthorized(name, value) # Proxy roles, which are a lot safer now. proxy_roles = getattr(eo, '_proxy_roles', None) if proxy_roles: # Verify that the owner actually can state the proxy role # in the context of the accessed item; users in subfolders # should not be able to use proxy roles to access items # above their subfolder! owner = eo.getWrappedOwner() if owner is not None: if container is not containerbase: # Unwrapped objects don't need checking if not owner._check_context(container): # container is higher up than the owner, # deny access if self._verbose: raiseVerbose( "The owner of the executing script is " "defined outside the context of the " "object being accessed. The script has " "proxy roles, but they do not apply in " "this context.", accessed, container, name, value, context, required_roles=roles, eo_owner=owner, eo=eo) raise Unauthorized(name, value) for r in proxy_roles: if r in roles: return 1 # Proxy roles actually limit access! if self._verbose: if len(roles) < 1: raiseVerbose("The object is marked as private", accessed, container, name, value, context) else: raiseVerbose( "The proxy roles set on the executing script " "do not allow access", accessed, container, name, value, context, eo=eo, eo_proxy_roles=proxy_roles, required_roles=roles) raise Unauthorized(name, value) try: if self._authenticated and context.user.allowed(value, roles): return 1 except AttributeError: pass if self._verbose: if len(roles) < 1: raiseVerbose("The object is marked as private", accessed, container, name, value, context) elif not self._authenticated: raiseVerbose( "Authenticated access is not allowed by this " "security policy", accessed, container, name, value, context) elif userHasRolesButNotInContext(context.user, value, roles): raiseVerbose( "Your user account is defined outside " "the context of the object being accessed", accessed, container, name, value, context, required_roles=roles, user=context.user) else: raiseVerbose( "Your user account does not " "have the required permission", accessed, container, name, value, context, required_roles=roles, user=context.user, user_roles=getUserRolesInContext(context.user, value)) raise Unauthorized(name, value)
def validate(self, accessed, container, name, value, context, roles=_noroles, getattr=getattr, _noroles=_noroles, valid_aq_=('aq_parent', 'aq_inner', 'aq_explicit')): ############################################################ # Provide special rules for the acquisition attributes if isinstance(name, str): if name.startswith('aq_') and name not in valid_aq_: if self._verbose: raiseVerbose( 'aq_* names (other than %s) are not allowed' % ', '.join(valid_aq_), accessed, container, name, value, context, ) raise Unauthorized(name, value) containerbase = aq_base(container) accessedbase = aq_base(accessed) if accessedbase is accessed: # accessed is not a wrapper, so assume that the # value could not have been acquired. accessedbase = container ############################################################ # If roles weren't passed in, we'll try to get them from the object if roles is _noroles: roles = getRoles(container, name, value, _noroles) ############################################################ # We still might not have any roles if roles is _noroles: ############################################################ # We have an object without roles and we didn't get a list # of roles passed in. Presumably, the value is some simple # object like a string or a list. We'll try to get roles # from its container. if container is None: # Either container or a list of roles is required # for ZopeSecurityPolicy to know whether access is # allowable. if self._verbose: raiseVerbose( 'No container provided', accessed, container, name, value, context) raise Unauthorized(name, value) roles = getattr(container, '__roles__', roles) if roles is _noroles: if containerbase is container: # Container is not wrapped. if containerbase is not accessedbase: if self._verbose: raiseVerbose( 'Unable to find __roles__ in the container ' 'and the container is not wrapped', accessed, container, name, value, context, ) raise Unauthorized(name, value) else: # Try to acquire roles try: roles = aq_acquire(container, '__roles__') except AttributeError: if containerbase is not accessedbase: if self._verbose: raiseVerbose( 'Unable to find or acquire __roles__ ' 'from the container', accessed, container, name, value, context) raise Unauthorized(name, value) # We need to make sure that we are allowed to # get unprotected attributes from the container. We are # allowed for certain simple containers and if the # container says we can. Simple containers # may also impose name restrictions. p = Containers(type(container), None) if p is None: p = getattr(container, '__allow_access_to_unprotected_subobjects__', None) if p is not None: if not isinstance(p, (bool, int)): if isinstance(p, dict): if isinstance(name, string_types): p = p.get(name) else: p = 1 else: p = p(name, value) if not p: if self._verbose: raiseVerbose( 'The container has no security assertions', accessed, container, name, value, context, ) raise Unauthorized(name, value) if roles is _noroles: return 1 # We are going to need a security-aware object to pass # to allowed(). We'll use the container. value = container # Short-circuit tests if we can: try: if roles is None or 'Anonymous' in roles: return 1 except TypeError: # 'roles' isn't a sequence LOG.error( "'%r' passed as roles" " during validation of '%s' is not a sequence." % ( roles, name, ), ) raise # Check executable security stack = context.stack if stack: eo = stack[-1] # If the executable had an owner, can it execute? if self._ownerous: owner = eo.getOwner() if (owner is not None) and not owner.allowed(value, roles): # We don't want someone to acquire if they can't # get an unacquired! if self._verbose: if len(roles) < 1: raiseVerbose( "The object is marked as private", accessed, container, name, value, context, ) elif userHasRolesButNotInContext(owner, value, roles): raiseVerbose( "The owner of the executing script is defined " "outside the context of the object being " "accessed", accessed, container, name, value, context, required_roles=roles, eo_owner=owner, eo=eo, ) else: raiseVerbose( "The owner of the executing script does not " "have the required permission", accessed, container, name, value, context, required_roles=roles, eo_owner=owner, eo=eo, eo_owner_roles=getUserRolesInContext(owner, value), ) raise Unauthorized(name, value) # Proxy roles, which are a lot safer now. proxy_roles = getattr(eo, '_proxy_roles', None) if proxy_roles: # Verify that the owner actually can state the proxy role # in the context of the accessed item; users in subfolders # should not be able to use proxy roles to access items # above their subfolder! owner = eo.getWrappedOwner() if owner is not None: if container is not containerbase: # Unwrapped objects don't need checking if not owner._check_context(container): # container is higher up than the owner, # deny access if self._verbose: raiseVerbose( "The owner of the executing script is " "defined outside the context of the " "object being accessed. The script has " "proxy roles, but they do not apply in " "this context.", accessed, container, name, value, context, required_roles=roles, eo_owner=owner, eo=eo) raise Unauthorized(name, value) for r in proxy_roles: if r in roles: return 1 # Proxy roles actually limit access! if self._verbose: if len(roles) < 1: raiseVerbose( "The object is marked as private", accessed, container, name, value, context) else: raiseVerbose( "The proxy roles set on the executing script " "do not allow access", accessed, container, name, value, context, eo=eo, eo_proxy_roles=proxy_roles, required_roles=roles) raise Unauthorized(name, value) try: if self._authenticated and context.user.allowed(value, roles): return 1 except AttributeError: pass if self._verbose: if len(roles) < 1: raiseVerbose( "The object is marked as private", accessed, container, name, value, context) elif not self._authenticated: raiseVerbose( "Authenticated access is not allowed by this " "security policy", accessed, container, name, value, context) elif userHasRolesButNotInContext(context.user, value, roles): raiseVerbose( "Your user account is defined outside " "the context of the object being accessed", accessed, container, name, value, context, required_roles=roles, user=context.user) else: raiseVerbose( "Your user account does not " "have the required permission", accessed, container, name, value, context, required_roles=roles, user=context.user, user_roles=getUserRolesInContext(context.user, value)) raise Unauthorized(name, value)