[Checkins] SVN: Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/ Use customised unrestrictedTraverse for the portal root
Matthew Wilkes
matthew at matthewwilkes.co.uk
Mon Aug 17 08:06:02 EDT 2009
Log message for revision 102872:
Use customised unrestrictedTraverse for the portal root
Changed:
U Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/PortalObject.py
U Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/Skinnable.py
-=-
Modified: Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/PortalObject.py
===================================================================
--- Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/PortalObject.py 2009-08-17 12:04:54 UTC (rev 102871)
+++ Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/PortalObject.py 2009-08-17 12:06:02 UTC (rev 102872)
@@ -55,6 +55,8 @@
(ReviewPortalContent, ()),
)
+ unrestrictedTraverse = SkinnableObjectManager.unrestrictedTraverse
+
def __init__(self, id, title='', description=''):
super(PortalObjectBase, self).__init__(id, title, description)
components = PersistentComponents('++etc++site')
Modified: Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/Skinnable.py
===================================================================
--- Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/Skinnable.py 2009-08-17 12:04:54 UTC (rev 102871)
+++ Products.CMFCore/branches/matthewwilkes-traversalprecedence/Products/CMFCore/Skinnable.py 2009-08-17 12:06:02 UTC (rev 102872)
@@ -23,12 +23,28 @@
from warnings import warn
from AccessControl.SecurityInfo import ClassSecurityInfo
+from AccessControl.ZopeGuards import guard, guarded_getattr
+from AccessControl.SecurityManagement import getSecurityManager
+from AccessControl.unauthorized import Unauthorized
+from Acquisition import Acquired
+from Acquisition import aq_acquire
from Acquisition import aq_base
+from Acquisition import aq_inner
+from Acquisition import aq_parent
+from OFS.interfaces import ITraversable
+from zExceptions import NotFound
+
+from Acquisition import aq_base
from App.class_init import InitializeClass
from OFS.ObjectManager import ObjectManager
from ZODB.POSException import ConflictError
from zope.interface import implements
-
+from zope.traversing.interfaces import TraversalError
+from zope.traversing.namespace import namespaceLookup
+from zope.traversing.namespace import nsParse
+from Acquisition.interfaces import IAcquirer
+from zope.interface import Interface
+from zope.component import queryMultiAdapter
from interfaces import ISkinnableObjectManager
logger = logging.getLogger('CMFCore.Skinnable')
@@ -217,4 +233,197 @@
SKINDATA[tid] = sd
return superCheckId(self, id, allow_dup)
+ def unrestrictedTraverse(self, path, default=_MARKER, restricted=False):
+ """Lookup an object by path.
+
+ path -- The path to the object. May be a sequence of strings or a slash
+ separated string. If the path begins with an empty path element
+ (i.e., an empty string or a slash) then the lookup is performed
+ from the application root. Otherwise, the lookup is relative to
+ self. Two dots (..) as a path element indicates an upward traversal
+ to the acquisition parent.
+
+ default -- If provided, this is the value returned if the path cannot
+ be traversed for any reason (i.e., no object exists at that path or
+ the object is inaccessible).
+
+ restricted -- If false (default) then no security checking is performed.
+ If true, then all of the objects along the path are validated with
+ the security machinery. Usually invoked using restrictedTraverse().
+ """
+ from webdav.NullResource import NullResource
+ if not path:
+ return self
+
+ if isinstance(path, str):
+ # Unicode paths are not allowed
+ path = path.split('/')
+ else:
+ path = list(path)
+
+ REQUEST = {'TraversalRequestNameStack': path}
+ path.reverse()
+ path_pop = path.pop
+
+ if len(path) > 1 and not path[0]:
+ # Remove trailing slash
+ path_pop(0)
+
+ if restricted:
+ validate = getSecurityManager().validate
+
+ if not path[-1]:
+ # If the path starts with an empty string, go to the root first.
+ path_pop()
+ obj = self.getPhysicalRoot()
+ if restricted:
+ validate(None, None, None, obj) # may raise Unauthorized
+ else:
+ obj = self
+
+ resource = _MARKER
+ try:
+ while path:
+ name = path_pop()
+ __traceback_info__ = path, name
+
+ if name[0] == '_':
+ # Never allowed in a URL.
+ raise NotFound, name
+
+ if name == '..':
+ next = aq_parent(obj)
+ if next is not None:
+ if restricted and not validate(obj, obj, name, next):
+ raise Unauthorized(name)
+ obj = next
+ continue
+
+ bobo_traverse = getattr(obj, '__bobo_traverse__', None)
+ try:
+ if name and name[:1] in '@+' and name != '+' and nsParse(name)[1]:
+ # Process URI segment parameters.
+ ns, nm = nsParse(name)
+ try:
+ next = namespaceLookup(
+ ns, nm, obj, aq_acquire(self, 'REQUEST'))
+ if IAcquirer.providedBy(next):
+ next = next.__of__(obj)
+ if restricted and not validate(
+ obj, obj, name, next):
+ raise Unauthorized(name)
+ except TraversalError:
+ raise AttributeError(name)
+
+ elif bobo_traverse is not None:
+ next = bobo_traverse(REQUEST, name)
+ if restricted:
+ if aq_base(next) is not next:
+ # The object is wrapped, so the acquisition
+ # context is the container.
+ container = aq_parent(aq_inner(next))
+ elif getattr(next, 'im_self', None) is not None:
+ # Bound method, the bound instance
+ # is the container
+ container = next.im_self
+ elif getattr(aq_base(obj), name, _MARKER) is next:
+ # Unwrapped direct attribute of the object so
+ # object is the container
+ container = obj
+ else:
+ # Can't determine container
+ container = None
+ # If next is a simple unwrapped property, its
+ # parentage is indeterminate, but it may have
+ # been acquired safely. In this case validate
+ # will raise an error, and we can explicitly
+ # check that our value was acquired safely.
+ try:
+ ok = validate(obj, container, name, next)
+ except Unauthorized:
+ ok = False
+ if not ok:
+ if (container is not None or
+ guarded_getattr(obj, name, _MARKER)
+ is not next):
+ raise Unauthorized(name)
+ else:
+ next = None
+ try:
+ next = obj.__getattribute__(name)
+ except AttributeError:
+ # this is not a direct object
+ pass
+ else:
+ try:
+ next = next.aq_base.__of__(obj)
+ except (AttributeError, TypeError):
+ pass # We can't aq wrap whatever this is
+ if restricted:
+ guard(obj, next)
+ if next is None:
+ try:
+ next = obj[name]
+ # The item lookup may return a NullResource,
+ # if this is the case we save it and return it
+ # if all other lookups fail.
+ if isinstance(next, NullResource):
+ resource = next
+ raise KeyError(name)
+ except AttributeError:
+ # Raise NotFound for easier debugging
+ # instead of AttributeError: __getitem__
+ raise NotFound(name)
+ if restricted and not validate(
+ obj, obj, None, next):
+ raise Unauthorized(name)
+ if next is None:
+ if restricted:
+ next = guarded_getattr(obj, name, _MARKER)
+ else:
+ next = getattr(obj, name, _MARKER)
+
+
+ except (AttributeError, NotFound, KeyError), e:
+ # Try to look for a view
+ next = queryMultiAdapter((obj, aq_acquire(self, 'REQUEST')),
+ Interface, name)
+
+ if next is not None:
+ if IAcquirer.providedBy(next):
+ next = next.__of__(obj)
+ if restricted and not validate(obj, obj, name, next):
+ raise Unauthorized(name)
+ elif bobo_traverse is not None:
+ # Attribute lookup should not be done after
+ # __bobo_traverse__:
+ raise e
+ else:
+ # No view, try acquired attributes
+ try:
+ if restricted:
+ next = guarded_getattr(obj, name, _MARKER)
+ else:
+ next = getattr(obj, name, _MARKER)
+ except AttributeError:
+ raise e
+ if next is _MARKER:
+ # If we have a NullResource from earlier use it.
+ next = resource
+ if next is _MARKER:
+ # Nothing found re-raise error
+ raise e
+
+ obj = next
+
+ return obj
+
+ except ConflictError:
+ raise
+ except:
+ if default is not _MARKER:
+ return default
+ else:
+ raise
+
InitializeClass(SkinnableObjectManager)
More information about the Checkins
mailing list