[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