[Zope3-checkins] CVS: Zope3/src/zope/security - checker.py:1.25

Steve Alexander steve@cat-box.net
Thu, 29 May 2003 11:51:50 -0400


Update of /cvs-repository/Zope3/src/zope/security
In directory cvs.zope.org:/tmp/cvs-serv6524/src/zope/security

Modified Files:
	checker.py 
Log Message:
Added a DecoratedChecker.


=== Zope3/src/zope/security/checker.py 1.24 => 1.25 ===
--- Zope3/src/zope/security/checker.py:1.24	Wed May 28 08:55:28 2003
+++ Zope3/src/zope/security/checker.py	Thu May 29 11:51:19 2003
@@ -170,6 +170,111 @@
 
         return Proxy(value, checker)
 
+
+class DecoratedChecker(TrustedCheckerBase):
+    """A checker using further permissions relative to an original checker.
+    """
+
+    implements(IChecker)
+
+    def __init__(self, original_checker, permission_func,
+                 setattr_permission_func=lambda name: None
+                 ):
+        """Create a checker
+
+        A dictionary or a callable must be provided for computing permissions
+        for names. The callable will be called with attribute names and must
+        return a permission id, None, or the special marker, CheckerPublic.  If
+        None is returned, then access to the name is decided by
+        original_checker. If CheckerPublic is returned, then access will be
+        granted without checking a permission.
+
+        An optional setattr permission function or dictionary may be
+        provided for checking set attribute access.
+        """
+        self._original_checker = original_checker
+
+        if type(permission_func) is dict:
+            permission_func = permission_func.get
+        self._permission_func = permission_func
+
+        if type(setattr_permission_func) is dict:
+            setattr_permission_func = setattr_permission_func.get
+        self._setattr_permission_func = setattr_permission_func
+
+    def permission_id(self, name):
+        permission = self._permission_func(name)
+        if permission is None:
+            permission = self._original_checker.permission_id(name)
+        return permission
+
+    def setattr_permission_id(self, name):
+        permission = self._setattr_permission_func(name)
+        if permission is None:
+            permission = self._original_checker.setattr_permission_id(name)
+        return permission
+
+    def check(self, object, name):
+        permission = self._permission_func(name)
+        if permission is not None:
+            if permission is CheckerPublic:
+                return # Public
+            manager = getSecurityManager()
+            if manager.checkPermission(permission, object):
+                return
+            else:
+                __traceback_supplement__ = (TracebackSupplement, object)
+                raise Unauthorized(name=name)
+        else:
+            # let the original checker decide
+            self._original_checker.check(object, name)
+            return
+
+    def check_getattr(self, object, name):
+        permission = self._permission_func(name)
+        if permission is not None:
+            if permission is CheckerPublic:
+                return # Public
+            manager = getSecurityManager()
+            if manager.checkPermission(permission, object):
+                return
+            else:
+                __traceback_supplement__ = (TracebackSupplement, object)
+                raise Unauthorized(name=name)
+        else:
+            # let the original checker decide
+            self._original_checker.check_getattr(object, name)
+            return
+
+    def check_setattr(self, object, name):
+        permission = self._setattr_permission_func(name)
+        if permission is not None:
+            if permission is CheckerPublic:
+                return # Public
+            manager = getSecurityManager()
+            if manager.checkPermission(permission, object):
+                return
+            else:
+                __traceback_supplement__ = (TracebackSupplement, object)
+                raise Unauthorized(name=name)
+        else:
+            # let the original checker decide
+            self._original_checker.check_setattr(object, name)
+            return
+
+    def proxy(self, value):
+        'See IChecker'
+        # Now we need to create a proxy
+
+        checker = getattr(value, '__Security_checker__', None)
+        if checker is None:
+            checker = selectChecker(value)
+            if checker is None:
+                return value
+
+        return Proxy(value, checker)
+
+
 class CheckerLoggingMixin:
     """Debugging mixin for Checker.
 
@@ -232,7 +337,8 @@
 if WATCH_CHECKERS:
     class Checker(CheckerLoggingMixin, Checker):
         pass
-
+    class DecoratedChecker(CheckerLoggingMixin, DecoratedChecker):
+        pass
 
 # Helper class for __traceback_supplement__
 class TracebackSupplement: