I made yesterday some checkins on the Zope-2.7 branch, which didn't appear on the zope-checkins list.

FYI they're below. I'm porting them to trunk right now.

Florent

Index: doc/CHANGES.txt
===================================================================
RCS file: /cvs-repository/Zope/doc/Attic/CHANGES.txt,v
retrieving revision 1.625.2.309
diff -u -r1.625.2.309 CHANGES.txt
--- doc/CHANGES.txt     18 Mar 2005 15:31:01 -0000      1.625.2.309
+++ doc/CHANGES.txt     24 Mar 2005 18:32:34 -0000
@@ -11,6 +11,10 @@
       - DateIndex/DateRangeIndexes did not reset their __len__ attribute
         properly when cleared

+      - Fixed brain.getObject() to correctly traverse to an object even
+        if one of its parents is not accessible, to be close to what the
+        Publisher does.
+
   Zope 2.7.5 final (2005/03/20)

Bugs fixed
Index: lib/python/Products/ZCatalog/CatalogBrains.py
===================================================================
RCS file: /cvs-repository/Products/ZCatalog/Attic/CatalogBrains.py,v
retrieving revision 1.8.44.1
diff -u -r1.8.44.1 CatalogBrains.py
--- lib/python/Products/ZCatalog/CatalogBrains.py 23 Mar 2004 20:27:23 -0000 1.8.44.1
+++ lib/python/Products/ZCatalog/CatalogBrains.py 24 Mar 2005 18:32:35 -0000
@@ -42,12 +42,24 @@


def getObject(self, REQUEST=None):
"""Return the object for this record
-
+
Will return None if the object cannot be found via its cataloged path
(i.e., it was deleted or moved without recataloging), or if the user is
- not authorized to access an object along the path.
+ not authorized to access the object.
+
+ This method mimicks a subset of what publisher's traversal does,
+ so it allows access if the final object can be accessed even
+ if intermediate objects cannot.
"""
- return self.aq_parent.restrictedTraverse(self.getPath(), None)
+ path = self.getPath().split('/')
+ if not path:
+ return None
+ parent = self.aq_parent
+ if len(path) > 1:
+ parent = parent.unrestrictedTraverse('/'.join(path[:-1]), None)
+ if parent is None:
+ return None
+ return parent.restrictedTraverse(path[-1], None)


def getRID(self):
"""Return the record ID for this object."""
Index: lib/python/Products/ZCatalog/tests/testBrains.py
===================================================================
RCS file: /cvs-repository/Products/ZCatalog/tests/Attic/testBrains.py,v
retrieving revision 1.1.4.1
diff -u -r1.1.4.1 testBrains.py
--- lib/python/Products/ZCatalog/tests/testBrains.py 23 Mar 2004 20:27:23 -0000 1.1.4.1
+++ lib/python/Products/ZCatalog/tests/testBrains.py 24 Mar 2005 18:32:35 -0000
@@ -23,15 +23,17 @@
"""Happy content"""
def __init__(self, id):
self.id = id
+ def check(self):
+ pass


 class Secret(Happy):
     """Object that raises Unauthorized when accessed"""
-    def __of__(self, parent):
+    def check(self):
         raise Unauthorized

 class Conflicter(Happy):
     """Object that raises ConflictError when accessed"""
-    def __of__(self, parent):
+    def check(self):
         raise ConflictError

class DummyRequest(Acquisition.Implicit):
@@ -50,10 +52,20 @@
'/conflicter':Conflicter('conflicter')}
_paths = _objs.keys() + ['/zonked']
_paths.sort()
-
+
+ # This is sooooo ugly
+
+ def unrestrictedTraverse(self, path, default=None):
+ assert path == '' # for these tests...
+ return self
+
def restrictedTraverse(self, path, default=_marker):
+ if not path.startswith('/'):
+ path = '/'+path
try:
- return self._objs[path].__of__(self)
+ ob = self._objs[path].__of__(self)
+ ob.check()
+ return ob
except (KeyError, Unauthorized):
if default is not _marker:
return default
Index: lib/python/Products/ZCatalog/tests/testCatalog.py
===================================================================
RCS file: /cvs-repository/Products/ZCatalog/tests/Attic/testCatalog.py,v
retrieving revision 1.22.12.6
diff -u -r1.22.12.6 testCatalog.py
--- lib/python/Products/ZCatalog/tests/testCatalog.py 18 May 2004 14:48:49 -0000 1.22.12.6
+++ lib/python/Products/ZCatalog/tests/testCatalog.py 24 Mar 2005 18:32:35 -0000
@@ -26,6 +26,10 @@
from Products.ZCatalog import ZCatalog,Vocabulary
from Products.ZCatalog.Catalog import Catalog, CatalogError
import ExtensionClass
+from OFS.Folder import Folder as OFS_Folder
+from AccessControl.SecurityManagement import setSecurityManager
+from AccessControl.SecurityManagement import noSecurityManager
+from AccessControl import Unauthorized


 from Products.PluginIndexes.FieldIndex.FieldIndex import FieldIndex
 from Products.PluginIndexes.TextIndex.TextIndex import TextIndex
