src/pyams_security/security.py
changeset 44 b999bd4dd461
parent 42 07229ac2497b
child 84 2d928c3189c0
--- 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