[Zope-Checkins] CVS: Zope3/lib/python/Zope/Security - Checker.py:1.1.2.6 Proxy.py:1.1.2.14 CheckerRegistry.py:NONE

Jim Fulton jim@zope.com
Mon, 22 Apr 2002 18:39:51 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Security
In directory cvs.zope.org:/tmp/cvs-serv556/lib/python/Zope/Security

Modified Files:
      Tag: SecurityProxy-branch
	Checker.py Proxy.py 
Removed Files:
      Tag: SecurityProxy-branch
	CheckerRegistry.py 
Log Message:
Refactored the Zope.Security package to move the code from the
CheckerRegistry and Proxy modules into the checker module, as the code
is tightly coupled and the separation was causing circular imports.

It's not clear what the role of the Proxy module should be.

Also cleaned up the dependencies between the Proxy factory and the
registry and merged the check utility function with the check Checker
method. 



=== Zope3/lib/python/Zope/Security/Checker.py 1.1.2.5 => 1.1.2.6 ===
 from Zope.Exceptions import Unauthorized, Forbidden, DuplicationError
+from Interface.IInterface import IInterface
+from _Proxy import _Proxy
+from types import InstanceType, ClassType, FunctionType, MethodType, ModuleType
+from ISecurityProxyFactory import ISecurityProxyFactory
 # XXX SecurityManagement needs to move out of App
 from Zope.App.Security.SecurityManagement import getSecurityManager
 
-from Interface.IInterface import IInterface
-
 # Marker for public attributes
 CheckerPublic = object()
 
+def Proxy(object, checker=None):
+    """Factory function that creats a proxy for an object
+
+    The proxy checker is looked up if not provided.
+    """
+    
+    if checker is None:        
+        checker = selectChecker(object)
+        if checker is None:
+            return object
+
+    else:
+        # Maybe someone passed us a proxy and a checker
+        if type(object) is _Proxy:
+            # XXX should we keep the existing proxy or create a new one.
+            return object
+
+    return _Proxy(object, checker)
+
+Proxy.__implements__ = ISecurityProxyFactory
+
 class Checker:
 
     __implements__ =  IChecker
@@ -37,7 +60,7 @@
 
     def check_getattr(self, object, name):
         'See Zope.Security.IChecker.IChecker'
-        check(self.__permission_func, name, object)
+        self.check(object, name)
 
     def check_setattr(self, object, name):
         'See Zope.Security.IChecker.IChecker'
@@ -46,7 +69,19 @@
 
     def check(self, object, name):
         'See Zope.Security.IChecker.IChecker'
-        check(self.__permission_func, name, object)
+
+        # We have the information we need already
+        permission = self.__permission_func(name)
+        if permission:
+            if permission is CheckerPublic:
+                return # Public
+            manager = getSecurityManager()
+            if manager.checkPermission(permission, object):
+                return
+            else:
+                raise Unauthorized(name=name)
+
+        raise Forbidden(name)
 
     def proxy(self, value):
         'See Zope.Security.IChecker.IChecker'
@@ -56,22 +91,6 @@
     #
     ############################################################
 
-
-def check(permission_func, name, object):
-    # We have the information we need already
-    permission = permission_func(name)
-    if permission:
-        if permission is CheckerPublic:
-            return # Public
-        manager = getSecurityManager()
-        if manager.checkPermission(permission, object):
-            return
-        else:
-            raise Unauthorized(name=name)
-
-    raise Forbidden(name)
-
-
 def NamesChecker(names, permission_id=CheckerPublic, **__kw__):
     """Return a checker that grants access to a set of names.
 
@@ -135,8 +154,102 @@
 
     return Checker(check)
 
-# Import this last due to module dependencies
-from Proxy import Proxy
 
+def selectChecker(object):
+    """Get a checker for the given object
+
+    The appropriate checker is returned or None is returned. If the
+    return value is None, then object should not be wrapped in a proxy.
+    """
+    checker = _getChecker(type(object), _defaultChecker)
+    if checker is NoProxy:
+        return None
+
+    while not isinstance(checker, Checker):
+        checker = checker(object)
+        if checker is NoProxy:
+            return None
+    
+    return checker
+    
+
+def defineChecker(type_, checker):
+    """Define a checker for a given type of object
+
+    The checker can be a Checker, or 
+    """
+    if type_ in _checkers:
+        raise DuplicationError(type_)
+    _checkers[type_] = checker
+
+
+NoProxy = object()
+
+# _checkers is a mapping.
+#
+#  - Keys are types
+#
+#  - Values are
+#
+#    o None => rock
+#    o a Checker
+#    o a function returning None or a Checker
+#
+_checkers = {}
+_getChecker = _checkers.get
+
+_defaultChecker = Checker({}.get)
+
+def _instanceChecker(inst):
+    checker = _checkers.get(inst.__class__, _defaultChecker)
+    if checker is _defaultChecker and isinstance(inst, Exception):
+        return NoProxy # XXX we should be more careful
+    return checker
+
+def _classChecker(class_):
+    checker = _checkers.get(class_, _typeChecker)
+    if checker is _typeChecker and issubclass(class_, Exception):
+        return NoProxy # XXX we should be more careful
+
+    return checker
+
+_callableChecker = NamesChecker(['__str__', '__repr__', '__hash__',
+                                 '__call__'])
+_typeChecker = NamesChecker(['__str__', '__repr__', '__hash__'])
+
+def _moduleChecker(module):
+    return _checkers.get(module, _typeChecker)
+
+
+_default_checkers = {
+    dict: NamesChecker(['__getitem__', 'get', 'has_key', '__len__',
+                         'keys', 'values', 'items']),
+    list: NamesChecker(['__getitem__', 'index', 'count', '__len__']),
+    # YAGNI: () a rock
+    tuple: NamesChecker(['__getitem__', '__len__']),
+    int: NoProxy,
+    float: NoProxy,
+    long: NoProxy,
+    complex: NoProxy,
+    type(None): NoProxy,
+    str: NoProxy,
+    unicode: NoProxy,
+    InstanceType: _instanceChecker,
+    _Proxy: NoProxy,
+    ClassType: _classChecker,
+    FunctionType: _callableChecker,
+    MethodType: _callableChecker,
+    type: _typeChecker,
+    ModuleType: _moduleChecker,
+    # XXX bool
+    }
+
+
+def _clear():
+    _checkers.clear()
+    _checkers.update(_default_checkers)
 
+_clear()
 
+from Zope.Testing.CleanUp import addCleanUp
+addCleanUp(_clear)


=== Zope3/lib/python/Zope/Security/Proxy.py 1.1.2.13 => 1.1.2.14 ===
 """
 
-from ISecurityProxyFactory import ISecurityProxyFactory
-from _Proxy import _Proxy
-from Zope.Exceptions import DuplicationError
+from Checker import Proxy
 
-def Proxy(object, checker=None):
-    if checker is None:
-        checker = getChecker(type(object), _defaultChecker)
-        if checker is NoProxy:
-            return object
-
-        if not isinstance(checker, Checker):
-            checker = checker(object)
-            if checker is NoProxy:
-                return object
-
-    else:
-        # Maybe someone passed us a proxy and a checker
-        if type(object) is _Proxy:
-            # XXX should we keep the existing proxy or create a new one.
-            return object
-
-    return _Proxy(object, checker)
-
-Proxy.__implements__ = ISecurityProxyFactory
-
-from Checker import Checker
-_defaultChecker = Checker({}.get)
-
-from CheckerRegistry import getChecker, NoProxy

=== Removed File Zope3/lib/python/Zope/Security/CheckerRegistry.py ===