summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/zope/security/proxy.py185
-rw-r--r--src/zope/security/tests/test_proxy.py29
2 files changed, 205 insertions, 9 deletions
diff --git a/src/zope/security/proxy.py b/src/zope/security/proxy.py
index 4c189dc..899970a 100644
--- a/src/zope/security/proxy.py
+++ b/src/zope/security/proxy.py
@@ -15,11 +15,188 @@
"""
__docformat__ = 'restructuredtext'
+import functools
-from zope.security._proxy import getChecker
-from zope.security._proxy import getObject
-from zope.security._proxy import _Proxy
-Proxy = _Proxy
+
+from zope.proxy import PyProxyBase
+
+
+def _check_name(meth):
+ name = meth.__name__
+ func = meth.__func__
+ def _wrapper(self, *args, **kw):
+ wrapped = super(PyProxyBase, self).__getattribute__('_wrapped')
+ checker = super(PyProxyBase, self).__getattribute__('_checker')
+ checker.check_getattr(wrapped, name)
+ return getattr(wrapped, name)(*args, **kw)
+ return functools.update_wrapper(_wrapper, meth)
+
+def _check_name_inplace(meth):
+ name = meth.__name__
+ func = meth.__func__
+ def _wrapper(self, *args, **kw):
+ wrapped = super(PyProxyBase, self).__getattribute__('_wrapped')
+ checker = super(PyProxyBase, self).__getattribute__('_checker')
+ checker.check_getattr(wrapped, name)
+ w_meth = getattr(wrapped, name, None)
+ if w_meth is not None:
+ return w_meth(*args, **kw)
+ x_name = '__%s__' % name[3:-2]
+ return ProxyPy(getattr(wrapped, x_name)(*args, **kw), checker)
+ return functools.update_wrapper(_wrapper, meth)
+
+
+class ProxyPy(PyProxyBase):
+ __slots__ = ('_wrapped', '_checker')
+
+ def __new__(cls, value, checker):
+ inst = super(PyProxyBase, cls).__new__(cls)
+ inst._wrapped = value
+ inst._checker = checker
+ return inst
+
+ def __init__(self, value, checker):
+ if checker is None:
+ raise ValueError('checker may now be None')
+ self._wrapped = value
+ self._checker = checker
+
+ # Attribute protocol
+ def __getattribute__(self, name):
+ wrapped = super(PyProxyBase, self).__getattribute__('_wrapped')
+ checker = super(PyProxyBase, self).__getattribute__('_checker')
+ if name == '_wrapped':
+ return wrapped
+ if name == '_checker':
+ return checker
+ if name not in ['__cmp__', '__hash__', '__bool__']:
+ checker.check_getattr(wrapped, name)
+ return super(ProxyPy, self).__getattribute__(name)
+
+ def __getattr__(self, name):
+ return getattr(self._wrapped, name)
+
+ def __setattr__(self, name, value):
+ if name in ('_wrapped', '_checker'):
+ return super(PyProxyBase, self).__setattr__(name, value)
+ setattr(self._wrapped, name, value)
+
+ def __delattr__(self, name):
+ if name in ('_wrapped', '_checker'):
+ raise AttributeError()
+ delattr(self._wrapped, name)
+
+ def __cmp__(self, other):
+ # no check
+ import pdb; pdb.set_trace()
+ wrapped = super(PyProxyBase, self).__getattribute__('_wrapped')
+ return cmp(wrapped, other)
+
+ def __hash__(self):
+ # no check
+ wrapped = super(PyProxyBase, self).__getattribute__('_wrapped')
+ return hash(wrapped)
+
+ def __nonzero__(self):
+ # no check
+ wrapped = super(PyProxyBase, self).__getattribute__('_wrapped')
+ return bool(wrapped)
+ __bool__ = __nonzero__
+
+for name in ['__call__',
+ '__repr__',
+ '__str__',
+ '__unicode__',
+ '__reduce__',
+ '__reduce_ex__',
+ '__lt__',
+ '__le__',
+ '__eq__',
+ '__ge__',
+ '__gt__',
+ #'__cmp__', # Unchecked in C proxy
+ #'__nonzero__', # Unchecked in C proxy
+ #'__bool__', # Unchecked in C proxy
+ #'__hash__', # Unchecked in C proxy
+ '__len__',
+ '__getitem__',
+ '__setitem__',
+ '__delitem__',
+ '__iter__',
+ '__next__',
+ 'next',
+ '__contains__',
+ '__neg__',
+ '__pos__',
+ '__abs__',
+ '__invert__',
+ '__complex__',
+ '__int__',
+ '__float__',
+ '__long__',
+ '__oct__',
+ '__hex__',
+ '__index__',
+ '__coerce__',
+ '__add__',
+ '__sub__',
+ '__mul__',
+ '__div__',
+ '__truediv__',
+ '__floordiv__',
+ '__mod__',
+ '__divmod__',
+ '__pow__',
+ '__radd__',
+ '__rsub__',
+ '__rmul__',
+ '__rdiv__',
+ '__rtruediv__',
+ '__rfloordiv__',
+ '__rmod__',
+ '__rdivmod__',
+ '__rpow__',
+ '__lshift__',
+ '__rshift__',
+ '__and__',
+ '__xor__',
+ '__or__',
+ '__rlshift__',
+ '__rrshift__',
+ '__rand__',
+ '__rxor__',
+ '__ror__',
+ ]:
+ meth = getattr(PyProxyBase, name)
+ setattr(ProxyPy, name, _check_name(meth))
+
+for name in ['__iadd__',
+ '__isub__',
+ '__imul__',
+ '__idiv__',
+ '__itruediv__',
+ '__ifloordiv__',
+ '__imod__',
+ '__ilshift__',
+ '__irshift__',
+ '__iand__',
+ '__ixor__',
+ '__ior__',
+ '__ipow__',
+ ]:
+ meth = getattr(PyProxyBase, name)
+ setattr(ProxyPy, name, _check_name_inplace(meth))
+
+try:
+ from zope.security._proxy import _Proxy
+except ImportError:
+ #getChecker = getCheckerPy
+ #getObject = getObjectPy
+ Proxy = ProxyPy
+else:
+ from zope.security._proxy import getChecker
+ from zope.security._proxy import getObject
+ Proxy = _Proxy
# We need the injection of DecoratedSecurityCheckerDescriptor into
# zope.location's LocationProxy as soon someone uses security proxies by
diff --git a/src/zope/security/tests/test_proxy.py b/src/zope/security/tests/test_proxy.py
index e54894d..523cd03 100644
--- a/src/zope/security/tests/test_proxy.py
+++ b/src/zope/security/tests/test_proxy.py
@@ -46,11 +46,7 @@ def _fmt_address(obj):
return '0x%0x' % id(obj)
-class ProxyCTests(unittest.TestCase):
-
- def _getTargetClass(self):
- from zope.security.proxy import _Proxy
- return _Proxy
+class ProxyTestBase(object):
def _makeOne(self, object, checker):
return self._getTargetClass()(object, checker)
@@ -1302,6 +1298,28 @@ class ProxyCTests(unittest.TestCase):
self.assertEqual(checker._checked, '__setitem__')
+class ProxyCTests(unittest.TestCase, ProxyTestBase):
+
+ def _getTargetClass(self):
+ from zope.security.proxy import _Proxy
+ return _Proxy
+
+
+class ProxyPyTests(unittest.TestCase, ProxyTestBase):
+
+ def _getTargetClass(self):
+ from zope.security.proxy import ProxyPy
+ return ProxyPy
+
+ def test_ctor_w_checker(self):
+ # Can't access '_wrapped' / '_checker' in C version
+ target = object()
+ checker = object()
+ proxy = self._makeOne(target, checker)
+ self.assertTrue(proxy._wrapped is target)
+ self.assertTrue(proxy._checker is checker)
+
+
class DummyChecker(object):
_proxied = _checked = None
def __init__(self, raising=None, allowed=()):
@@ -1844,6 +1862,7 @@ class LocationProxySecurityCheckerTests(unittest.TestCase):
def test_suite():
return unittest.TestSuite((
+ unittest.makeSuite(ProxyPyTests),
unittest.makeSuite(ProxyCTests),
unittest.makeSuite(Test_getTestProxyItems),
unittest.makeSuite(Test_isinstance),