[Zope3-checkins] SVN: Zope3/trunk/src/zope/security/ No longer re-proxying objects that provide an explicit __Security_checker__.

Garrett Smith garrett at mojave-corp.com
Tue Mar 15 15:17:08 EST 2005


Log message for revision 29482:
  No longer re-proxying objects that provide an explicit __Security_checker__.

Changed:
  U   Zope3/trunk/src/zope/security/_zope_security_checker.c
  U   Zope3/trunk/src/zope/security/checker.py
  U   Zope3/trunk/src/zope/security/tests/test_checker.py

-=-
Modified: Zope3/trunk/src/zope/security/_zope_security_checker.c
===================================================================
--- Zope3/trunk/src/zope/security/_zope_security_checker.c	2005-03-15 18:05:14 UTC (rev 29481)
+++ Zope3/trunk/src/zope/security/_zope_security_checker.c	2005-03-15 20:17:08 UTC (rev 29482)
@@ -90,7 +90,7 @@
       Py_DECREF(r);
       if (i < 0)
         return -1;
-      if (i) 
+      if (i)
         return 0;
 /*             else: */
 /*                 __traceback_supplement__ = (TracebackSupplement, object) */
@@ -133,7 +133,7 @@
     }
 
 
-  operator = (PyString_Check(name) 
+  operator = (PyString_Check(name)
               && PyString_AS_STRING(name)[0] == '_'
               && PyString_AS_STRING(name)[1] == '_');
 
@@ -150,10 +150,10 @@
 /*         if name != '__iter__' or hasattr(object, name): */
 /*             __traceback_supplement__ = (TracebackSupplement, object) */
 /*             raise ForbiddenAttribute, (name, object) */
-      
+
       if (strcmp("__iter__", PyString_AS_STRING(name)) == 0
           && ! PyObject_HasAttr(object, name))
-        /* We want an attr error if we're asked for __iter__ and we don't 
+        /* We want an attr error if we're asked for __iter__ and we don't
            have it. We'll get one by allowing the access. */
         return 0;
     }
@@ -214,7 +214,7 @@
       Py_INCREF(Py_None);
       return Py_None;
     }
-  
+
 /*         __traceback_supplement__ = (TracebackSupplement, object) */
 /*         raise ForbiddenAttribute, (name, object) */
   args = Py_BuildValue("OO", name, object);
@@ -235,6 +235,15 @@
 Checker_proxy(Checker *self, PyObject *value)
 {
   PyObject *checker, *r;
+
+/*        if type(value) is Proxy: */
+/*            return value */
+  if ((PyObject*)(value->ob_type) == Proxy)
+    {
+      Py_INCREF(value);
+      return value;
+    }
+
 /*         checker = getattr(value, '__Security_checker__', None) */
   checker = PyObject_GetAttr(value, str___Security_checker__);
 /*         if checker is None: */
@@ -267,10 +276,10 @@
           PyErr_SetObject(PyExc_ValueError, errv);
           Py_DECREF(errv);
         }
-      
+
       return NULL;
     }
-    
+
   r = PyObject_CallFunctionObjArgs(Proxy, value, checker, NULL);
   Py_DECREF(checker);
   return r;
