--- a/src/pyams_security/security.py Wed Jun 17 09:59:26 2015 +0200
+++ b/src/pyams_security/security.py Tue Jun 30 15:02:07 2015 +0200
@@ -28,7 +28,7 @@
from pyams_utils.property import request_property
from pyams_utils.registry import query_utility
from pyramid.location import lineage
-from pyramid.security import DENY_ALL, Everyone, Allow, ALL_PERMISSIONS, Authenticated
+from pyramid.security import DENY_ALL, Everyone, Allow, Deny, ALL_PERMISSIONS, Authenticated
from pyramid.threadlocal import get_current_registry
from zope.container.contained import Contained
from zope.interface import implementer
@@ -42,49 +42,59 @@
"""Base class for object protected by roles"""
inherit_parent_security = FieldProperty(IRoleProtectedObject['inherit_parent_security'])
- _everyone_permissions = FieldProperty(IRoleProtectedObject['everyone_permissions'])
- _authenticated_permissions = FieldProperty(IRoleProtectedObject['authenticated_permissions'])
+ everyone_denied = FieldProperty(IRoleProtectedObject['everyone_denied'])
+ everyone_granted = FieldProperty(IRoleProtectedObject['everyone_granted'])
+ authenticated_denied = FieldProperty(IRoleProtectedObject['authenticated_denied'])
+ authenticated_granted = FieldProperty(IRoleProtectedObject['authenticated_granted'])
inherit_parent_roles = FieldProperty(IRoleProtectedObject['inherit_parent_roles'])
def __init__(self):
self._principals_by_role = PersistentDict()
self._roles_by_principal = PersistentDict()
- @property
- def everyone_permissions(self):
- permissions = self._everyone_permissions
- if (not permissions) and self.inherit_parent_security:
+ def get_everyone_denied(self):
+ permissions = self.everyone_denied or set()
+ if self.inherit_parent_security:
+ for parent in lineage(self):
+ if parent in (self, self.__parent__):
+ continue
+ protection = IProtectedObject(parent, None)
+ if protection is not None:
+ permissions = permissions | (protection.everyone_denied or set())
+ return permissions
+
+ def get_everyone_granted(self):
+ permissions = self.everyone_granted or set()
+ if self.inherit_parent_security:
for parent in lineage(self):
if parent in (self, self.__parent__):
continue
protection = IProtectedObject(parent, None)
if protection is not None:
- permissions = protection.everyone_permissions
- if permissions:
- break
+ permissions = permissions | (protection.everyone_granted or set())
return permissions
- @everyone_permissions.setter
- def everyone_permissions(self, value):
- self._everyone_permissions = value
-
- @property
- def authenticated_permissions(self):
- permissions = self._authenticated_permissions
- if (not permissions) and self.inherit_parent_security:
+ def get_authenticated_denied(self):
+ permissions = self.authenticated_denied or set()
+ if self.inherit_parent_security:
for parent in lineage(self):
if parent in (self, self.__parent__):
continue
protection = IProtectedObject(parent, None)
if protection is not None:
- permissions = protection.authenticated_permissions
- if permissions:
- break
+ permissions = permissions | (protection.authenticated_denied or set())
return permissions
- @authenticated_permissions.setter
- def authenticated_permissions(self, value):
- self._authenticated_permissions = value
+ def get_authenticated_granted(self):
+ permissions = self.authenticated_granted or set()
+ if self.inherit_parent_security:
+ for parent in lineage(self):
+ if parent in (self, self.__parent__):
+ continue
+ protection = IProtectedObject(parent, None)
+ if protection is not None:
+ permissions = permissions | (protection.authenticated_granted or set())
+ return permissions
def grant_role(self, role_id, principal_ids):
registry = get_current_registry()
@@ -146,24 +156,43 @@
result |= role.permissions or set()
return result
+ def get_granted_roles(self):
+ roles = set(self._principals_by_role.keys())
+ if self.inherit_parent_roles:
+ for parent in lineage(self):
+ if parent in (self, self.__parent__):
+ continue
+ protection = IProtectedObject(parent, None)
+ if protection is not None:
+ roles = roles | protection.get_granted_roles()
+ return roles
+
@request_property(key=None)
def __acl__(self):
# always grant all permissions to system manager
result = [(Allow, 'system:admin', ALL_PERMISSIONS)]
- # grant permission to everyone and authenticated
- if self.everyone_permissions:
- result.append((Allow, Everyone, self.everyone_permissions))
- if self.authenticated_permissions:
- result.append((Allow, Authenticated, self.authenticated_permissions))
# grant access to all roles permissions
- for role_id in self._principals_by_role.keys():
+ for role_id in self.get_granted_roles():
role = query_utility(IRole, role_id)
if role is not None:
result.append((Allow, 'role:{0}'.format(role_id), role.permissions))
+ # grant permission to everyone and authenticated
+ permissions = self.get_everyone_denied()
+ if permissions:
+ result.append((Deny, Everyone, permissions))
+ permissions = self.get_authenticated_denied()
+ if permissions:
+ result.append((Deny, Authenticated, permissions))
+ permissions = self.get_authenticated_granted()
+ if permissions:
+ result.append((Allow, Authenticated, permissions))
+ permissions = self.get_everyone_granted()
+ if permissions:
+ result.append((Allow, Everyone, permissions))
# stop inheritance if required
if not self.inherit_parent_security:
result.append(DENY_ALL)
- logger.debug('ACL = {0}'.format(str(result)))
+ logger.debug('ACL({0!r}) = {1}'.format(self.__parent__, str(result)))
return result