Commit eabd6a8b authored by Tres Seaver's avatar Tres Seaver

LP #281156: 'AccessControl.SecurityInfo.secureModule' dropped ModuleSecurity

for failed imports, obscuring later attempts to import the same broken module.

'AccessControl.ZopeGuards.guarded_import' mapped some Unauthorized exceptions
onto ImportErrors:  don't do that!  Also, removed mutable defaults from
argument list, improved tests.
parent 1c6e27a2
...@@ -8,6 +8,14 @@ Zope Changes ...@@ -8,6 +8,14 @@ Zope Changes
Bugs fixed Bugs fixed
- 'AccessControl.ZopeGuards.guarded_import' mapped some Unauthorized
exceptions onto ImportErrors: don't do that! Also, removed
mutable defaults from argument list, improved tests.
- LP #281156: 'AccessControl.SecurityInfo.secureModule' dropped
ModuleSecurity for failed imports, obscuring later attempts to
import the same broken module.
- LP #142667: Updated to ZODB-3.7.3 to fix problem with product - LP #142667: Updated to ZODB-3.7.3 to fix problem with product
auto-refresh. auto-refresh.
......
...@@ -208,10 +208,10 @@ def secureModule(mname, *imp): ...@@ -208,10 +208,10 @@ def secureModule(mname, *imp):
modsec = _moduleSecurity.get(mname, None) modsec = _moduleSecurity.get(mname, None)
if modsec is None: if modsec is None:
return return
del _moduleSecurity[mname]
if imp: if imp:
__import__(mname, *imp) __import__(mname, *imp)
del _moduleSecurity[mname]
module = sys.modules[mname] module = sys.modules[mname]
modsec.apply(module.__dict__) modsec.apply(module.__dict__)
_appliedModuleSecurity[mname] = modsec _appliedModuleSecurity[mname] = modsec
......
...@@ -259,19 +259,24 @@ def guarded_map(f, *seqs): ...@@ -259,19 +259,24 @@ def guarded_map(f, *seqs):
return map(f, *safe_seqs) return map(f, *safe_seqs)
safe_builtins['map'] = guarded_map safe_builtins['map'] = guarded_map
def guarded_import(mname, globals={}, locals={}, fromlist=None): def guarded_import(mname, globals=None, locals=None, fromlist=None):
if fromlist is None:
fromlist = ()
if '*' in fromlist:
raise Unauthorized, "'from %s import *' is not allowed"
if globals is None:
globals = {}
if locals is None:
locals = {}
mnameparts = mname.split('.') mnameparts = mname.split('.')
firstmname = mnameparts[0] firstmname = mnameparts[0]
validate = getSecurityManager().validate validate = getSecurityManager().validate
module = load_module(None, None, mnameparts, validate, globals, locals) module = load_module(None, None, mnameparts, validate, globals, locals)
if module is not None: if module is None:
raise Unauthorized, "import of '%s' is unauthorized" % mname
if fromlist is None: if fromlist is None:
fromlist = () fromlist = ()
try:
for name in fromlist: for name in fromlist:
if name == '*':
raise ImportError, ('"from %s import *" is not allowed'
% mname)
v = getattr(module, name, None) v = getattr(module, name, None)
if v is None: if v is None:
v = load_module(module, mname, [name], validate, v = load_module(module, mname, [name], validate,
...@@ -280,10 +285,6 @@ def guarded_import(mname, globals={}, locals={}, fromlist=None): ...@@ -280,10 +285,6 @@ def guarded_import(mname, globals={}, locals={}, fromlist=None):
raise Unauthorized raise Unauthorized
else: else:
return __import__(mname, globals, locals, fromlist) return __import__(mname, globals, locals, fromlist)
except Unauthorized, why:
raise ImportError, ('import of "%s" from "%s" is unauthorized. %s'
% (name, mname, why))
raise ImportError, 'import of "%s" is unauthorized' % mname
safe_builtins['__import__'] = guarded_import safe_builtins['__import__'] = guarded_import
class GuardedListType: class GuardedListType:
......
############################################################################## ##############################################################################
# #
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved. # Copyright (c) 2008 Zope Corporation and Contributors. All Rights Reserved.
# #
# This software is subject to the provisions of the Zope Public License, # This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
...@@ -10,51 +10,44 @@ ...@@ -10,51 +10,44 @@
# FOR A PARTICULAR PURPOSE # FOR A PARTICULAR PURPOSE
# #
############################################################################## ##############################################################################
"""Module Import Tests import unittest
"""
__rcs_id__='$Id$' class ModuleSecurityTests(unittest.TestCase):
__version__='$Revision: 1.4 $'[11:-2]
import os, sys, unittest def setUp(self):
from AccessControl import ModuleSecurityInfo as MSI
MSI('AccessControl.tests.mixed_module').declarePublic('pub')
MSI('AccessControl.tests.public_module').declarePublic('pub')
MSI('AccessControl.tests.public_module.submodule').declarePublic('pub')
import Testing def tearDown(self):
import ZODB import sys
from AccessControl import User for module in ('AccessControl.tests.public_module',
from AccessControl import Unauthorized, ModuleSecurityInfo 'AccessControl.tests.public_module.submodule',
from AccessControl.ZopeGuards import guarded_import 'AccessControl.tests.mixed_module',
'AccessControl.tests.mixed_module.submodule',
ModuleSecurityInfo('AccessControl.tests.mixed_module').declarePublic('pub') 'AccessControl.tests.private_module',
'AccessControl.tests.private_module.submodule',
ModuleSecurityInfo('AccessControl.tests.public_module').declarePublic('pub') ):
ModuleSecurityInfo('AccessControl.tests.public_module.submodule' if module in sys.modules:
).declarePublic('pub') del sys.modules[module]
class SecurityTests(unittest.TestCase):
def assertUnauth(self, module, fromlist): def assertUnauth(self, module, fromlist):
try: from zExceptions import Unauthorized
guarded_import(module, fromlist=fromlist) from AccessControl.ZopeGuards import guarded_import
except (Unauthorized, ImportError): self.assertRaises(Unauthorized,
# Passed the test. guarded_import, module, fromlist=fromlist)
pass
else:
assert 0, ('Did not protect module instance %s, %s' %
(`module`, `fromlist`))
def assertAuth(self, module, fromlist): def assertAuth(self, module, fromlist):
try: from AccessControl.ZopeGuards import guarded_import
guarded_import(module, fromlist=fromlist) guarded_import(module, fromlist=fromlist)
except (Unauthorized, ImportError):
assert 0, ('Did not expose module instance %s, %s' %
(`module`, `fromlist`))
def testPrivateModule(self): def testPrivateModule(self):
for name in '', '.submodule': self.assertUnauth('AccessControl.tests.private_module', ())
for fromlist in (), ('priv',): self.assertUnauth('AccessControl.tests.private_module', ('priv',))
self.assertUnauth( self.assertUnauth('AccessControl.tests.private_module.submodule', ())
'AccessControl.tests.private_module%s' % name, self.assertUnauth('AccessControl.tests.private_module.submodule',
fromlist) ('priv',))
def testMixedModule(self): def testMixedModule(self):
self.assertAuth('AccessControl.tests.mixed_module', ()) self.assertAuth('AccessControl.tests.mixed_module', ())
...@@ -63,19 +56,25 @@ class SecurityTests(unittest.TestCase): ...@@ -63,19 +56,25 @@ class SecurityTests(unittest.TestCase):
self.assertUnauth('AccessControl.tests.mixed_module.submodule', ()) self.assertUnauth('AccessControl.tests.mixed_module.submodule', ())
def testPublicModule(self): def testPublicModule(self):
for name in '', '.submodule': self.assertAuth('AccessControl.tests.public_module', ())
for fromlist in (), ('pub',): self.assertAuth('AccessControl.tests.public_module', ('pub',))
self.assertAuth( self.assertAuth('AccessControl.tests.public_module.submodule', ())
'AccessControl.tests.public_module%s' % name, self.assertAuth('AccessControl.tests.public_module.submodule',
fromlist) ('pub',))
def test_suite(): def test_public_module_asterisk_not_allowed(self):
suite = unittest.TestSuite() self.assertUnauth('AccessControl.tests.public_module', ('*',))
suite.addTest( unittest.makeSuite( SecurityTests ) )
return suite
def main(): def test_failed_import_keeps_MSI(self):
unittest.TextTestRunner().run(test_suite()) # LP #281156
from AccessControl import ModuleSecurityInfo as MSI
from AccessControl.SecurityInfo import _moduleSecurity as MS
from AccessControl.ZopeGuards import guarded_import
MSI('AccessControl.tests.nonesuch').declarePublic('pub')
self.failUnless('AccessControl.tests.nonesuch' in MS)
self.assertRaises(ImportError,
guarded_import, 'AccessControl.tests.nonesuch', ())
self.failUnless('AccessControl.tests.nonesuch' in MS)
if __name__ == '__main__': def test_suite():
main() return unittest.makeSuite(ModuleSecurityTests)
...@@ -236,9 +236,10 @@ class TestPythonScriptErrors(PythonScriptTestBase): ...@@ -236,9 +236,10 @@ class TestPythonScriptErrors(PythonScriptTestBase):
self.assertPSRaises(SyntaxError, path='subversive_except') self.assertPSRaises(SyntaxError, path='subversive_except')
def testBadImports(self): def testBadImports(self):
self.assertPSRaises(ImportError, body="from string import *") from zExceptions import Unauthorized
self.assertPSRaises(ImportError, body="from datetime import datetime") self.assertPSRaises(Unauthorized, body="from string import *")
#self.assertPSRaises(ImportError, body="import mmap") self.assertPSRaises(Unauthorized, body="from datetime import datetime")
self.assertPSRaises(Unauthorized, body="import mmap")
def testAttributeAssignment(self): def testAttributeAssignment(self):
# It's illegal to assign to attributes of anything that # It's illegal to assign to attributes of anything that
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment