[Zope-Checkins] CVS: Zope/lib/python/AccessControl/tests -
actual_python.py:1.1.2.1 testBindings.py:1.1.4.1
testImplementation.py:1.1.2.1 testZopeGuards.py:1.1.4.1
test_safeiter.py:1.1.4.1 testDeprecatedAPI.py:1.5.14.2
testZopeSecurityPolicy.py:1.6.2.2
Tres Seaver
tseaver at zope.com
Thu Jan 8 18:34:15 EST 2004
Update of /cvs-repository/Zope/lib/python/AccessControl/tests
In directory cvs.zope.org:/tmp/cvs-serv30073/lib/python/AccessControl/tests
Modified Files:
Tag: Zope-2_7-branch
testDeprecatedAPI.py testZopeSecurityPolicy.py
Added Files:
Tag: Zope-2_7-branch
actual_python.py testBindings.py testImplementation.py
testZopeGuards.py test_safeiter.py
Log Message:
Merge security audit work for the 2.7 branch:
- Collector #1140: setting the access control implementation from
the configuration file didn't work. The ZOPE_SECURITY_POLICY
environment variable is no longer honored.
- Browsers that do not escape html in query strings such as
Internet Explorer 5.5 could potentially send a script tag in a
query string to the ZSearch interface for cross-site scripting.
- FilteredSets (used within TopicIndex) are defined via an expression,
which was naievely eval'ed.
- The ZTUtils SimpleTree decompressed tree state data from the
request without checking for final size, which could allow for
certain types of DoS attacks.
- Inadequate security assertions on administrative "find" methods
could potentially be abused.
- Some improper security assertions on DTMLDocument objects could
potentially allow access to members that should be protected.
- Class security was not properly intialized for PythonScripts,
potentially allowing access to variables that should be protected.
It turned out that most of the security assertions were in fact
activated as a side effect of other code, but this fix is still
appropriate to ensure that all security declarations are properly
applied.
- The dtml-tree tag used an "eval" of user-supplied data; its
efforts to prevent abuse were ineffective.
- XML-RPC marshalling of class instances used the instance
__dict__ to marshal the object, and could include attributes
prefixed with an underscore name. These attributes are considered
private in Zope and should generally not be disclosed.
- Some property types were stored in a mutable data type (list) which
could potentially allow untrusted code to effect changes on those
properties without going through appropriate security checks in
particular scenarios.
- Inadequate type checking could allow unicode values passed to
RESPONSE.write() to be passed into deeper layers of asyncore,
where an exception would eventually be generated at a level that
would cause the Zserver main loop to terminate.
- The variables bound to page templates and Python scripts such as
"context" and "container" were not checked adequately, allowing
a script to potentially access those objects without ensuring the
necessary permissions on the part of the executing user.
- Iteration over sequences could in some cases fail to check access
to an object obtained from the sequence. Subsequent checks (such
as for attributes access) of such an object would still be
performed, but it should not have been possible to obtain the
object in the first place.
- List and dictionary instance methods such as the get method of
dictionary objects were not security aware and could return an
object without checking access to that object. Subsequent checks
(such as for attributes access) of such an object would still be
performed, but it should not have been possible to obtain the
object in the first place.
- Use of 'import as. in Python scripts could potentially rebind
names in ways that could be used to avoid appropriate security
checks.
- A number of newer built-ins (min, max, enumerate, iter, sum)
were either unavailable in untrusted code or did not perform
adequate security checking.
- Unpacking via function calls, variable assignment, exception
variables and other contexts did not perform adequate security
checks, potentially allowing access to objects that should have
been protected.
- DTMLMethods with proxy rights could incorrectly transfer those
rights via acquisition when traversing to a parent object.
=== Added File Zope/lib/python/AccessControl/tests/actual_python.py ===
# The code in this file is executed after being compiled as restricted code,
# and given a globals() dict with our idea of safe builtins, and the
# Zope production implementations of the special restricted-Python functions
# (like _getitem_ and _getiter_, etc).
#
# This isn't trying to provoke security problems, it's just trying to verify
# that Python code continues to work as intended after all the transformations,
# and with all the special wrappers we supply.
def f1():
next = iter(xrange(3)).next
assert next() == 0
assert next() == 1
assert next() == 2
try:
next()
except StopIteration:
pass
else:
assert 0, "expected StopIteration"
f1()
def f2():
assert map(lambda x: x+1, range(3)) == range(1, 4)
f2()
def f3():
assert filter(None, range(10)) == range(1, 10)
f3()
def f4():
assert [i+1 for i in range(3)] == range(*(1, 4))
f4()
def f5():
x = range(5)
def add(a, b):
return a+b
assert sum(x) == reduce(add, x, 0)
f5()
def f6():
class C:
def display(self):
return str(self.value)
c1 = C()
c2 = C()
# XXX Oops -- it's apparently against the rules to create a new
# XXX attribute. Trying to yields
# XXX TypeError: attribute-less object (assign or del)
## c1.value = 12
## assert getattr(c1, 'value') == 12
## assert c1.display() == '12'
assert not hasattr(c2, 'value')
## setattr(c2, 'value', 34)
## assert c2.value == 34
## assert hasattr(c2, 'value')
## del c2.value
assert not hasattr(c2, 'value')
# OK, if we can't set new attributes, at least verify that we can't.
try:
c1.value = 12
except TypeError:
pass
else:
assert 0, "expected direct attribute creation to fail"
try:
setattr(c1, 'value', 12)
except TypeError:
pass
else:
assert 0, "expected indirect attribute creation to fail"
assert getattr(C, "display", None) == getattr(C, "display")
try:
setattr(C, "display", lambda self: "replaced")
except TypeError:
pass
else:
assert 0, "expected setattr() attribute replacement to fail"
try:
delattr(C, "display")
except TypeError:
pass
else:
assert 0, "expected delattr() attribute deletion to fail"
f6()
def f7():
d = apply(dict, [((1, 2), (3, 4))]) # {1: 2, 3: 4}
expected = {'k': [1, 3],
'v': [2, 4],
'i': [(1, 2), (3, 4)]}
for meth, kind in [('iterkeys', 'k'),
('iteritems', 'i'),
('itervalues', 'v'),
('keys', 'k'),
('items', 'i'),
('values', 'v')]:
access = getattr(d, meth)
result = list(access())
result.sort()
assert result == expected[kind], (meth, kind, result, expected[kind])
f7()
def f8():
import math
ceil = getattr(math, 'ceil')
smallest = 1e100
smallest_index = None
largest = -1e100
largest_index = None
all = []
for i, x in enumerate((2.2, 1.1, 3.3, 5.5, 4.4)):
all.append(x)
effective = ceil(x)
if effective < smallest:
assert min(effective, smallest) == effective
smallest = effective
smallest_index = i
if effective > largest:
assert max(effective, largest) == effective
largest = effective
largest_index = i
assert smallest == 2
assert smallest_index == 1
assert largest == 6
assert largest_index == 3
assert min([ceil(x) for x in all]) == smallest
assert max(map(ceil, all)) == largest
f8()
# After all the above, these wrappers were still untouched:
# ['DateTime', '_print_', 'reorder', 'same_type', 'test']
# So do something to touch them.
def f9():
d = DateTime()
print d # this one provoked _print_
# Funky. This probably isn't an intended use of reorder, but I'm
# not sure why it exists.
assert reorder('edcbaxyz', 'abcdef', 'c') == zip('abde', 'abde')
assert test(0, 'a', 0, 'b', 1, 'c', 0, 'd') == 'c'
assert test(0, 'a', 0, 'b', 0, 'c', 0, 'd', 'e') == 'e'
# Unclear that the next one is *intended* to return None (it falls off
# the end of test's implementation without explicitly returning anything).
assert test(0, 'a', 0, 'b', 0, 'c', 0, 'd') == None
assert same_type(3, 2, 1), 'expected same type'
assert not same_type(3, 2, 'a'), 'expected not same type'
f9()
=== Added File Zope/lib/python/AccessControl/tests/testBindings.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test Bindings
$Id: testBindings.py,v 1.1.4.1 2004/01/08 23:33:44 tseaver Exp $
"""
import unittest
import ZODB
import Zope
import AccessControl.SecurityManagement
from AccessControl import Unauthorized
from Testing.makerequest import makerequest
from Products.PythonScripts.PythonScript import PythonScript
class TransactionalTest( unittest.TestCase ):
def setUp( self ):
if hasattr(Zope, 'startup'):
Zope.startup()
get_transaction().begin()
self.connection = Zope.DB.open()
self.root = self.connection.root()[ 'Application' ]
def tearDown( self ):
get_transaction().abort()
self.connection.close()
class RequestTest( TransactionalTest ):
def setUp(self):
TransactionalTest.setUp(self)
root = self.root = makerequest(self.root)
self.REQUEST = root.REQUEST
self.RESPONSE = root.REQUEST.RESPONSE
class SecurityManager:
def __init__(self, reject=0):
self.calls = []
self.reject = reject
def validate(self, *args):
self.calls.append(('validate', args))
if self.reject:
raise Unauthorized
return 1
def validateValue(self, *args):
self.calls.append(('validateValue', args))
if self.reject:
raise Unauthorized
return 1
def checkPermission(self, *args):
self.calls.append(('checkPermission', args))
return not self.reject
def addContext(self, *args):
self.calls.append(('addContext', args))
return 1
def removeContext(self, *args):
self.calls.append(('removeContext', args))
return 1
class GuardTestCase(RequestTest):
def setSecurityManager(self, manager):
key = AccessControl.SecurityManagement.get_ident()
old = AccessControl.SecurityManagement._managers.get(key)
if manager is None:
del AccessControl.SecurityManagement._managers[key]
else:
AccessControl.SecurityManagement._managers[key] = manager
return old
class TestBindings(GuardTestCase):
def setUp(self):
RequestTest.setUp(self)
self.sm = SecurityManager(reject=1)
self.old = self.setSecurityManager(self.sm)
def tearDown(self):
self.setSecurityManager(self.old)
TransactionalTest.tearDown(self)
def _newPS(self, txt, bind=None):
ps = PythonScript('ps')
#ps.ZBindings_edit(bind or {})
ps.write(txt)
ps._makeFunction()
return ps
def test_fail_container(self):
container_ps = self._newPS('return container')
self.root._setOb('container_ps', container_ps)
container_ps = self.root._getOb('container_ps')
self.assertRaises(Unauthorized, container_ps)
def test_fail_context(self):
context_ps = self._newPS('return context')
self.root._setOb('context_ps', context_ps)
context_ps = self.root._getOb('context_ps')
self.assertRaises(Unauthorized, context_ps)
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestBindings))
return suite
if __name__ == '__main__':
unittest.main()
=== Added File Zope/lib/python/AccessControl/tests/testImplementation.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test of the implementation selection support."""
import unittest
from AccessControl.Implementation import getImplementationName
from AccessControl.Implementation import setImplementation
class AccessControlImplementationTest(unittest.TestCase):
have_cAccessControl = None
def setUp(self):
if self.have_cAccessControl is None:
try:
import AccessControl.cAccessControl
except ImportError:
v = False
else:
v = True
self.__class__.have_cAccessControl = v
self.original = getImplementationName()
def tearDown(self):
setImplementation(self.original)
def test_setImplemenationC(self):
setImplementation("C")
name = getImplementationName()
if self.have_cAccessControl:
self.assertEqual(name, "C")
else:
self.assertEqual(name, "PYTHON")
def test_setImplemenationPython(self):
setImplementation("Python")
self.assertEqual(getImplementationName(), "PYTHON")
def test_suite():
return unittest.makeSuite(AccessControlImplementationTest)
if __name__ == "__main__":
unittest.main(defaultTest="test_suite")
=== Added File Zope/lib/python/AccessControl/tests/testZopeGuards.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test Zope Guards
Well, at least begin testing some of the functionality
$Id: testZopeGuards.py,v 1.1.4.1 2004/01/08 23:33:44 tseaver Exp $
"""
import os, sys
import unittest
import ZODB
import AccessControl.SecurityManagement
from AccessControl.SimpleObjectPolicies import ContainerAssertions
from AccessControl import Unauthorized
from AccessControl.ZopeGuards \
import guarded_getattr, get_dict_get, get_dict_pop, get_list_pop, \
get_iter, guarded_min, guarded_max, safe_builtins, guarded_enumerate, \
guarded_sum, guarded_apply
try:
__file__
except NameError:
__file__ = os.path.abspath(sys.argv[1])
_FILEPATH = os.path.abspath( __file__ )
_HERE = os.path.dirname( _FILEPATH )
class SecurityManager:
def __init__(self, reject=0):
self.calls = []
self.reject = reject
def validate(self, *args):
self.calls.append(('validate', args))
if self.reject:
raise Unauthorized
return 1
def validateValue(self, *args):
self.calls.append(('validateValue', args))
if self.reject:
raise Unauthorized
return 1
def checkPermission(self, *args):
self.calls.append(('checkPermission', args))
return not self.reject
class GuardTestCase(unittest.TestCase):
def setSecurityManager(self, manager):
key = AccessControl.SecurityManagement.get_ident()
old = AccessControl.SecurityManagement._managers.get(key)
if manager is None:
del AccessControl.SecurityManagement._managers[key]
else:
AccessControl.SecurityManagement._managers[key] = manager
return old
class Method:
def __init__(self, *args):
self.args = args
class TestGuardedGetattr(GuardTestCase):
def setUp(self):
self.__sm = SecurityManager()
self.__old = self.setSecurityManager(self.__sm)
def tearDown(self):
self.setSecurityManager(self.__old)
def test_calls_validate_for_unknown_type(self):
guarded_getattr(self, 'test_calls_validate_for_unknown_type')
self.assert_(self.__sm.calls)
def test_attr_handler_table(self):
d = {}
_dict = type(d)
old = ContainerAssertions.get(_dict)
mytable = {'keys': 1,
'values': Method,
}
ContainerAssertions[_dict] = mytable
try:
guarded_getattr(d, 'keys')
self.assertEqual(len(self.__sm.calls), 0)
values = guarded_getattr(d, 'values')
self.assertEqual(values.__class__, Method)
self.assertEqual(values.args, (d, 'values'))
self.assertRaises(Unauthorized, guarded_getattr, d, 'items')
finally:
ContainerAssertions[_dict] = old
class TestDictGuards(GuardTestCase):
def test_get_simple(self):
get = get_dict_get({'foo': 'bar'}, 'get')
self.assertEqual(get('foo'), 'bar')
def test_get_default(self):
get = get_dict_get({'foo': 'bar'}, 'get')
self.failUnless(get('baz') is None)
self.assertEqual(get('baz', 'splat'), 'splat')
def test_get_validates(self):
sm = SecurityManager()
old = self.setSecurityManager(sm)
get = get_dict_get({'foo':GuardTestCase}, 'get')
try:
get('foo')
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
def test_pop_simple(self):
pop = get_dict_pop({'foo': 'bar'}, 'pop')
self.assertEqual(pop('foo'), 'bar')
def test_pop_raises(self):
pop = get_dict_pop({'foo': 'bar'}, 'pop')
self.assertRaises(KeyError, pop, 'baz')
def test_pop_default(self):
pop = get_dict_pop({'foo': 'bar'}, 'pop')
self.assertEqual(pop('baz', 'splat'), 'splat')
def test_pop_validates(self):
sm = SecurityManager()
old = self.setSecurityManager(sm)
pop = get_dict_get({'foo':GuardTestCase}, 'pop')
try:
pop('foo')
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
if sys.version_info >= (2, 2):
def test_iterkeys_simple(self):
d = {'foo':1, 'bar':2, 'baz':3}
iterkeys = get_iter(d, 'iterkeys')
keys = d.keys()
keys.sort()
ikeys = list(iterkeys())
ikeys.sort()
self.assertEqual(keys, ikeys)
def test_iterkeys_empty(self):
iterkeys = get_iter({}, 'iterkeys')
self.assertEqual(list(iterkeys()), [])
def test_iterkeys_validates(self):
sm = SecurityManager()
old = self.setSecurityManager(sm)
iterkeys = get_iter({GuardTestCase: 1}, 'iterkeys')
try:
iterkeys().next()
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
def test_itervalues_simple(self):
d = {'foo':1, 'bar':2, 'baz':3}
itervalues = get_iter(d, 'itervalues')
values = d.values()
values.sort()
ivalues = list(itervalues())
ivalues.sort()
self.assertEqual(values, ivalues)
def test_itervalues_empty(self):
itervalues = get_iter({}, 'itervalues')
self.assertEqual(list(itervalues()), [])
def test_itervalues_validates(self):
sm = SecurityManager()
old = self.setSecurityManager(sm)
itervalues = get_iter({GuardTestCase: 1}, 'itervalues')
try:
itervalues().next()
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
class TestListGuards(GuardTestCase):
def test_pop_simple(self):
pop = get_list_pop(['foo', 'bar', 'baz'], 'pop')
self.assertEqual(pop(), 'baz')
self.assertEqual(pop(0), 'foo')
def test_pop_raises(self):
pop = get_list_pop([], 'pop')
self.assertRaises(IndexError, pop)
def test_pop_validates(self):
sm = SecurityManager()
old = self.setSecurityManager(sm)
pop = get_list_pop([GuardTestCase], 'pop')
try:
pop()
finally:
self.setSecurityManager(old)
self.assert_(sm.calls)
class TestBuiltinFunctionGuards(GuardTestCase):
def test_min_fails(self):
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_min, [1,2,3])
self.assertRaises(Unauthorized, guarded_min, 1,2,3)
self.setSecurityManager(old)
def test_max_fails(self):
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_max, [1,2,3])
self.assertRaises(Unauthorized, guarded_max, 1,2,3)
self.setSecurityManager(old)
def test_enumerate_fails(self):
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
enum = guarded_enumerate([1,2,3])
self.assertRaises(Unauthorized, enum.next)
self.setSecurityManager(old)
def test_sum_fails(self):
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
self.assertRaises(Unauthorized, guarded_sum, [1,2,3])
self.setSecurityManager(old)
def test_min_succeeds(self):
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_min([1,2,3]), 1)
self.assertEqual(guarded_min(1,2,3), 1)
self.setSecurityManager(old)
def test_max_succeeds(self):
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_max([1,2,3]), 3)
self.assertEqual(guarded_max(1,2,3), 3)
self.setSecurityManager(old)
def test_enumerate_succeeds(self):
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
enum = guarded_enumerate([1,2,3])
self.assertEqual(enum.next(), (0,1))
self.assertEqual(enum.next(), (1,2))
self.assertEqual(enum.next(), (2,3))
self.assertRaises(StopIteration, enum.next)
self.setSecurityManager(old)
def test_sum_succeeds(self):
sm = SecurityManager() # accepts
old = self.setSecurityManager(sm)
self.assertEqual(guarded_sum([1,2,3]), 6)
self.assertEqual(guarded_sum([1,2,3], start=36), 42)
self.setSecurityManager(old)
def test_apply(self):
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
gapply = safe_builtins['apply']
def f(a=1, b=2):
return a+b
# This one actually succeeds, because apply isn't given anything
# to unpack.
self.assertEqual(gapply(f), 3)
# Likewise, because the things passed are empty.
self.assertEqual(gapply(f, (), {}), 3)
self.assertRaises(Unauthorized, gapply, f, [1])
self.assertRaises(Unauthorized, gapply, f, (), {'a': 2})
self.assertRaises(Unauthorized, gapply, f, [1], {'a': 2})
sm = SecurityManager(0) # accepts
self.setSecurityManager(sm)
self.assertEqual(gapply(f), 3)
self.assertEqual(gapply(f, (), {}), 3)
self.assertEqual(gapply(f, [0]), 2)
self.assertEqual(gapply(f, [], {'b': 18}), 19)
self.assertEqual(gapply(f, [10], {'b': 1}), 11)
self.setSecurityManager(old)
class TestGuardedDictListTypes(unittest.TestCase):
def testDictCreation(self):
d = safe_builtins['dict']
self.assertEquals(d(), {})
self.assertEquals(d({1:2}), {1:2})
self.assertEquals(d(((1,2),)), {1:2})
self.assertEquals(d(foo=1), {"foo":1})
self.assertEquals(d.fromkeys((1,2,3)), {1:None, 2:None, 3:None})
self.assertEquals(d.fromkeys((1,2,3), 'f'), {1:'f', 2:'f', 3:'f'})
def testListCreation(self):
l = safe_builtins['list']
self.assertEquals(l(), [])
self.assertEquals(l([1,2,3]), [1,2,3])
x = [3,2,1]
self.assertEquals(l(x), [3,2,1])
if sys.version_info >= (2, 4):
self.assertEquals(l.sorted(x), [1,2,3])
class TestRestrictedPythonApply(GuardTestCase):
def test_apply(self):
sm = SecurityManager(1) # rejects
old = self.setSecurityManager(sm)
gapply = guarded_apply
def f(a=1, b=2):
return a+b
# This one actually succeeds, because apply isn't given anything
# to unpack.
self.assertEqual(gapply(*(f,)), 3)
# Likewise, because the things passed are empty.
self.assertEqual(gapply(*(f,), **{}), 3)
self.assertRaises(Unauthorized, gapply, *(f, 1))
self.assertRaises(Unauthorized, gapply, *(f,), **{'a': 2})
self.assertRaises(Unauthorized, gapply, *(f, 1), **{'a': 2})
sm = SecurityManager(0) # accepts
self.setSecurityManager(sm)
self.assertEqual(gapply(*(f,)), 3)
self.assertEqual(gapply(*(f,), **{}), 3)
self.assertEqual(gapply(*(f, 0)), 2)
self.assertEqual(gapply(*(f,), **{'b': 18}), 19)
self.assertEqual(gapply(*(f, 10), **{'b': 1}), 11)
self.setSecurityManager(old)
# Map function name to the # of times it's been called.
wrapper_count = {}
class FuncWrapper:
def __init__(self, funcname, func):
self.funcname = funcname
wrapper_count[funcname] = 0
self.func = func
def __call__(self, *args, **kws):
wrapper_count[self.funcname] += 1
return self.func(*args, **kws)
def __repr__(self):
return "<FuncWrapper around %r>" % self.func
# Given the high wall between AccessControl and RestrictedPython, I suppose
# the next one could be called an integration test. But we're simply
# trying to run restricted Python with the *intended* implementations of
# the special wrappers here, so no apologies.
class TestActualPython(GuardTestCase):
def testPython(self):
from RestrictedPython.tests import verify
code, its_globals = self._compile("actual_python.py")
verify.verify(code)
# Fiddle the global and safe-builtins dicts to count how many times
# the special functions are called.
self._wrap_replaced_dict_callables(its_globals)
self._wrap_replaced_dict_callables(its_globals['__builtins__'])
sm = SecurityManager()
old = self.setSecurityManager(sm)
try:
exec code in its_globals
finally:
self.setSecurityManager(old)
# Use wrapper_count to determine coverage.
## print wrapper_count # uncomment to see wrapper names & counts
untouched = [k for k, v in wrapper_count.items() if v == 0]
if untouched:
untouched.sort()
self.fail("Unexercised wrappers: %r" % untouched)
# Compile code in fname, as restricted Python. Return the
# compiled code, and a safe globals dict for running it in.
# fname is the string name of a Python file; it must be found
# in the same directory as this file.
def _compile(self, fname):
from RestrictedPython import compile_restricted
from AccessControl.ZopeGuards import get_safe_globals, guarded_getattr
fn = os.path.join( _HERE, fname)
code = compile_restricted(open(fn).read(), fn, 'exec')
g = get_safe_globals()
g['_getattr_'] = guarded_getattr
g['__debug__'] = 1 # so assert statements are active
g['__name__'] = __name__ # so classes can be defined in the script
return code, g
# d is a dict, the globals for execution or our safe builtins.
# The callable values which aren't the same as the corresponding
# entries in __builtin__ are wrapped in a FuncWrapper, so we can
# tell whether they're executed.
def _wrap_replaced_dict_callables(self, d):
import __builtin__
for k, v in d.items():
if callable(v) and v is not getattr(__builtin__, k, None):
d[k] = FuncWrapper(k, v)
def test_suite():
suite = unittest.TestSuite()
for cls in (TestGuardedGetattr,
TestDictGuards,
TestBuiltinFunctionGuards,
TestListGuards,
TestGuardedDictListTypes,
TestRestrictedPythonApply,
TestActualPython,
):
suite.addTest(unittest.makeSuite(cls))
return suite
if __name__ == '__main__':
unittest.main()
=== Added File Zope/lib/python/AccessControl/tests/test_safeiter.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Tests for the guarded iterartor.
$Id: test_safeiter.py,v 1.1.4.1 2004/01/08 23:33:44 tseaver Exp $
"""
import unittest
# Persistence system must be initialized.
import ZODB
from AccessControl import ZopeGuards
class SafeIterTestCase(unittest.TestCase):
# XXX these tests replace the global guard() function in
# AccessControl.ZopeGuards; this is not the nicest way to check
# that things work, but avoids making the SafeIter unit tests from
# testing things other than the guarded iterator itself. In
# particular, it avoids testing the actual guard checks, which
# should be tested separately.
def setUp(self):
self.original_guard = ZopeGuards.guard
ZopeGuards.guard = self.guard
self.checks = []
def tearDown(self):
ZopeGuards.guard = self.original_guard
def guard(self, container, value, index=None):
self.checks.append((id(container), value))
def test_iteration(self):
seq = [1, 2, 3]
seqid = id(seq)
it = ZopeGuards.SafeIter(seq)
self.assertEqual(list(it), seq)
self.assertEqual(self.checks, [(seqid, 1),
(seqid, 2),
(seqid, 3)])
def test_iteration_with_container(self):
seq = [1, 2, 3]
container = object()
contid = id(container)
it = ZopeGuards.SafeIter(seq, container)
self.assertEqual(list(it), seq)
self.assertEqual(self.checks, [(contid, 1),
(contid, 2),
(contid, 3)])
def test_suite():
return unittest.makeSuite(SafeIterTestCase)
=== Zope/lib/python/AccessControl/tests/testDeprecatedAPI.py 1.5.14.1 => 1.5.14.2 ===
--- Zope/lib/python/AccessControl/tests/testDeprecatedAPI.py:1.5.14.1 Thu Dec 18 15:34:09 2003
+++ Zope/lib/python/AccessControl/tests/testDeprecatedAPI.py Thu Jan 8 18:33:44 2004
@@ -19,7 +19,6 @@
__rcs_id__='$Id$'
__version__='$Revision$'[11:-2]
-import ZODB # Sigh. Persistent needs to be set, so we import ZODB.
from AccessControl import User
import unittest, warnings
=== Zope/lib/python/AccessControl/tests/testZopeSecurityPolicy.py 1.6.2.1 => 1.6.2.2 ===
--- Zope/lib/python/AccessControl/tests/testZopeSecurityPolicy.py:1.6.2.1 Thu Oct 23 21:25:54 2003
+++ Zope/lib/python/AccessControl/tests/testZopeSecurityPolicy.py Thu Jan 8 18:33:44 2004
@@ -37,8 +37,11 @@
class App(Explicit):
- pass
-
+ def unrestrictedTraverse(self, path):
+ ob = self
+ for el in path:
+ ob = getattr(ob, el)
+ return ob
class PublicMethod (Method):
def getOwner(self):
@@ -61,12 +64,22 @@
class setuidMethod (PublicMethod):
_proxy_roles = sysadmin_roles
+
+class OwnedSetuidMethod(Implicit):
+ __roles__ = eo_roles
+ _proxy_roles = sysadmin_roles
+
+ def getOwner(self, info=0):
+ if info:
+ return (('subobject', 'acl_users'), 'theowner')
+ else:
+ return self.aq_parent.aq_parent.acl_users.getUserById('theowner')
+
class DangerousMethod (PublicMethod):
# Only accessible to sysadmin or people who use proxy roles
__roles__ = sysadmin_roles
-
class SimpleItemish (Implicit):
public_m = PublicMethod()
protected_m = ProtectedMethod()
@@ -75,6 +88,9 @@
dangerous_m = DangerousMethod()
public_prop = 'Public Value'
private_prop = 'Private Value'
+
+class ImplictAcqObject(Implicit):
+ pass
class UnprotectedSimpleItem (SimpleItemish):
@@ -82,6 +98,14 @@
__allow_access_to_unprotected_subobjects__ = 1
+class OwnedSimpleItem(UnprotectedSimpleItem):
+ def getOwner(self, info=0):
+ if info:
+ return (('subobject', 'acl_users'), 'theowner')
+ else:
+ return self.aq_parent.acl_users.getuserById('theowner')
+
+
class RestrictedSimpleItem (SimpleItemish):
__allow_access_to_unprotected_subobjects__ = 0
@@ -246,6 +270,35 @@
'', '', name, '', None)
else:
policy.validate('', '', name, '', None)
+
+ def testProxyRoleScope(self):
+ self.a.subobject = ImplictAcqObject()
+ subobject = self.a.subobject
+ subobject.acl_users = UserFolder()
+ subobject.acl_users._addUser('theowner', 'password', 'password',
+ eo_roles + sysadmin_roles, ())
+ subobject.item = UnprotectedSimpleItem()
+ subitem = subobject.item
+ subitem.owned_setuid_m = OwnedSetuidMethod()
+ subitem.getPhysicalRoot = lambda root=self.a: root
+
+ item = self.a.item
+ item.getPhysicalRoot = lambda root=self.a: root
+ self.context.stack.append(subitem.owned_setuid_m.__of__(subitem))
+
+ # Out of owner context
+ self.assertPolicyAllows(item, 'public_m')
+ self.assertPolicyDenies(item, 'protected_m')
+ self.assertPolicyDenies(item, 'owned_m')
+ self.assertPolicyAllows(item, 'setuid_m')
+ self.assertPolicyDenies(item, 'dangerous_m')
+
+ # Inside owner context
+ self.assertPolicyAllows(subitem, 'public_m')
+ self.assertPolicyDenies(subitem, 'protected_m')
+ self.assertPolicyDenies(subitem, 'owned_m')
+ self.assertPolicyAllows(subitem, 'setuid_m')
+ self.assertPolicyAllows(subitem, 'dangerous_m')
if 0:
# This test purposely generates a log entry.
@@ -268,12 +321,7 @@
def test_suite():
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(ZopeSecurityPolicyTests, 'test'))
- return suite
-
-def main():
- unittest.TextTestRunner().run(test_suite())
+ return unittest.makeSuite(ZopeSecurityPolicyTests)
if __name__ == '__main__':
- main()
+ unittest.main(defaultTest="test_suite")
More information about the Zope-Checkins
mailing list