[Zope-Checkins] CVS: Zope/lib/python/AccessControl/tests - testZopeGuards.py:1.1.2.1 test_safeiter.py:1.1.2.1 testSecurity.py:1.10.6.1

Tres Seaver tseaver at zope.com
Thu Jan 8 15:12:38 EST 2004


Update of /cvs-repository/Zope/lib/python/AccessControl/tests
In directory cvs.zope.org:/tmp/cvs-serv29583/lib/python/AccessControl/tests

Modified Files:
      Tag: Zope-2_6-branch
	testSecurity.py 
Added Files:
      Tag: Zope-2_6-branch
	testZopeGuards.py test_safeiter.py 
Log Message:


  - Enforce new restrictions on untrusted code, identified during
    the December 2003 security audit.  These issues affect sites
    that allow untrusted users to write Python Scripts, Page Templates,
    and DTML:

    o 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.

    o 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.

    o Use of 'import as. in Python scripts could potentially rebind 
      names in ways that could be used to avoid appropriate security 
      checks.

    o A number of newer built-ins (min, max, enumerate, iter, sum)
      were either unavailable in untrusted code or did not perform
      adequate security checking.

    o 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.

    o DTMLMethods with proxy rights could incorrectly transfer those 
      rights via acquisition when traversing to a parent object.



=== 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.2.1 2004/01/08 20:12:07 tseaver Exp $
"""

import sys
import unittest
import ZODB
from AccessControl.ZopeGuards \
    import guarded_getattr, get_dict_get, get_dict_pop, get_list_pop, \
    get_iter, guarded_min, guarded_max, safe_builtins

class SecurityManager:

    def __init__(self, reject=0):
        self.calls = []
        self.reject = reject

    def validate(self, *args):
        from AccessControl import Unauthorized
        self.calls.append(('validate', args))
        if self.reject:
            raise Unauthorized
        return 1

    def validateValue(self, *args):
        from AccessControl import Unauthorized
        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 setUp(self):
        from AccessControl.SecurityManagement import noSecurityManager
        noSecurityManager()

    def tearDown(self):
        from AccessControl.SecurityManagement import noSecurityManager
        noSecurityManager()

    def setSecurityManager(self, manager):
        import AccessControl.SecurityManagement
        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 test_calls_validate_for_unknown_type(self):
        sm = SecurityManager()
        self.setSecurityManager(sm)
        guarded_getattr(self, 'test_calls_validate_for_unknown_type')
        self.assert_(sm.calls)

    def test_attr_handler_table(self):
        from AccessControl.SimpleObjectPolicies import ContainerAssertions
        from AccessControl import Unauthorized
        sm = SecurityManager()
        self.setSecurityManager(sm)
        d = {}
        _dict = type(d)
        old = ContainerAssertions.get(_dict)
        
        mytable = {'keys': 1,
                   'values': Method,
                   }
        ContainerAssertions[_dict] = mytable
        try:
            guarded_getattr(d, 'keys')
            self.assertEqual(len(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):
        from AccessControl.SecurityManagement import noSecurityManager
        sm = SecurityManager()
        self.setSecurityManager(sm)
        get = get_dict_get({'foo':GuardTestCase}, 'get')
        try:
            get('foo')
        finally:
            noSecurityManager()
        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):
        from AccessControl.SecurityManagement import noSecurityManager
        sm = SecurityManager()
        self.setSecurityManager(sm)
        pop = get_dict_get({'foo':GuardTestCase}, 'pop')
        try:
            pop('foo')
        finally:
            noSecurityManager()
        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):
            from AccessControl.SecurityManagement import noSecurityManager
            sm = SecurityManager()
            self.setSecurityManager(sm)
            iterkeys = get_iter({GuardTestCase: 1}, 'iterkeys')
            try:
                iterkeys().next()
            finally:
                noSecurityManager()
            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):
            from AccessControl.SecurityManagement import noSecurityManager
            sm = SecurityManager()
            self.setSecurityManager(sm)
            itervalues = get_iter({GuardTestCase: 1}, 'itervalues')
            try:
                itervalues().next()
            finally:
                noSecurityManager()
            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):
        from AccessControl.SecurityManagement import noSecurityManager
        sm = SecurityManager()
        self.setSecurityManager(sm)
        pop = get_list_pop([GuardTestCase], 'pop')
        try:
            pop()
        finally:
            noSecurityManager()
        self.assert_(sm.calls)
                

class TestMinMaxGuards(GuardTestCase):

    def test_min_fails(self):
        from AccessControl import Unauthorized
        sm = SecurityManager(1) # rejects
        self.setSecurityManager(sm)
        self.assertRaises(Unauthorized, guarded_min, [1,2,3])
        self.assertRaises(Unauthorized, guarded_min, 1,2,3)

    def test_max_fails(self):
        from AccessControl import Unauthorized
        sm = SecurityManager(1) # rejects
        self.setSecurityManager(sm)
        self.assertRaises(Unauthorized, guarded_max, [1,2,3])
        self.assertRaises(Unauthorized, guarded_max, 1,2,3)

    def test_min_succeeds(self):
        sm = SecurityManager() # accepts
        self.setSecurityManager(sm)
        self.assertEqual(guarded_min([1,2,3]), 1)
        self.assertEqual(guarded_min(1,2,3), 1)

    def test_max_succeeds(self):
        sm = SecurityManager() # accepts
        self.setSecurityManager(sm)
        self.assertEqual(guarded_max([1,2,3]), 3)
        self.assertEqual(guarded_max(1,2,3), 3)

class TestGuardedDictListTypes(unittest.TestCase):
    
    if sys.version_info >= (2, 2):
        def testDictCreation(self):
            d = safe_builtins['dict']
            self.assertEquals(d(), {})
            self.assertEquals(d({1:2}), {1:2})
            self.assertEquals(d(((1,2),)), {1:2})
            if sys.version_info >= (2, 3):
                # dict() didn't take keyword arguments before 2.3, and
                # the class constructor dict.fromkeys() didn't exist either.
                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'})
            else:
                self.assertRaises(AttributeError, getattr, d, 'fromkeys')
                try:
                    d(foo=1)
                except TypeError:
                    pass
                else:
                    self.fail("expected dict(foo=1) to raise TypeError")
    else:
        def testNoDictBuiltin(self):
            self.failIf(safe_builtins.has_key('dict'))
    
    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(x, [3,2,1])
        if sys.version_info >= (2, 4):
            self.assertEquals(l.sorted(x), [1,2,3])

def test_suite():
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestGuardedGetattr))
    suite.addTest(unittest.makeSuite(TestDictGuards))
    suite.addTest(unittest.makeSuite(TestMinMaxGuards))
    suite.addTest(unittest.makeSuite(TestListGuards))
    suite.addTest(unittest.makeSuite(TestGuardedDictListTypes))
    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.2.1 2004/01/08 20:12:07 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 = []
        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/testSecurity.py 1.10 => 1.10.6.1 ===
--- Zope/lib/python/AccessControl/tests/testSecurity.py:1.10	Wed Aug 14 17:28:08 2002
+++ Zope/lib/python/AccessControl/tests/testSecurity.py	Thu Jan  8 15:12:07 2004
@@ -11,18 +11,17 @@
 #
 ##############################################################################
 """Document Template Tests