@@ -282,7 +291,7 @@
 static struct PyMethodDef Checker_methods[] = {
   {"permission_id", (PyCFunction)Checker_permission_id, METH_O,
    "permission_id(name) -- Return the permission neded to get the name"},
-  {"setattr_permission_id", (PyCFunction)Checker_setattr_permission_id, 
+  {"setattr_permission_id", (PyCFunction)Checker_setattr_permission_id,
    METH_O,
    "setattr_permission_id(name) -- Return the permission neded to set the name"
   },
@@ -320,7 +329,7 @@
     return -1;
   if (self->setperms != NULL && visit(self->setperms, arg) < 0)
     return -1;
-	
+
   return 0;
 }
 
@@ -330,10 +339,10 @@
   PyObject *getperms, *setperms=NULL;
   static char *kwlist[] = {"get_permissions", "set_permissions", NULL};
 
-  if (! PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!:Checker", kwlist, 
-                                    &PyDict_Type, &getperms, 
+  if (! PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!:Checker", kwlist,
+                                    &PyDict_Type, &getperms,
                                     &PyDict_Type, &setperms))
-    return -1; 
+    return -1;
 
   Py_INCREF(getperms);
   self->getperms = getperms;
@@ -372,11 +381,11 @@
 }
 
 static PyGetSetDef Checker_getset[] = {
-    {"get_permissions", 
+    {"get_permissions",
      (getter)Checker_get_get_permissions, NULL,
      "getattr name to permission dictionary",
      NULL},
-    {"set_permissions", 
+    {"set_permissions",
      (getter)Checker_get_set_permissions, NULL,
      "setattr name to permission dictionary",
      NULL},
@@ -421,7 +430,7 @@
         /* tp_setattro       */ (setattrofunc)0,
         /* tp_as_buffer      */ 0,
         /* tp_flags          */ Py_TPFLAGS_DEFAULT
-				| Py_TPFLAGS_BASETYPE 
+				| Py_TPFLAGS_BASETYPE
                           	| Py_TPFLAGS_HAVE_GC,
 	/* tp_doc            */ "Security checker",
         /* tp_traverse       */ (traverseproc)Checker_traverse,
@@ -455,7 +464,7 @@
 /*     return value is None, then object should not be wrapped in a proxy. */
 /*     """ */
 
-static char selectChecker_doc[] = 
+static char selectChecker_doc[] =
 "Get a checker for the given object\n"
 "\n"
 "The appropriate checker is returned or None is returned. If the\n"
@@ -485,7 +494,7 @@
 /*     if checker is _defaultChecker and isinstance(object, Exception): */
 /*         return None */
 
-  if (checker == _defaultChecker 
+  if (checker == _defaultChecker
       && PyObject_IsInstance(object, PyExc_Exception))
     {
       Py_INCREF(Py_None);
@@ -529,7 +538,7 @@
 #define PyMODINIT_FUNC void
 #endif
 PyMODINIT_FUNC
-init_zope_security_checker(void) 
+init_zope_security_checker(void)
 {
   PyObject* m;
 
@@ -548,7 +557,7 @@
   INIT_STRING(__Security_checker__);
   INIT_STRING(interaction);
 
-  if ((_checkers = PyDict_New()) == NULL) 
+  if ((_checkers = PyDict_New()) == NULL)
     return;
 
   NoProxy = PyObject_CallObject((PyObject*)&PyBaseObject_Type, NULL);
@@ -580,7 +589,7 @@
 
   m = Py_InitModule3("_zope_security_checker", module_methods,
                      "C optimizations for zope.security.checker");
-  
+
   if (m == NULL)
     return;
 
@@ -590,7 +599,7 @@
   EXPORT(NoProxy);
   EXPORT(_defaultChecker);
   EXPORT(_available_by_default);
-    
+
   Py_INCREF(&CheckerType);
   PyModule_AddObject(m, "Checker", (PyObject *)&CheckerType);
 }

Modified: Zope3/trunk/src/zope/security/checker.py
===================================================================
--- Zope3/trunk/src/zope/security/checker.py	2005-03-15 18:05:14 UTC (rev 29481)
+++ Zope3/trunk/src/zope/security/checker.py	2005-03-15 20:17:08 UTC (rev 29482)
@@ -193,6 +193,8 @@
 
     def proxy(self, value):
         'See IChecker'
+        if type(value) is Proxy:
+            return value
         checker = getattr(value, '__Security_checker__', None)
         if checker is None:
             checker = selectChecker(value)

Modified: Zope3/trunk/src/zope/security/tests/test_checker.py
===================================================================
--- Zope3/trunk/src/zope/security/tests/test_checker.py	2005-03-15 18:05:14 UTC (rev 29481)
+++ Zope3/trunk/src/zope/security/tests/test_checker.py	2005-03-15 20:17:08 UTC (rev 29482)
@@ -20,6 +20,7 @@
 from zope.interface.verify import verifyObject
 from zope.security.checker import Checker, NamesChecker, CheckerPublic
 from zope.testing.cleanup import CleanUp
+from zope.proxy import getProxiedObject
 from zope.security.interfaces import ISecurityPolicy
 from zope.security.interfaces import Forbidden, ForbiddenAttribute
 from zope.security.interfaces import Unauthorized
@@ -245,6 +246,24 @@
             #    proxy2 = checker.proxy(proxy)
             #    self.failUnless(proxy2 is proxy, [proxy, proxy2])
 
+    def testLayeredProxies(self):
+        """Tests that a Proxy will not be re-proxied."""
+        class Base:
+            __Security_checker__ = NamesChecker(['__Security_checker__'])
+        base = Base()
+        checker = Checker({})
+
+        # base is not proxied, so we expect a proxy
+        proxy1 = checker.proxy(base)
+        self.assert_(type(proxy1) is Proxy)
+        self.assert_(getProxiedObject(proxy1) is base)
+
+        # proxy is a proxy, so we don't expect to get another
+        proxy2 = checker.proxy(proxy1)
+        self.assert_(proxy2 is proxy1)
+        self.assert_(getProxiedObject(proxy2) is base)
+
+
     def testMultiChecker(self):
         from zope.interface import Interface
 
@@ -366,39 +385,39 @@
         proxy1 = ProxyFactory(obj, checker)
         proxy2 = ProxyFactory(proxy1, checker)
         self.assert_(proxy1 is proxy2)
-    
+
     def test_canWrite_canAccess(self):
         # the canWrite and canAccess functions are conveniences.  Often code
-        # wants to check if a certain option is open to a user before 
+        # wants to check if a certain option is open to a user before
         # presenting it.  If the code relies on a certain permission, the
         # Zope 3 goal of keeping knowledge of security assertions out of the
         # code and only in the zcml assertions is broken.  Instead, ask if the
-        # current user canAccess or canWrite some pertinent aspect of the 
+        # current user canAccess or canWrite some pertinent aspect of the
         # object.  canAccess is used for both read access on an attribute
         # and call access to methods.
-        
+
         # For example, consider this humble pair of class and object.
         class SomeClass(object):
             pass
         obj = SomeClass()
-        
+
         # We will establish a checker for the class.  This is the standard
         # name-based checker, and works by specifying two dicts, one for read
         # and one for write.  Each item in the dictionary should be an
-        # attribute name and the permission required to read or write it.  
-        
-        # For these tests, the SecurityPolicy defined at the top of this file 
+        # attribute name and the permission required to read or write it.
+
+        # For these tests, the SecurityPolicy defined at the top of this file
         # is in place.  It is a stub.  Normally, the security policy would
         # have knowledge of interactions and participants, and would determine
         # on the basis of the particpants and the object if a certain permission
-        # were authorized.  This stub simply says that the 'test_allowed' 
+        # were authorized.  This stub simply says that the 'test_allowed'
         # permission is authorized and nothing else is, for any object you pass
         # it.
-        
-        # Therefore, according to the checker created here, the current 
+
+        # Therefore, according to the checker created here, the current
         # 'interaction' (as stubbed out in the security policy) will be allowed
-        # to access and write foo, and access bar.  The interaction is 
-        # unauthorized for accessing baz and writing bar.  Any other access or 
+        # to access and write foo, and access bar.  The interaction is
+        # unauthorized for accessing baz and writing bar.  Any other access or
         # write is not merely unauthorized but forbidden--including write access
         # for baz.
         checker = Checker(
@@ -408,19 +427,19 @@
             {'foo':'test_allowed',
              'bar':'you_will_not_have_this_permission'})
         defineChecker(SomeClass, checker)
-        
+
         # so, our hapless interaction may write and access foo...
         self.assert_(canWrite(obj, 'foo'))
         self.assert_(canAccess(obj, 'foo'))
-        
+
         # ...may access, but not write, bar...
         self.assert_(not canWrite(obj, 'bar'))
         self.assert_(canAccess(obj, 'bar'))
-        
+
         # ...and may access baz.
         self.assert_(not canAccess(obj, 'baz'))
-        
-        # there are no security assertions for writing baz or accessing 
+
+        # there are no security assertions for writing baz or accessing
         # anything else, so these actually raise Forbidden.  The rationale
         # behind exposing the Forbidden exception is primarily that it is
         # usually indicative of programming or configuration errors.



More information about the Zope3-Checkins mailing list