@@ -60,18 +64,6 @@
 # XXX What's this mean?  What does this comment apply to?

################################################################################

-# XXX These imports and class don't appear to be needed?
-## from AccessControl.SecurityManagement import newSecurityManager
-## from AccessControl.SecurityManagement import noSecurityManager
-
-## class DummyUser:
-
-##     def __init__( self, name ):
-##         self._name = name
-
-##     def getUserName( self ):
-##         return self._name
-
 def sort(iterable):
     L = list(iterable)
     L.sort()
@@ -584,7 +576,82 @@
         expected.sort()
         expected = [rid for sortkey, rid, getitem in expected]
         self.assertEqual(merged_rids, expected)
-
+
+
+class PickySecurityManager:
+    def __init__(self, badnames=[]):
+        self.badnames = badnames
+    def validateValue(self, value):
+        return 1
+    def validate(self, accessed, container, name, value):
+        if name not in self.badnames:
+            return 1
+        raise Unauthorized(name)
+
+class Folder(OFS_Folder):
+    def __init__(self, id):
+        self._setId(id)
+        OFS_Folder.__init__(self)
+
+class TestZCatalogGetObject(unittest.TestCase):
+    # Test what objects are returned by brain.getObject()
+
+    def setUp(self):
+        catalog = ZCatalog.ZCatalog('catalog')
+        catalog.addIndex('id', 'FieldIndex')
+        root = Folder('')
+        root.getPhysicalRoot = lambda: root
+        self.root = root
+        self.root.catalog = catalog
+
+    def tearDown(self):
+        noSecurityManager()
+
+    def test_getObject_found(self):
+        # Check normal traversal
+        root = self.root
+        catalog = root.catalog
+        root.ob = Folder('ob')
+        catalog.catalog_object(root.ob)
+        brain = catalog.searchResults()[0]
+        self.assertEqual(brain.getPath(), '/ob')
+        self.assertEqual(brain.getObject().getId(), 'ob')
+
+    def test_getObject_missing(self):
+        # Check that if the object is missing None is returned
+        root = self.root
+        catalog = root.catalog
+        root.ob = Folder('ob')
+        catalog.catalog_object(root.ob)
+        brain = catalog.searchResults()[0]
+        del root.ob
+        self.assertEqual(brain.getObject(), None)
+
+    def test_getObject_restricted(self):
+        # Check that if the object's security does not allow traversal,
+        # None is returned
+        root = self.root
+        catalog = root.catalog
+        root.fold = Folder('fold')
+        root.fold.ob = Folder('ob')
+        catalog.catalog_object(root.fold.ob)
+        brain = catalog.searchResults()[0]
+        # allow all accesses
+        pickySecurityManager = PickySecurityManager()
+        setSecurityManager(pickySecurityManager)
+        self.assertEqual(brain.getObject().getId(), 'ob')
+        # disallow just 'ob' access
+        pickySecurityManager = PickySecurityManager(['ob'])
+        setSecurityManager(pickySecurityManager)
+        self.assertEqual(brain.getObject(), None)
+        # disallow just 'fold' access
+        pickySecurityManager = PickySecurityManager(['fold'])
+        setSecurityManager(pickySecurityManager)
+        ob = brain.getObject()
+        self.failIf(ob is None)
+        self.assertEqual(ob.getId(), 'ob')
+
+
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest( unittest.makeSuite( TestAddDelColumn ) )
@@ -593,6 +660,7 @@
     suite.addTest( unittest.makeSuite( TestCatalogObject ) )
     suite.addTest( unittest.makeSuite( TestRS ) )
     suite.addTest( unittest.makeSuite( TestMerge ) )
+    suite.addTest( unittest.makeSuite( TestZCatalogGetObject ) )
     return suite

 if __name__ == '__main__':


--
Florent Guillaume, Nuxeo (Paris, France) CTO, Director of R&D
+33 1 40 33 71 59 http://nuxeo.com [EMAIL PROTECTED]
_______________________________________________
Zope-Dev maillist - Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
** No cross posts or HTML encoding! **
(Related lists - http://mail.zope.org/mailman/listinfo/zope-announce
http://mail.zope.org/mailman/listinfo/zope )

Reply via email to