[Zope3-checkins] SVN: Zope3/branches/dominik-locatableadapters/src/zope/app/ Assert location for all adapters that require any dedicated permission:

Dominik Huber dominik.huber at projekt01.ch
Thu Apr 14 10:06:47 EDT 2005


Log message for revision 29981:
  Assert location for all adapters that require any dedicated permission:
  
  If the permission attribute is used in the adapter directive and the permission is not zope.Public, then:
  
      If the adapter doesn't provide ILocation, we location 
      proxy it and set the parent.
  
      If the adapter does provide ILocation and it's __parent__
      is None, we set the __parent__. 
  
  TODO:
  I do not unterstand three tests inside zope.app.component.tests.test_directives.
  
  I've got pickable errors within zope.app.intid's
  functional tests. As a workaround I derive
  zope.app.keyreference.persistent.KeyReferenceToPersistent
  from location.
  
  I marked those issues with
  # TODO: I do not understand that test

Changed:
  U   Zope3/branches/dominik-locatableadapters/src/zope/app/component/metaconfigure.py
  U   Zope3/branches/dominik-locatableadapters/src/zope/app/component/tests/test_directives.py
  U   Zope3/branches/dominik-locatableadapters/src/zope/app/intid/__init__.py
  U   Zope3/branches/dominik-locatableadapters/src/zope/app/keyreference/persistent.py
  U   Zope3/branches/dominik-locatableadapters/src/zope/app/security/adapter.py

-=-
Modified: Zope3/branches/dominik-locatableadapters/src/zope/app/component/metaconfigure.py
===================================================================
--- Zope3/branches/dominik-locatableadapters/src/zope/app/component/metaconfigure.py	2005-04-14 11:31:07 UTC (rev 29980)
+++ Zope3/branches/dominik-locatableadapters/src/zope/app/component/metaconfigure.py	2005-04-14 14:06:47 UTC (rev 29981)
@@ -29,8 +29,9 @@
 from zope.security.proxy import Proxy
 
 from zope.app import zapi
-from zope.app.security.adapter import TrustedAdapterFactory
+from zope.app.security.adapter import TrustedAdapterFactory, UntrustedAdapterFactory
 
+
 PublicPermission = 'zope.Public'
 
 def handler(methodName, *args, **kwargs):
@@ -176,8 +177,13 @@
         checker = InterfaceChecker(provides, permission)
         factory = _protectedFactory(factory, checker)
 
-    if trusted:
-        factory = TrustedAdapterFactory(factory)
+        if trusted:
+            factory = TrustedAdapterFactory(factory)
+        elif permission != PublicPermission:
+            factory = UntrustedAdapterFactory(factory)
+    else:
+        if trusted:
+            factory = TrustedAdapterFactory(factory)
 
     _context.action(
         discriminator = ('adapter', for_, provides, name),

Modified: Zope3/branches/dominik-locatableadapters/src/zope/app/component/tests/test_directives.py
===================================================================
--- Zope3/branches/dominik-locatableadapters/src/zope/app/component/tests/test_directives.py	2005-04-14 11:31:07 UTC (rev 29980)
+++ Zope3/branches/dominik-locatableadapters/src/zope/app/component/tests/test_directives.py	2005-04-14 14:06:47 UTC (rev 29981)
@@ -343,10 +343,16 @@
             '''
             )))
 
-        # With an unproxied object, business as usual
+        # With an unproxied none-locatable object we get a location-proxied
+        # object back
         ob = Content()
-        self.assertEqual(type(I1(ob)), type(A1()))
+        from zope.app.location import LocationProxy
+        self.assertEqual(type(I1(ob)), LocationProxy)
 
+        # if we remove the location proxy the content object appears
+        from zope.proxy import removeAllProxies
+        self.assertEqual(type(removeAllProxies(I1(ob))), type(A1()))
+
         # Now with a proxied object:
         from zope.security.checker import ProxyFactory
         p = ProxyFactory(ob)
@@ -464,7 +470,15 @@
         content = Content()
         a1 = A1()
         a2 = A2()
-        a3 = ProxyFactory(zapi.queryMultiAdapter((content, a1, a2), I3))
+        from zope.app.location import LocationProxy
+        self.assertEqual(type(zapi.queryMultiAdapter((content, a1, a2), I3)), LocationProxy)
+
+        # TODO: I do not understand that test
+        # a3 = ProxyFactory(zapi.queryMultiAdapter((content, a1, a2), I3))
+        # workaround start
+        from zope.proxy import removeAllProxies
+        a3 = ProxyFactory(removeAllProxies(zapi.queryMultiAdapter((content, a1, a2), I3)))
+        # workaround end
         self.assertEqual(a3.__class__, A3)
         items = [item[0] for item in getTestProxyItems(a3)]
         self.assertEqual(items, ['f1', 'f2', 'f3'])
@@ -568,7 +582,15 @@
             '''
             )))
 
