From 512dfac3a71657cf1db24a999bea7765284fa169 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Wed, 1 Feb 2017 17:13:10 +0100 Subject: [PATCH] Added `override_container` context manager. (#22) Added `override_container` context manager. --- CHANGES.txt | 4 +- src/AccessControl/SimpleObjectPolicies.py | 16 +++++ .../tests/testZopeSecurityPolicy.py | 59 ++++++++++++++----- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 1b87abc..d5d1ef4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,7 +4,9 @@ Changelog 2.13.15 (unreleased) -------------------- -- TBD +- Added ``override_container`` context manager. Used this in tests to + make them pass when the standard permissive security assertions for + strings has been changed. [maurits] 2.13.14 (2015-12-21) -------------------- diff --git a/src/AccessControl/SimpleObjectPolicies.py b/src/AccessControl/SimpleObjectPolicies.py index 1de5733..7acdf51 100644 --- a/src/AccessControl/SimpleObjectPolicies.py +++ b/src/AccessControl/SimpleObjectPolicies.py @@ -44,7 +44,9 @@ ''' _noroles = [] # this is imported in various places +_marker = object() +from contextlib import contextmanager import Record # Allow access to unprotected attributes @@ -119,3 +121,17 @@ def allow_type(Type, allowed=1): if has_values: assert key_type is type(tree.values()) assert key_type is type(tree.items()) + + +@contextmanager +def override_containers(type_, assertions): + """Temporarily override the container assertions.""" + orig_container = Containers(type_, _marker) + ContainerAssertions[type_] = assertions + try: + yield + finally: + if orig_container is _marker: + del ContainerAssertions[type_] + else: + ContainerAssertions[type_] = orig_container diff --git a/src/AccessControl/tests/testZopeSecurityPolicy.py b/src/AccessControl/tests/testZopeSecurityPolicy.py index 3a0694c..da47c56 100644 --- a/src/AccessControl/tests/testZopeSecurityPolicy.py +++ b/src/AccessControl/tests/testZopeSecurityPolicy.py @@ -306,7 +306,7 @@ def test_checkPermission_proxy_role_scope(self): self.a.subobject = ImplictAcqObject() subobject = self.a.subobject subobject.acl_users = UserFolder() - subobject.acl_users._doAddUser('theowner', 'password', + subobject.acl_users._doAddUser('theowner', 'password', eo_roles + sysadmin_roles, ()) subobject.r_item = RestrictedSimpleItem() r_subitem = subobject.r_item @@ -335,18 +335,44 @@ def testUnicodeRolesForPermission(self): v = self.policy.checkPermission(u'View', r_item, o_context) self.assert_(v, '_View_Permission should grant access to theowner') + def testContainersContextManager(self): + from AccessControl.SimpleObjectPolicies import override_containers + from AccessControl.SimpleObjectPolicies import ContainerAssertions + from AccessControl.SimpleObjectPolicies import Containers + from types import EllipsisType + # Surely we have no assertions for this type. There might be a good + # reason to have then, but I have not even heard of this type. + self.assertFalse(EllipsisType in ContainerAssertions) + with override_containers(EllipsisType, 1): + self.assertTrue(EllipsisType in ContainerAssertions) + self.assertEqual(Containers(EllipsisType), 1) + # Override it again. + with override_containers(EllipsisType, {}): + self.assertEqual(Containers(EllipsisType), {}) + # We are outside the nested override, so the first override should + # have been restored. + self.assertEqual(Containers(EllipsisType), 1) + # We are outside all overrides, so the type should no longer be in the + # assertions. + self.assertFalse(EllipsisType in ContainerAssertions) + def testAqNames(self): policy = self.policy names = { 'aq_self': 0, 'aq_base': 0, 'aq_parent': 1, 'aq_explicit': 1, 'aq_inner': 1 } - for name, allowed in names.items(): - if not allowed: - self.assertRaises(Unauthorized, policy.validate, - '', '', name, '', None) - else: - policy.validate('', '', name, '', None) + from AccessControl.SimpleObjectPolicies import override_containers + # By default we allow all access to str, but this may have been + # overridden to disallow some access of str.format. So we temporarily + # restore the default of allowing all access. + with override_containers(str, 1): + for name, allowed in names.items(): + if not allowed: + self.assertRaises(Unauthorized, policy.validate, + '', '', name, '', None) + else: + policy.validate('', '', name, '', None) def testProxyRoleScope(self): self.a.subobject = ImplictAcqObject() @@ -358,11 +384,11 @@ def testProxyRoleScope(self): 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') @@ -379,7 +405,12 @@ def testProxyRoleScope(self): def testUnicodeName(self): policy = self.policy - assert policy.validate('', '', u'foo', '', None) + from AccessControl.SimpleObjectPolicies import override_containers + # By default we allow all access to str, but this may have been + # overridden to disallow some access of str.format. So we temporarily + # restore the default of allowing all access. + with override_containers(str, 1): + assert policy.validate('', '', u'foo', '', None) if 0: # This test purposely generates a log entry. @@ -497,7 +528,7 @@ def test_getRoles(): """ >>> from AccessControl.ZopeSecurityPolicy import getRoles - + >>> class C: ... x = 'CRole' @@ -612,10 +643,10 @@ def test_zsp_gets_right_roles_for_methods(): ... self.user = user >>> c = C() - + >>> bool(zsp.validate(c, c, 'foo', c.foo, Context(User(['greeneggs'])))) True - + >>> zsp.validate(c, c, 'foo', c.foo, Context(User(['spam']))) Traceback (most recent call last): ... @@ -635,7 +666,7 @@ def test_zsp_gets_right_roles_for_methods(): >>> c.__allow_access_to_unprotected_subobjects__ = 1 >>> bool(zsp.validate(c, c, 'bar', c.bar, Context(User(['spam'])))) True - + """ from doctest import DocTestSuite