[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