-"""
 
-__rcs_id__='$Id$'
-__version__='$Revision$'[11:-2]
+$Id$
+"""
 
-import os, sys, unittest
+import unittest
 
 import ZODB
 from DocumentTemplate import HTML
 from DocumentTemplate.tests.testDTML import DTMLTests
 from Products.PythonScripts.standard import DTML
-from AccessControl import User, Unauthorized
+from AccessControl import Unauthorized
 from ExtensionClass import Base
 
 class UnownedDTML(DTML):
@@ -40,13 +39,8 @@
         doc = self.doc_class(
             '<dtml-with person>Hi, my name is '
             '<dtml-var name></dtml-with>')
-        try:
-            doc(person=person())
-        except Unauthorized:
-            # Passed the test.
-            pass
-        else:
-            assert 0, 'Did not protect class instance'
+
+        self.assertRaises(Unauthorized, doc, person=person)
 
     def testExprExplicitDeny(self):
         class myclass (Base):
@@ -56,7 +50,7 @@
                 return "This is a protected operation of public object"
 
         html = self.doc_class('<dtml-var expr="myinst.somemethod()">')
-        self.failUnlessRaises(Unauthorized, html, myinst=myclass())
+        self.assertRaises(Unauthorized, html, myinst=myclass())
 
     def testSecurityInSyntax(self):
         '''




More information about the Zope-Checkins mailing list