| |
|
| from zope.security.checker import ProxyFactory |
from zope.security.checker import ProxyFactory |
| from zope.security.proxy import removeSecurityProxy |
from zope.security.proxy import removeSecurityProxy |
| from zope.app.location import ILocation, Location |
from zope.app.location import ILocation, Location, LocationProxy |
| |
|
| class TrustedAdapterFactory(object): |
|
| """Adapt an adapter factory to to provide trusted adapters |
|
| |
|
| Trusted adapters always adapt unproxied objects. If asked to |
def assertLocation(adapter, parent): |
| adapt any proxied objects, it will unproxy them and then proxy the |
"""Assert locatable adapters. |
| resulting adapter. |
|
| |
|
| Suppose we have an adapter factory: |
|
| |
|
| >>> class A(object): |
|
| ... def __init__(self, context): |
|
| ... self.context = context |
|
| |
|
| Now, suppose have an object and proxy it: |
|
| |
|
| >>> o = [] |
|
| >>> p = ProxyFactory(o) |
|
| |
|
| If we adapt it: |
|
| |
|
| >>> a = A(p) |
|
| |
|
| the result is not a proxy: |
|
| |
|
| >>> type(a).__name__ |
|
| 'A' |
|
| |
|
| But the object it adapts still is: |
|
| |
|
| >>> type(a.context).__name__ |
|
| '_Proxy' |
|
| |
|
| Now, will we'll adapt our adapter factory to a trusted adapter factory: |
|
| |
|
| >>> TA = TrustedAdapterFactory(A) |
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. |
| |
|
| and if we use it: |
see adapter.txt |
| |
""" |
| >>> a = TA(p) |
# 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 |
| |
|
| then the adapter is proxied: |
# handle locatable, parentful adapters (C) |
| |
else: |
| |
return adapter |
| |
|
| >>> type(a).__name__ |
|
| '_Proxy' |
|
| |
|
| And the object proxied is not. (We actually have to remove the |
class LocatingTrustedAdapterFactory(object): |
| adapter to get to the adapted object in this case.) |
"""Adapt an adapter factory to provide trusted and (locatable) adapters. |
| |
|
| >>> a = removeSecurityProxy(a) |
Trusted adapters always adapt unproxied objects. If asked to |
| >>> type(a.context).__name__ |
adapt any proxied objects, it will unproxy them and then |
| 'list' |
security-proxy the resulting adapter (S) unless the objects where not |
| |
security-proxied before (N). |
| |
|
| |
Further locating trusted adapters provide a location for protected |
| |
adapters only (S). If such a protected adapter itself does not provide |
| |
ILocation it is wrapped within a location proxy and it parent will |
| |
be set. If the adapter does provide ILocation and it's __parent__ is None, |
| |
we set the __parent__ to the adapter's context: |
| |
|
| This works with multiple objects too: |
see adapter.txt |
| |
""" |
| |
def __init__(self, factory): |
| |
self.factory = factory |
| |
self.__name__ = factory.__name__ |
| |
self.__module__ = factory.__module__ |
| |
|
| >>> class M(object): |
# protected methods |
| ... def __init__(self, *context): |
def _customizeProtected(self, adapter, context): |
| ... self.context = context |
return assertLocation(adapter, context) |
| |
|
| >>> TM = TrustedAdapterFactory(M) |
def _customizeUnprotected(self, adapter, context): |
| |
if (ILocation.providedBy(adapter) |
| |
and adapter.__parent__ is None): |
| |
adapter.__parent__ = context |
| |
return adapter |
| |
|
| >>> o2 = [] |
def __call__(self, *args): |
| >>> o3 = [] |
for arg in args: |
| |
if removeSecurityProxy(arg) is not arg: |
| |
args = map(removeSecurityProxy, args) |
| |
adapter = self.factory(*args) |
| |
adapter = self._customizeProtected(adapter, args[0]) |
| |
return ProxyFactory(adapter) |
| |
|
| >>> a = TM(p, o2, o3) |
adapter = self.factory(*args) |
| >>> type(a).__name__ |
adapter = self._customizeUnprotected(adapter, args[0]) |
| '_Proxy' |
return adapter |
| >>> a = removeSecurityProxy(a) |
|
| >>> a.context[0] is o, a.context[1] is o2, a.context[2] is o3 |
|
| (True, True, True) |
|
| |
|
| >>> a = TM(p, ProxyFactory(o2), ProxyFactory(o3)) |
|
| >>> type(a).__name__ |
|
| '_Proxy' |
|
| >>> a = removeSecurityProxy(a) |
|
| >>> 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 |
# BBB, entire class gone in 3.2 |
| is a location. M isn't a location, so the adapter has no |
class TrustedAdapterFactory(LocatingTrustedAdapterFactory): |
| __parent__: |
"""Adapt an adapter factory to provide trusted adapters. |
| |
|
| >>> a.__parent__ |
Trusted adapters always adapt unproxied objects. If asked to |
| Traceback (most recent call last): |
adapt any proxied objects, it will unproxy them and then |
| ... |
security-proxy the resulting adapter unless the objects where not |
| AttributeError: 'M' object has no attribute '__parent__' |
security-proxied before. |
| |
|
| But if we create an adapter that is a Location: |
If the adapter does provide ILocation and it's __parent__ is None, |
| |
we set the __parent__ to the adapter's context. |
| |
""" |
| |
|
| >>> class L(A, Location): |
# do not location-proxy the adapter |
| ... pass |
def _customizeProtected(self, adapter, context): |
| >>> TL = TrustedAdapterFactory(L) |
return self._customizeUnprotected(adapter, context) |
| |
|
| Then __parent__ will be set: |
|
| |
|
| >>> TL(o).__parent__ is o |
class LocatingUntrustedAdapterFactory(object): |
| True |
"""Adapt an adapter factory to provide locatable untrusted adapters |
| >>> removeSecurityProxy(TL(p)).__parent__ is o |
|
| True |
|
| |
|
| The factory adapter has the __name__ and __module__ of the |
Untrusted adapters always adapt proxied objects. If any permission |
| factory it adapts: |
other than zope.Public is required, untrusted adapters need a location |
| |
in order that the local authentication mechanism can be inovked |
| |
correctly. |
| |
|
| >>> (TA.__module__, TA.__name__) == (A.__module__, A.__name__) |
If the adapter does not provide ILocation, we location proxy it and |
| True |
set the parent. If the adapter does provide ILocation and |
| |
it's __parent__ is None, we set the __parent__ to the adapter's |
| |
context only: |
| |
|
| |
see adapter.txt |
| """ |
""" |
| |
|
| def __init__(self, factory): |
def __init__(self, factory): |
| self.__module__ = factory.__module__ |
self.__module__ = factory.__module__ |
| |
|
| def __call__(self, *args): |
def __call__(self, *args): |
| for arg in args: |
|
| if removeSecurityProxy(arg) is not arg: |
|
| args = map(removeSecurityProxy, args) |
|
| adapter = self.factory(*args) |
adapter = self.factory(*args) |
| if (ILocation.providedBy(adapter) |
return assertLocation(adapter, args[0]) |
| and adapter.__parent__ is None): |
|
| adapter.__parent__ = args[0] |
|
| return ProxyFactory(adapter) |
|
| |
|
| adapter = self.factory(*args) |
|
| if (ILocation.providedBy(adapter) |
|
| and adapter.__parent__ is None): |
|
| adapter.__parent__ = args[0] |
|
| return adapter |
|