[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/ Implement untrusted traveral for page templates.

Fred L. Drake, Jr. fred at zope.com
Fri Jul 23 12:16:30 EDT 2004


Log message for revision 26704:
  Implement untrusted traveral for page templates.
  
  - Use separate subclasses of PathExpr to implement path expressions
    for trusted and untrusted templates.  The untrusted class uses a new
    traversal function that makes sure the result at each step is
    wrapped in the appropriate security proxy.
  
  - Add missing security declarations in a couple of tests.
  


Changed:
  U   Zope3/trunk/src/zope/app/pagetemplate/engine.py
  U   Zope3/trunk/src/zope/app/traversing/ftests/test_vhosting.py
  U   Zope3/trunk/src/zope/app/zptpage/tests/test_zptpage.py


-=-
Modified: Zope3/trunk/src/zope/app/pagetemplate/engine.py
===================================================================
--- Zope3/trunk/src/zope/app/pagetemplate/engine.py	2004-07-23 14:50:20 UTC (rev 26703)
+++ Zope3/trunk/src/zope/app/pagetemplate/engine.py	2004-07-23 16:16:30 UTC (rev 26704)
@@ -36,19 +36,26 @@
 
 from zope.app import zapi
 from zope.app.i18n import ZopeMessageIDFactory as _
-from zope.app.traversing.adapters import Traverser
+from zope.app.traversing.adapters import Traverser, traversePathElement
 from zope.app.traversing.interfaces import IPathAdapter, ITraversable
 
 class InlineCodeError(Exception):
     pass
 
+
 def zopeTraverser(object, path_items, econtext):
     """Traverses a sequence of names, first trying attributes then items.
     """
-    traverser = Traverser(object)
-    return traverser.traverse(path_items,
-                              request=getattr(econtext, 'request', None))
+    request = getattr(econtext, 'request', None)
+    path_items = list(path_items)
+    path_items.reverse()
 
+    while path_items:
+        name = path_items.pop()
+        object = traversePathElement(object, name, path_items,
+                                     request=request)
+        object = ProxyFactory(object)
+    return object
 
 class ZopePathExpr(PathExpr):
 
@@ -56,6 +63,20 @@
         super(ZopePathExpr, self).__init__(name, expr, engine, zopeTraverser)
 
 
+def trustedZopeTraverser(object, path_items, econtext):
+    """Traverses a sequence of names, first trying attributes then items.
+    """
+    traverser = Traverser(object)
+    return traverser.traverse(path_items,
+                              request=getattr(econtext, 'request', None))
+
+class TrustedZopePathExpr(PathExpr):
+
+    def __init__(self, name, expr, engine):
+        super(TrustedZopePathExpr, self).__init__(name, expr, engine,
+                                                  trustedZopeTraverser)
+
+
 # Create a version of the restricted built-ins that uses a safe
 # version of getattr() that wraps values in security proxies where
 # appropriate:
@@ -196,6 +217,7 @@
             self.namespaces[name] = namespace
         return namespace
 
+
 class ZopeEngine(ExpressionEngine):
     """Untrusted expression engine.
 
@@ -237,6 +259,54 @@
       >>> type(r)
       <type 'zope.security._proxy._Proxy'>
 
+    General path expressions provide objects that are wrapped in
+    security proxies as well::
+
+      >>> from zope.app.container.sample import SampleContainer
+      >>> from zope.app.tests.placelesssetup import setUp, tearDown
+      >>> from zope.security.checker import NamesChecker, defineChecker
+
+      >>> class Container(SampleContainer):
+      ...     implements(ITraversable)
+      ...     def traverse(self, name, further_path):
+      ...         return self[name]
+
+      >>> setUp()
+      >>> defineChecker(Container, NamesChecker(['traverse']))
+      >>> d = engine.getBaseNames()
+      >>> foo = Container()
+      >>> foo.__name__ = 'foo'
+      >>> d['foo'] = ProxyFactory(foo)
+      >>> foo['bar'] = bar = Container()
+      >>> bar.__name__ = 'bar'
+      >>> bar.__parent__ = foo
+      >>> bar['baz'] = baz = Container()
+      >>> baz.__name__ = 'baz'
+      >>> baz.__parent__ = bar
+      >>> context = engine.getContext(d)
+
+      >>> o1 = context.evaluate('foo/bar')
+      >>> o1.__name__
+      'bar'
+      >>> type(o1)
+      <type 'zope.security._proxy._Proxy'>
+
+      >>> o2 = context.evaluate('foo/bar/baz')
+      >>> o2.__name__
+      'baz'
+      >>> type(o2)
+      <type 'zope.security._proxy._Proxy'>
+      >>> o3 = o2.__parent__
+      >>> type(o3)
+      <type 'zope.security._proxy._Proxy'>
+      >>> o1 == o3
+      True
+
+      >>> o1 is o2
+      False
+
+      >>> tearDown()
+
     """
 
     _create_context = ZopeContext
@@ -312,7 +382,7 @@
 def _Engine(engine=None):
     if engine is None:
         engine = ZopeEngine()
-    engine = _create_base_engine(engine)
+    engine = _create_base_engine(engine, ZopePathExpr)
     engine.registerType('python', ZopePythonExpr)
 
     # Using a proxy around sys.modules allows page templates to use
@@ -326,14 +396,14 @@
 def _TrustedEngine(engine=None):
     if engine is None:
         engine = TrustedZopeEngine()
-    engine = _create_base_engine(engine)
+    engine = _create_base_engine(engine, TrustedZopePathExpr)
     engine.registerType('python', PythonExpr)
     engine.registerBaseName('modules', TraversableModuleImporter())
     return engine
 
-def _create_base_engine(engine):
-    for pt in ZopePathExpr._default_type_names:
-        engine.registerType(pt, ZopePathExpr)
+def _create_base_engine(engine, pathtype):
+    for pt in pathtype._default_type_names:
+        engine.registerType(pt, pathtype)
     engine.registerType('string', StringExpr)
     engine.registerType('not', NotExpr)
     engine.registerType('defer', DeferExpr)

Modified: Zope3/trunk/src/zope/app/traversing/ftests/test_vhosting.py
===================================================================
--- Zope3/trunk/src/zope/app/traversing/ftests/test_vhosting.py	2004-07-23 14:50:20 UTC (rev 26703)
+++ Zope3/trunk/src/zope/app/traversing/ftests/test_vhosting.py	2004-07-23 16:16:30 UTC (rev 26704)
@@ -22,7 +22,7 @@
 from transaction import get_transaction
 from zope.app.publisher.browser.resource import Resource
 from zope.app.traversing.api import traverse
-from zope.security.checker import defineChecker, NoProxy
+from zope.security.checker import defineChecker, NamesChecker, NoProxy
 from zope.app.container.contained import Contained
 from zope.app.zptpage.zptpage import ZPTPage
 
@@ -125,6 +125,7 @@
 
     def test_resources(self):
         ztapi.browserResource('quux', Resource)
+        defineChecker(Resource, NamesChecker(['__call__']))
         self.addPage('/foo/bar/pt',
                      u'<span tal:replace="context/++resource++quux" />')
         self.verify('/foo/bar/pt', 'http://localhost/@@/quux\n')

Modified: Zope3/trunk/src/zope/app/zptpage/tests/test_zptpage.py
===================================================================
--- Zope3/trunk/src/zope/app/zptpage/tests/test_zptpage.py	2004-07-23 14:50:20 UTC (rev 26703)
+++ Zope3/trunk/src/zope/app/zptpage/tests/test_zptpage.py	2004-07-23 16:16:30 UTC (rev 26704)
@@ -110,6 +110,8 @@
                     return 'None'
                 return name
 
+        defineChecker(AU, NamesChecker(['__str__']))
+
         from zope.app.traversing.namespace import view
         ztapi.provideNamespaceHandler('view', view)
         ztapi.browserView(IZPTPage, 'name', AU)



More information about the Zope3-Checkins mailing list