-        adapter = ProxyFactory(IApp(Content()))
+        from zope.app.location import LocationProxy
+        self.assertEqual(type(IApp(Content())), LocationProxy)
+
+        # TODO: I do not understand that test
+        #adapter = ProxyFactory(IApp(Content()))
+        # workaround start
+        from zope.proxy import removeAllProxies
+        adapter = ProxyFactory(removeAllProxies(IApp(Content())))
+        # workaround end
         items = [item[0] for item in getTestProxyItems(adapter)]
         self.assertEqual(items, ['a', 'f'])
         self.assertEqual(removeSecurityProxy(adapter).__class__, Comp)
@@ -584,7 +606,15 @@
             '''
             )))
 
-        adapter = ProxyFactory(IApp(Content()))
+        from zope.app.location import LocationProxy
+        self.assertEqual(type(IApp(Content())), LocationProxy)
+
+        # TODO: I do not understand that test
+        #adapter = ProxyFactory(IApp(Content()))
+        # workaround start
+        from zope.proxy import removeAllProxies
+        adapter = ProxyFactory(removeAllProxies(IApp(Content())))
+        # workaround end
         items = [item[0] for item in getTestProxyItems(adapter)]
         self.assertEqual(items, ['a', 'f'])
         self.assertEqual(removeSecurityProxy(adapter).__class__, Comp)

Modified: Zope3/branches/dominik-locatableadapters/src/zope/app/intid/__init__.py
===================================================================
--- Zope3/branches/dominik-locatableadapters/src/zope/app/intid/__init__.py	2005-04-14 11:31:07 UTC (rev 29980)
+++ Zope3/branches/dominik-locatableadapters/src/zope/app/intid/__init__.py	2005-04-14 14:06:47 UTC (rev 29981)
@@ -27,7 +27,7 @@
 
 from zope.event import notify
 from zope.interface import implements
-from zope.security.proxy import removeSecurityProxy
+from zope.proxy import removeAllProxies
 
 from zope.app import zapi
 from zope.app.container.contained import Contained
@@ -103,7 +103,7 @@
 
     def register(self, ob):
         # Note that we'll still need to keep this proxy removal.
-        ob = removeSecurityProxy(ob)
+        ob = removeAllProxies(ob)
         ref = IKeyReference(ob)
         if ref in self.ids:
             return self.ids[ref]

Modified: Zope3/branches/dominik-locatableadapters/src/zope/app/keyreference/persistent.py
===================================================================
--- Zope3/branches/dominik-locatableadapters/src/zope/app/keyreference/persistent.py	2005-04-14 11:31:07 UTC (rev 29980)
+++ Zope3/branches/dominik-locatableadapters/src/zope/app/keyreference/persistent.py	2005-04-14 14:06:47 UTC (rev 29981)
@@ -23,9 +23,16 @@
 from ZODB.interfaces import IConnection
 import zope.interface
 
+from zope.app.location import Location
+
 import zope.app.keyreference.interfaces
 
-class KeyReferenceToPersistent(object):
+# TODO: I do not understand that test
+# I get pickable Errors within the functional tests of zope.app.intid
+# The reference derives from Location to prevent its location-proxying
+# by the trusted adapters facility. 
+
+class KeyReferenceToPersistent(Location):
     """An IReference for persistent object which is comparable.
 
     These references compare by _p_oids of the objects they reference.

Modified: Zope3/branches/dominik-locatableadapters/src/zope/app/security/adapter.py
===================================================================
--- Zope3/branches/dominik-locatableadapters/src/zope/app/security/adapter.py	2005-04-14 11:31:07 UTC (rev 29980)
+++ Zope3/branches/dominik-locatableadapters/src/zope/app/security/adapter.py	2005-04-14 14:06:47 UTC (rev 29981)
@@ -18,8 +18,101 @@
 
 from zope.security.checker import ProxyFactory
 from zope.security.proxy import removeSecurityProxy
-from zope.app.location import ILocation, Location
+from zope.app.location import ILocation, Location, LocationProxy
 
+
+def assertLocation(adapter, parent):
+    """Assert locatable adapters.
+
+    This function asserts that the adapter get location-proxied unless it does
+    not provide ILocation itself. Further more the returned locatable adapter
+    get its parent set unless its __parent__ attribute is not None.
+    
+    Arguments
+    ---------
+    adapter - proxied or unproxied adapter
+    parent - unproxied locatable object
+
+    Usage
+    -----
+    Suppose we have a location that plays the duty-parent in cases
+    where no regular-parent is provided by the adapter itself:
+
+        >>> dutyparent = Location()
+
+    We account three different base use cases A, B and C.
+    
+    A. Adapters which do not provide ILocation get location-proxied
+    and theirs parent is set to the duty-parent:
+
+        >>> class A(object):
+        ...     def __init__(self, context):
+        ...         self.context = context
+
+        >>> a = A(dutyparent)
+        >>> a1 = assertLocation(a, dutyparent)
+
+        >>> ILocation.providedBy(a1)
+        True
+        >>> a1.__parent__ is dutyparent
+        True
+        >>> type(a1).__name__
+        'LocationProxy'
+
+    B. Adapters which do provide ILocation get never location-proxied,
+    but theirs parent is also set to the duty-parent unless their parent is
+    not None:
+
+        >>> class B(Location):
+        ...     def __init__(self, context):
+        ...         self.context = context
+
+        >>> b = B(dutyparent)
+        >>> b1 = assertLocation(b, dutyparent)
+
+        >>> ILocation.providedBy(b1)
+        True
+        >>> b1.__parent__ is dutyparent
+        True
+        >>> type(b1).__name__
+        'B'
+
+    C. In those cases where the parent is provided by the adapter itself, the adapter
+    keeps its regular-parent:
+
+        >>> regularparent = Location()
+
+        >>> class C(Location):
+        ...     def __init__(self, context):
+        ...         self.context = context
+        ...         self.__parent__ = context
+
+        >>> c = C(regularparent)
+        >>> c1 = assertLocation(c, dutyparent)
+
+        >>> ILocation.providedBy(c1)
+        True
+        >>> c1.__parent__ is regularparent
+        True
+        >>> type(c1).__name__
+        'C'
+    """
+    # handle none-locatable adapters (A)
+    if not ILocation.providedBy(adapter):
+        locatable = LocationProxy(adapter)
+        locatable.__parent__ = parent
+        return locatable
+
+    # handle locatable, parentless adapters (B)
+    if adapter.__parent__ is None:
+        adapter.__parent__ = parent
+        return adapter
+
+    # handle locatable, parentful adapters (C)
+    else:
+        return adapter
+
+
 class TrustedAdapterFactory(object):
     """Adapt an adapter factory to to provide trusted adapters
 
@@ -27,9 +120,20 @@
        adapt any proxied objects, it will unproxy them and then proxy the
        resulting adapter.
 
+       Further trusted adapters always provide a location. If an adapter
+       itself does not provide ILocation it is wrapped within a location proxy
+       and it parent will be set:
+
+           security proxy > location proxy > adapter > object(s)
+
+       If the adapter does provide ILocation and it's __parent__ is None,
+       we set the __parent__ only: 
+       
+           security proxy > adapter > object(s) 
+
        Suppose we have an adapter factory:
 
-         >>> class A(object):
+         >>> class B(Location):
          ...     def __init__(self, context):
          ...         self.context = context
 
@@ -40,12 +144,12 @@
 
        If we adapt it:
 
-         >>> a = A(p)
+         >>> a = B(p)
 
        the result is not a proxy:
 
          >>> type(a).__name__
-         'A'
+         'B'
 
        But the object it adapts still is:
 
@@ -54,11 +158,11 @@
 
        Now, will we'll adapt our adapter factory to a trusted adapter factory:
 
-         >>> TA = TrustedAdapterFactory(A)
+         >>> TB = TrustedAdapterFactory(B)
 
        and if we use it:
 
-         >>> a = TA(p)
+         >>> a = TB(p)
 
        then the adapter is proxied:
 
@@ -74,7 +178,7 @@
 
        This works with multiple objects too:
 
-         >>> class M(object):
+         >>> class M(Location):
          ...     def __init__(self, *context):
          ...         self.context = context
 
@@ -97,32 +201,45 @@
          >>> a.context[0] is o, a.context[1] is o2, a.context[2] is o3
          (True, True, True)
 
-       The __parent__ will be set to the first object if the adapter
-       is a location. M isn't a location, so the adapter has no
-       __parent__:
+       The __parent__ will be always set to the first object unless the
+       adapter's parent is not None. This happens even if the adapter 
+       itself does not provide a location.
+       
+       A. None-locatable Adapters:
 
-         >>> a.__parent__
-         Traceback (most recent call last):
-         ...
-         AttributeError: 'M' object has no attribute '__parent__'
+         >>> class A(object):
+         ...     def __init__(self, context):
+         ...         self.context = context
 
-       But if we create an adapter that is a Location:
+         >>> TA = TrustedAdapterFactory(A)
+         >>> TA(o).__parent__ is o
+         True
 
-         >>> class L(A, Location):
-         ...     pass
-         >>> TL = TrustedAdapterFactory(L)
+       B. Locatable, parentless Adapters:
 
-       Then __parent__ will be set:
+         >>> TB = TrustedAdapterFactory(B)
+         >>> TB(o).__parent__ is o
+         True
+         >>> removeSecurityProxy(TB(p)).__parent__ is o
+         True
 
-         >>> TL(o).__parent__ is o
+       C. Locatable, parentful Adapters:
+
+         >>> class C(Location):
+         ...     def __init__(self, context):
+         ...         self.context = context
+         ...         self.__parent__ = context
+
+         >>> TC = TrustedAdapterFactory(C)
+         >>> TC(o).__parent__ is o
          True
-         >>> removeSecurityProxy(TL(p)).__parent__ is o
+         >>> removeSecurityProxy(TC(p)).__parent__ is o
          True
 
        The factory adapter has the __name__ and __module__ of the
        factory it adapts:
 
-         >>> (TA.__module__, TA.__name__) == (A.__module__, A.__name__)
+         >>> (TB.__module__, TB.__name__) == (B.__module__, B.__name__)
          True
 
        """
@@ -137,13 +254,101 @@
             if removeSecurityProxy(arg) is not arg:
                 args = map(removeSecurityProxy, args)
                 adapter = self.factory(*args)
-                if (ILocation.providedBy(adapter)
-                    and adapter.__parent__ is None):
-                    adapter.__parent__ = args[0]
-                return ProxyFactory(adapter)
+                return ProxyFactory(assertLocation(adapter, args[0]))
 
         adapter = self.factory(*args)
-        if (ILocation.providedBy(adapter)
-            and adapter.__parent__ is None):
-            adapter.__parent__ = args[0]
-        return adapter
+        return assertLocation(adapter, args[0])
+
+
+class UntrustedAdapterFactory(object):
+    """Adapt an adapter factory to provide locatable untrusted adapters
+
+       Untrusted adapters always adapt proxied objects. If any permission
+       other than zope.Public is required, untrusted adapters need a location
+       in order that the local authentication mechanism can be inovked correctly.
+
+       If the adapter doesn't provide ILocation, we location proxy it and
+       set the parent:
+       
+        location proxy > adapter > security proxy > object(s) 
+       
+       If the adapter does provide ILocation and it's __parent__ is None,
+       we set the __parent__ only:
+
+         adapter > security proxy > object(s)
+
+       Now, suppose have an object and proxy it:
+
+         o = []
+         >>> o = []
+         >>> p = ProxyFactory(o)
+
+       A. Adapters which do not provide ILocation get location-proxied
+       and theirs parent is set:
+
+         >>> class A(object):
+         ...     def __init__(self, context):
+         ...         self.context = context
+
+         >>> UA = UntrustedAdapterFactory(A)
+         >>> a = UA(o)
+
+         >>> ILocation.providedBy(a)
+         True
+         >>> a.__parent__ is o
+         True
+         >>> type(a).__name__
+         'LocationProxy'
+
+       B. Adapters which do provide ILocation get never location-proxied,
+       but theirs parent is also set unless their parent is
+       not None:
+
+           >>> class B(Location):
+           ...     def __init__(self, context):
+           ...         self.context = context
+
+           >>> UB = UntrustedAdapterFactory(B)
+           >>> b = UB(o)
+
+           >>> ILocation.providedBy(b)
+           True
+           >>> b.__parent__ is o
+           True
+           >>> type(b).__name__
+           'B'
+
+       C. In those cases where the parent is provided by the adapter itself,
+       nothing happens:
+
+           >>> class C(Location):
+           ...     def __init__(self, context):
+           ...         self.context = context
+           ...         self.__parent__ = context
+
+           >>> UC = UntrustedAdapterFactory(C)
+           >>> c = UC(o)
+
+           >>> ILocation.providedBy(c)
+           True
+           >>> c.__parent__ is o
+           True
+           >>> type(c).__name__
+           'C'
+
+        The factory adapter has the __name__ and __module__ of the
+        factory it adapts:
+
+            >>> (UB.__module__, UB.__name__) == (B.__module__, B.__name__)
+            True
+
+    """
+
+    def __init__(self, factory):
+        self.factory = factory
+        self.__name__ = factory.__name__
+        self.__module__ = factory.__module__
+
+    def __call__(self, *args):
+        adapter = self.factory(*args)
+        return assertLocation(adapter, args[0])



More information about the Zope3-Checkins mailing list