diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/zope/security/proxy.py | 44 | ||||
-rw-r--r-- | src/zope/security/tests/test_adapter.py | 9 | ||||
-rw-r--r-- | src/zope/security/tests/test_checker.py | 50 | ||||
-rw-r--r-- | src/zope/security/tests/test_proxy.py | 36 |
4 files changed, 80 insertions, 59 deletions
diff --git a/src/zope/security/proxy.py b/src/zope/security/proxy.py index c393bc7..974b923 100644 --- a/src/zope/security/proxy.py +++ b/src/zope/security/proxy.py @@ -20,16 +20,16 @@ from zope.proxy import PyProxyBase from zope.security._compat import PYPY from zope.security.interfaces import ForbiddenAttribute -# Never expose this attribute in an utrusted environment. -_secret = str(hash(object())) - -def _check_name(meth): +def _check_name(meth, wrap_result=True): name = meth.__name__ def _wrapper(self, *args, **kw): wrapped = super(PyProxyBase, self).__getattribute__('_wrapped') checker = super(PyProxyBase, self).__getattribute__('_checker') - checker.check_getattr(wrapped, name) - return checker.proxy(getattr(wrapped, name)(*args, **kw)) + checker.check(wrapped, name) + res = meth(self, *args, **kw) + if not wrap_result: + return res + return checker.proxy(res) return functools.update_wrapper(_wrapper, meth) def _check_name_inplace(meth): @@ -37,7 +37,7 @@ def _check_name_inplace(meth): def _wrapper(self, *args, **kw): wrapped = super(PyProxyBase, self).__getattribute__('_wrapped') checker = super(PyProxyBase, self).__getattribute__('_checker') - checker.check_getattr(wrapped, name) + checker.check(wrapped, name) w_meth = getattr(wrapped, name, None) if w_meth is not None: # The proxy object cannot change; we are modifying in place. @@ -74,14 +74,15 @@ class ProxyPy(PyProxyBase): # Attribute protocol def __getattribute__(self, name): - # Explicitely disallow _wrapped and _checker to be accessed. if name in ('_wrapped', '_checker'): - raise AttributeError(name) + # Only allow _wrapped and _checker to be accessed from inside. + if sys._getframe(1).f_locals.get('self') is not self: + raise AttributeError(name) wrapped = super(PyProxyBase, self).__getattribute__('_wrapped') - if name == '_wrapped'+_secret: + if name == '_wrapped': return wrapped checker = super(PyProxyBase, self).__getattribute__('_checker') - if name == '_checker'+_secret: + if name == '_checker': return checker if name not in ['__cmp__', '__hash__', '__bool__', '__nonzero__', '__lt__', '__le__', '__eq__', '__ne__', '__ge__', @@ -113,13 +114,13 @@ class ProxyPy(PyProxyBase): @_check_name def __getslice__(self, start, end): - getitem = super(PyProxyBase, self).__getattribute__('__getitem__') - return getitem(start, end) + getitem = PyProxyBase.__getattribute__(self, '__getitem__') + return getitem(slice(start, end)) @_check_name def __setslice__(self, i, j, value): - setitem = super(PyProxyBase, self).__getattribute__('__setitem__') - return setitem(i, j, value) + setitem = PyProxyBase.__getattribute__(self, '__setitem__') + return setitem(slice(i, j), value) def __cmp__(self, other): # no check @@ -212,7 +213,6 @@ for name in ['__call__', #'__bool__', # Unchecked in C proxy (rich coparison) #'__hash__', # Unchecked in C proxy (rich coparison) #'__cmp__', # Unchecked in C proxy - '__len__', '__getitem__', '__setitem__', '__delitem__', @@ -263,6 +263,11 @@ for name in ['__call__', meth = getattr(PyProxyBase, name) setattr(ProxyPy, name, _check_name(meth)) +for name in ['__len__', + ]: + meth = getattr(PyProxyBase, name) + setattr(ProxyPy, name, _check_name(meth, False)) + for name in ['__iadd__', '__isub__', '__imul__', @@ -281,10 +286,13 @@ for name in ['__iadd__', setattr(ProxyPy, name, _check_name_inplace(meth)) def getCheckerPy(proxy): - return getattr(proxy, '_checker'+_secret) + return super(PyProxyBase, proxy).__getattribute__('_checker') def getObjectPy(proxy): - return getattr(proxy, '_wrapped'+_secret) + isinstance_func = builtin_isinstance or isinstance + if not isinstance_func(proxy, ProxyPy): + return proxy + return super(PyProxyBase, proxy).__getattribute__('_wrapped') try: from zope.security._proxy import _Proxy diff --git a/src/zope/security/tests/test_adapter.py b/src/zope/security/tests/test_adapter.py index ab8e80a..f9bebb3 100644 --- a/src/zope/security/tests/test_adapter.py +++ b/src/zope/security/tests/test_adapter.py @@ -165,6 +165,7 @@ class LocatingTrustedAdapterFactoryTests(unittest.TestCase): @_skip_wo_zope_location def test__call__w_non_ILocation_w_spacesuit(self): from zope.proxy import getProxiedObject + from zope.security.proxy import getObject from zope.security.proxy import ProxyFactory from zope.security.proxy import removeSecurityProxy factory = self._makeFactory() @@ -239,7 +240,7 @@ class LocatingTrustedAdapterFactoryTests(unittest.TestCase): def test__call__w_ILocation_w_spacesuit(self): from zope.interface import directlyProvides from zope.location import ILocation - from zope.proxy import getProxiedObject + from zope.security.proxy import getObject from zope.security.proxy import ProxyFactory from zope.security.proxy import removeSecurityProxy factory = self._makeFactory() @@ -256,7 +257,7 @@ class LocatingTrustedAdapterFactoryTests(unittest.TestCase): self.assertFalse(returned is factory) ploc = removeSecurityProxy(returned) self.assertTrue(ploc.__parent__ is adapter) - unwrapped = getProxiedObject(ploc) + unwrapped = getObject(ploc) self.assertTrue(unwrapped is factory) after = dict([(k, v) for k, v in unwrapped.__dict__.items() if k not in ('_called_with', '__parent__')]) @@ -268,7 +269,7 @@ class LocatingTrustedAdapterFactoryTests(unittest.TestCase): def test__call__w_ILocation_w_spacesuit_w_existing_parent(self): from zope.interface import directlyProvides from zope.location import ILocation - from zope.proxy import getProxiedObject + from zope.security.proxy import getObject from zope.security.proxy import ProxyFactory from zope.security.proxy import removeSecurityProxy factory = self._makeFactory() @@ -286,7 +287,7 @@ class LocatingTrustedAdapterFactoryTests(unittest.TestCase): self.assertFalse(returned is factory) ploc = removeSecurityProxy(returned) self.assertTrue(ploc.__parent__ is parent) - unwrapped = getProxiedObject(ploc) + unwrapped = getObject(ploc) self.assertTrue(unwrapped is factory) after = dict([(k, v) for k, v in unwrapped.__dict__.items() if k not in ('_called_with', '__parent__')]) diff --git a/src/zope/security/tests/test_checker.py b/src/zope/security/tests/test_checker.py index fcd7698..f6ad51b 100644 --- a/src/zope/security/tests/test_checker.py +++ b/src/zope/security/tests/test_checker.py @@ -32,8 +32,7 @@ class Test_ProxyFactory(unittest.TestCase): return ProxyFactory(object, checker) def test_w_already_proxied_no_checker(self): - from zope.security._proxy import _Proxy as Proxy - from zope.security._proxy import getChecker + from zope.security.proxy import Proxy, getChecker obj = object() def _check(*x): pass @@ -43,8 +42,7 @@ class Test_ProxyFactory(unittest.TestCase): self.assertTrue(getChecker(returned) is _check) def test_w_already_proxied_same_checker(self): - from zope.security._proxy import _Proxy as Proxy - from zope.security._proxy import getChecker + from zope.security.proxy import Proxy, getChecker obj = object() def _check(*x): pass @@ -54,7 +52,7 @@ class Test_ProxyFactory(unittest.TestCase): self.assertTrue(getChecker(returned) is _check) def test_w_already_proxied_different_checker(self): - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() def _check(*x): pass @@ -64,7 +62,7 @@ class Test_ProxyFactory(unittest.TestCase): self.assertRaises(TypeError, self._callFUT, proxy, _sneaky) def test_w_explicit_checker(self): - from zope.security._proxy import getChecker + from zope.security.proxy import getChecker obj = object() def _check(*x): pass @@ -78,8 +76,7 @@ class Test_ProxyFactory(unittest.TestCase): self.assertTrue(returned is obj) def test_no_checker_w_dunder(self): - from zope.security._proxy import getChecker - from zope.security._proxy import getObject + from zope.security.proxy import getChecker, getObject _check = object() # don't use a func, due to bound method class _WithChecker(object): __Security_checker__ = _check @@ -93,8 +90,7 @@ class Test_ProxyFactory(unittest.TestCase): from zope.security.checker import Checker from zope.security.checker import _checkers from zope.security.checker import _clear - from zope.security._proxy import getChecker - from zope.security._proxy import getObject + from zope.security.proxy import getChecker, getObject class _Obj(object): pass obj = _Obj() @@ -128,21 +124,21 @@ class Test_canWrite(unittest.TestCase): return _Checker() def test_ok(self): - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() proxy = Proxy(obj, self._makeChecker()) self.assertTrue(self._callFUT(proxy, 'whatever')) def test_w_setattr_unauth(self): from zope.security.interfaces import Unauthorized - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() proxy = Proxy(obj, self._makeChecker(ch_set=Unauthorized)) self.assertFalse(self._callFUT(proxy, 'whatever')) def test_w_setattr_forbidden_getattr_allowed(self): from zope.security.interfaces import ForbiddenAttribute - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() proxy = Proxy(obj, self._makeChecker(ch_set=ForbiddenAttribute)) self.assertFalse(self._callFUT(proxy, 'whatever')) @@ -150,7 +146,7 @@ class Test_canWrite(unittest.TestCase): def test_w_setattr_forbidden_getattr_unauth(self): from zope.security.interfaces import ForbiddenAttribute from zope.security.interfaces import Unauthorized - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() proxy = Proxy(obj, self._makeChecker(ch_get=Unauthorized, ch_set=ForbiddenAttribute)) @@ -158,7 +154,7 @@ class Test_canWrite(unittest.TestCase): def test_w_setattr_forbidden_getattr_forbidden(self): from zope.security.interfaces import ForbiddenAttribute - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() proxy = Proxy(obj, self._makeChecker(ch_get=ForbiddenAttribute, ch_set=ForbiddenAttribute)) @@ -179,21 +175,21 @@ class Test_canAccess(unittest.TestCase): return _Checker() def test_ok(self): - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() proxy = Proxy(obj, self._makeChecker()) self.assertTrue(self._callFUT(proxy, 'whatever')) def test_w_getattr_unauth(self): from zope.security.interfaces import Unauthorized - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() proxy = Proxy(obj, self._makeChecker(ch_get=Unauthorized)) self.assertFalse(self._callFUT(proxy, 'whatever')) def test_w_setattr_forbidden_getattr_allowed(self): from zope.security.interfaces import ForbiddenAttribute - from zope.security._proxy import _Proxy as Proxy + from zope.security.proxy import Proxy obj = object() proxy = Proxy(obj, self._makeChecker(ch_get=ForbiddenAttribute)) self.assertRaises(ForbiddenAttribute, self._callFUT, proxy, 'whatever') @@ -344,8 +340,7 @@ class CheckerTestsBase(object): del thread_local.interaction def test_proxy_already_proxied(self): - from zope.security._proxy import _Proxy as Proxy - from zope.security._proxy import getChecker + from zope.security.proxy import Proxy, getChecker obj = object() def _check(*x): pass @@ -362,8 +357,7 @@ class CheckerTestsBase(object): self.assertTrue(returned is obj) def test_proxy_no_checker_w_dunder(self): - from zope.security._proxy import getChecker - from zope.security._proxy import getObject + from zope.security.proxy import getChecker, getObject _check = object() # don't use a func, due to bound method class _WithChecker(object): __Security_checker__ = _check @@ -378,8 +372,7 @@ class CheckerTestsBase(object): from zope.security.checker import Checker from zope.security.checker import _checkers from zope.security.checker import _clear - from zope.security._proxy import getChecker - from zope.security._proxy import getObject + from zope.security.proxy import getChecker, getObject class _Obj(object): pass obj = _Obj() @@ -696,7 +689,7 @@ class _SelectCheckerBase(object): datetime.datetime.now(), datetime.date.today(), datetime.datetime.now().time(), - datetime.tzinfo('UTC'), + datetime.tzinfo(), ]: self.assertTrue(self._callFUT(obj) is None) @@ -1588,8 +1581,7 @@ class Test(unittest.TestCase): def testLayeredProxies(self): #Test that a Proxy will not be re-proxied. - from zope.proxy import getProxiedObject - from zope.security.proxy import Proxy + from zope.security.proxy import Proxy, getObject from zope.security.checker import Checker from zope.security.checker import NamesChecker class Base: @@ -1600,12 +1592,12 @@ class Test(unittest.TestCase): # base is not proxied, so we expect a proxy proxy1 = checker.proxy(base) self.assertTrue(type(proxy1) is Proxy) - self.assertTrue(getProxiedObject(proxy1) is base) + self.assertTrue(getObject(proxy1) is base) # proxy is a proxy, so we don't expect to get another proxy2 = checker.proxy(proxy1) self.assertTrue(proxy2 is proxy1) - self.assertTrue(getProxiedObject(proxy2) is base) + self.assertTrue(getObject(proxy2) is base) def testMultiChecker(self): diff --git a/src/zope/security/tests/test_proxy.py b/src/zope/security/tests/test_proxy.py index ce7a046..974c26f 100644 --- a/src/zope/security/tests/test_proxy.py +++ b/src/zope/security/tests/test_proxy.py @@ -16,7 +16,7 @@ import unittest import sys -from zope.security._compat import PYTHON2 +from zope.security._compat import PYTHON2, PYPY def _skip_if_not_Py2(testfunc): from functools import update_wrapper @@ -1313,6 +1313,25 @@ class ProxyTestBase(object): self.assertRaises(ForbiddenAttribute, _try) self.assertEqual(checker._checked, '__setitem__') + binops = [ + "x+y", "x-y", "x*y", "x/y", "divmod(x, y)", "x**y", "x//y", + "x<<y", "x>>y", "x&y", "x|y", "x^y", + ] + + def test_binops(self): + from zope.security.proxy import removeSecurityProxy + checker = DummyChecker() + for expr in self.binops: + first = 1 + for x in [1, self._makeOne(1, checker)]: + for y in [2, self._makeOne(2, checker)]: + if first: + z = eval(expr) + first = 0 + else: + self.assertEqual(removeSecurityProxy(eval(expr)), z, + "x=%r; y=%r; expr=%r" % (x, y, expr)) + class ProxyCTests(unittest.TestCase, ProxyTestBase): @@ -1328,7 +1347,6 @@ class ProxyPyTests(unittest.TestCase, ProxyTestBase): return ProxyPy def test_wrapper_checker_unaccessible(self): - from zope.security.proxy import _secret # Can't access '_wrapped' / '_checker' in C version target = object() checker = object() @@ -1337,13 +1355,13 @@ class ProxyPyTests(unittest.TestCase, ProxyTestBase): self.assertRaises(AttributeError, getattr, proxy, '_checker') def test_ctor_w_checker(self): - from zope.security.proxy import _secret + from zope.security.proxy import getObjectPy, getCheckerPy # Can't access '_wrapped' / '_checker' in C version target = object() checker = object() proxy = self._makeOne(target, checker) - self.assertTrue(getattr(proxy, '_wrapped'+_secret) is target) - self.assertTrue(getattr(proxy, '_checker'+_secret) is checker) + self.assertTrue(getObjectPy(proxy) is target) + self.assertTrue(getCheckerPy(proxy) is checker) def test___delattr___w__wrapped(self): target = object() @@ -1535,7 +1553,6 @@ class ProxyTests(unittest.TestCase): % (x.__class__.__module__, x.__class__.__name__)), s) - def testRepr(self): from zope.security.proxy import ProxyFactory self.assertEqual(repr(self.p), repr(self.x)) @@ -1826,6 +1843,7 @@ class ProxyTests(unittest.TestCase): a, b = coerce(x, y) self.assertTrue(type(removeSecurityProxy(a)) is float and b is y) + def test_using_mapping_slots_hack(): """The security proxy will use mapping slots, on the checker to go faster @@ -1920,12 +1938,14 @@ class LocationProxySecurityCheckerTests(unittest.TestCase): def test_suite(): - return unittest.TestSuite(( + suite = unittest.TestSuite(( unittest.makeSuite(ProxyPyTests), - unittest.makeSuite(ProxyCTests), unittest.makeSuite(Test_getTestProxyItems), unittest.makeSuite(Test_isinstance), # pre-geddon unittest.makeSuite(ProxyTests), unittest.makeSuite(LocationProxySecurityCheckerTests), )) + if not PYPY: + suite.addTest(unittest.makeSuite(ProxyCTests)) + return suite |