[Zope-Checkins] SVN: Zope/trunk/ Moved security related ZCML configuration into the AccessControl package.
Hanno Schlichting
hannosch at hannosch.eu
Thu Dec 31 16:41:57 EST 2009
Log message for revision 107479:
Moved security related ZCML configuration into the AccessControl package.
Changed:
U Zope/trunk/doc/CHANGES.rst
A Zope/trunk/src/AccessControl/meta.zcml
A Zope/trunk/src/AccessControl/metaconfigure.py
A Zope/trunk/src/AccessControl/tests/testZCML.py
U Zope/trunk/src/Products/Five/browser/tests/test_zope3security.py
U Zope/trunk/src/Products/Five/browser/tests/zope3security.py
U Zope/trunk/src/Products/Five/meta.zcml
U Zope/trunk/src/Products/Five/metaconfigure.py
D Zope/trunk/src/Products/Five/tests/test_security.py
-=-
Modified: Zope/trunk/doc/CHANGES.rst
===================================================================
--- Zope/trunk/doc/CHANGES.rst 2009-12-31 20:40:13 UTC (rev 107478)
+++ Zope/trunk/doc/CHANGES.rst 2009-12-31 21:41:57 UTC (rev 107479)
@@ -35,7 +35,8 @@
- Removed experimental support for configuring the Twisted HTTP server
as an alternative to ``ZServer``.
-- Moved ``Products/Five/security.py`` into the AccessControl package.
+- Moved ``Products/Five/security.py`` and security related ZCML configuration
+ into the AccessControl package.
- Moved ``Products/Five/traversing.zcml`` directly into the configure.zcml.
Added: Zope/trunk/src/AccessControl/meta.zcml
===================================================================
--- Zope/trunk/src/AccessControl/meta.zcml (rev 0)
+++ Zope/trunk/src/AccessControl/meta.zcml 2009-12-31 21:41:57 UTC (rev 107479)
@@ -0,0 +1,41 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:meta="http://namespaces.zope.org/meta">
+
+ <include package="zope.component" file="meta.zcml" />
+ <include package="zope.security" file="meta.zcml" />
+
+ <meta:directives namespace="http://namespaces.zope.org/zope">
+
+ <meta:complexDirective
+ name="class"
+ schema="zope.security.metadirectives.IClassDirective"
+ handler=".metaconfigure.ClassDirective"
+ >
+
+ <meta:subdirective
+ name="implements"
+ schema="zope.security.metadirectives.IImplementsSubdirective"
+ />
+
+ <meta:subdirective
+ name="require"
+ schema="zope.security.metadirectives.IRequireSubdirective"
+ />
+
+ <meta:subdirective
+ name="allow"
+ schema="zope.security.metadirectives.IAllowSubdirective"
+ />
+
+ </meta:complexDirective>
+
+ <meta:directive
+ name="securityPolicy"
+ schema="zope.security.zcml.ISecurityPolicyDirective"
+ handler="zope.security.zcml.securityPolicy"
+ />
+
+ </meta:directives>
+
+</configure>
Property changes on: Zope/trunk/src/AccessControl/meta.zcml
___________________________________________________________________
Added: svn:eol-style
+ native
Copied: Zope/trunk/src/AccessControl/metaconfigure.py (from rev 107450, Zope/trunk/src/Products/Five/metaconfigure.py)
===================================================================
--- Zope/trunk/src/AccessControl/metaconfigure.py (rev 0)
+++ Zope/trunk/src/AccessControl/metaconfigure.py 2009-12-31 21:41:57 UTC (rev 107479)
@@ -0,0 +1,49 @@
+##############################################################################
+#
+# Copyright (c) 2004, 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# 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.
+# 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.
+#
+##############################################################################
+
+import warnings
+from zope.security import metaconfigure
+from AccessControl.security import protectName
+from App.class_init import InitializeClass
+
+class ClassDirective(metaconfigure.ClassDirective):
+
+ def __protectName(self, name, permission_id):
+ self.__context.action(
+ discriminator = ('five:protectName', self.__class, name),
+ callable = protectName,
+ args = (self.__class, name, permission_id)
+ )
+
+ def __protectSetAttributes(self, names, permission_id):
+ warnings.warn("The set_attribute option of the <require /> directive "
+ "is not supported in Zope 2. "
+ "Ignored for %s" % str(self.__class), stacklevel=3)
+
+ def __protectSetSchema(self, schema, permission):
+ warnings.warn("The set_schema option of the <require /> directive "
+ "is not supported in Zope 2. "
+ "Ignored for %s" % str(self.__class), stacklevel=3)
+
+ def __mimic(self, _context, class_):
+ warnings.warn("The like_class option of the <require /> directive "
+ "is not supported in Zope 2. "
+ "Ignored for %s" % str(self.__class), stacklevel=3)
+
+ def __call__(self):
+ return self.__context.action(
+ discriminator = None,
+ callable = InitializeClass,
+ args = (self.__class,)
+ )
Copied: Zope/trunk/src/AccessControl/tests/testZCML.py (from rev 107450, Zope/trunk/src/Products/Five/tests/test_security.py)
===================================================================
--- Zope/trunk/src/AccessControl/tests/testZCML.py (rev 0)
+++ Zope/trunk/src/AccessControl/tests/testZCML.py 2009-12-31 21:41:57 UTC (rev 107479)
@@ -0,0 +1,381 @@
+##############################################################################
+#
+# Copyright (c) 2004, 2005 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# 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.
+# 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 security induced by ZCML
+
+$Id$
+"""
+
+from zope.interface import implements
+from zope.interface import Interface
+from zope.schema import TextLine
+from AccessControl.SecurityInfo import ClassSecurityInfo
+
+class ISuperDummy(Interface):
+ """
+ """
+
+ def superMethod():
+ """
+ """
+
+class IDummy(ISuperDummy):
+ """Just a marker interface"""
+
+ def foo():
+ """
+ """
+
+class Dummy1:
+ implements(IDummy)
+ def foo(self): pass
+ def bar(self): pass
+ def baz(self): pass
+ def keg(self): pass
+ def wot(self): pass
+ def superMethod(self): pass
+
+class Dummy2(Dummy1):
+ security = ClassSecurityInfo()
+ security.declarePublic('foo')
+ security.declareProtected('View management screens', 'bar')
+ security.declarePrivate('baz')
+ security.declareProtected('View management screens', 'keg')
+
+class IDummy3(Interface):
+ attr = TextLine(title=u"Attribute")
+
+class Dummy3:
+ implements(IDummy3)
+ attr = None
+
+class Dummy4:
+ foo = None
+
+def test_security_equivalence():
+ """This test demonstrates that the traditional declarative security of
+ Zope 2 can be replaced by ZCML statements without any loss of
+ information.
+
+ >>> from zope.component.testing import setUp, tearDown
+ >>> setUp()
+
+ We start out with two classes, ``Dummy1`` and ``Dummy2``. They
+ are identical in every way, except that ``Dummy2`` has security
+ declarations and ``Dummy1`` does not. Before we do anything, none
+ of them have security access controls:
+
+ >>> from AccessControl.tests.testZCML import Dummy1, Dummy2
+ >>> hasattr(Dummy1, '__ac_permissions__')
+ False
+ >>> hasattr(Dummy2, '__ac_permissions__')
+ False
+
+ Before we can make security declarations through ZCML, we need to
+ register the directive and the permission:
+
+ >>> import AccessControl
+ >>> from zope.configuration.xmlconfig import XMLConfig
+ >>> XMLConfig('meta.zcml', AccessControl)()
+ >>> XMLConfig('permissions.zcml', AccessControl)()
+
+ Now we initialize the security for ``Dummy2`` and provide some
+ ZCML declarations for ``Dummy1``:
+
+ >>> from StringIO import StringIO
+ >>> configure_zcml = StringIO('''
+ ... <configure xmlns="http://namespaces.zope.org/zope">
+ ... <class class="AccessControl.tests.testZCML.Dummy1">
+ ... <allow attributes="foo" />
+ ... <!--deny attributes="baz" /--> <!-- XXX not yet supported -->
+ ... </class>
+ ... <class class="AccessControl.tests.testZCML.Dummy1">
+ ... <require attributes="bar keg"
+ ... permission="zope2.ViewManagementScreens"
+ ... />
+ ... </class>
+ ... </configure>
+ ... ''')
+ >>> from zope.configuration.xmlconfig import xmlconfig
+ >>> xmlconfig(configure_zcml)
+
+ >>> from App.class_init import InitializeClass
+ >>> InitializeClass(Dummy2)
+
+ Now we compare their access controls:
+
+ >>> ac1 = getattr(Dummy1, '__ac_permissions__')
+ >>> ac2 = getattr(Dummy2, '__ac_permissions__')
+ >>> ac1 == ac2
+ True
+
+ Now we look at the individual permissions:
+
+ >>> from AccessControl.ZopeSecurityPolicy import getRoles
+ >>> from AccessControl import ACCESS_PUBLIC
+ >>> from AccessControl import ACCESS_PRIVATE
+
+ >>> dummy1 = Dummy1()
+ >>> getRoles(dummy1, 'bar', dummy1.bar, ('Def',))
+ ('Manager',)
+
+ >>> getRoles(dummy1, 'keg', dummy1.keg, ('Def',))
+ ('Manager',)
+
+ >>> getRoles(dummy1, 'foo', dummy1.foo, ('Def',)) is ACCESS_PUBLIC
+ True
+
+ #>>> getRoles(dummy1, 'baz', dummy1.baz, ('Def',)) is ACCESS_PRIVATE
+ #True XXX Not yet supported.
+
+ >>> dummy2 = Dummy2()
+ >>> getRoles(dummy2, 'bar', dummy2.bar, ('Def',))
+ ('Manager',)
+
+ >>> getRoles(dummy2, 'keg', dummy2.keg, ('Def',))
+ ('Manager',)
+
+ >>> getRoles(dummy2, 'foo', dummy2.foo, ('Def',)) is ACCESS_PUBLIC
+ True
+
+ >>> getRoles(dummy2, 'baz', dummy2.baz, ('Def',)) is ACCESS_PRIVATE
+ True
+
+ Before we end we should clean up after ourselves:
+
+ >>> from AccessControl.security import clearSecurityInfo
+ >>> clearSecurityInfo(Dummy1)
+ >>> clearSecurityInfo(Dummy2)
+
+ >>> tearDown()
+ """
+
+
+def test_set_warnings():
+ """This test demonstrates that set_attributes and set_schema will result
+ in warnings, not errors. This type of protection doesn't make sense in
+ Zope 2, but we want to be able to re-use Zope Toolkit packages that use
+ them without error.
+
+ >>> from zope.component.testing import setUp, tearDown
+ >>> setUp()
+
+ Before we can make security declarations through ZCML, we need to
+ register the directive and the permission:
+
+ >>> import AccessControl
+ >>> from zope.configuration.xmlconfig import XMLConfig
+ >>> XMLConfig('meta.zcml', AccessControl)()
+ >>> XMLConfig('permissions.zcml', AccessControl)()
+
+ Now we provide some ZCML declarations for ``Dummy1``:
+
+ >>> from StringIO import StringIO
+ >>> configure_zcml = StringIO('''
+ ... <configure xmlns="http://namespaces.zope.org/zope">
+ ...
+ ... <class class="AccessControl.tests.testZCML.Dummy3">
+ ... <require
+ ... permission="zope2.View"
+ ... interface="AccessControl.tests.testZCML.IDummy3"
+ ... />
+ ... <require
+ ... permission="zope2.ChangeConfig"
+ ... set_schema="AccessControl.tests.testZCML.IDummy3"
+ ... />
+ ... </class>
+ ...
+ ... <class class="AccessControl.tests.testZCML.Dummy4">
+ ... <require
+ ... permission="zope2.ChangeConfig"
+ ... set_attributes="foo"
+ ... />
+ ... </class>
+ ...
+ ... </configure>
+ ... ''')
+
+ Running this should not throw an exception (but will print a warning to
+ stderr)
+
+ >>> from zope.configuration.xmlconfig import xmlconfig
+ >>> xmlconfig(configure_zcml)
+ >>> tearDown()
+ """
+
+def test_checkPermission():
+ """
+ Test checkPermission
+
+ >>> from zope.component.testing import setUp, tearDown
+ >>> setUp()
+
+ Zope 3 has a function zope.security.checkPermission which provides
+ an easy way of checking whether the currently authenticated user
+ has the permission to access an object. The function delegates to
+ the security policy's checkPermission() method.
+
+ Zope2 has the same function, AccessControl.security.checkPermission,
+ but in a Zope2-compatible implementation. It too uses the currently
+ active security policy of Zope 2 for the actual permission
+ checking.
+
+ >>> import AccessControl
+ >>> from zope.configuration.xmlconfig import XMLConfig
+ >>> XMLConfig('meta.zcml', AccessControl)()
+ >>> XMLConfig('permissions.zcml', AccessControl)()
+
+ In the following we want to test AccessControl's checkPermission function.
+ We do that by taking the test's folder and asserting several
+ standard permissions. What we want to assure is that
+ checkPermission translates the Zope 2 permissions correctly,
+ especially the edge cases:
+
+ a) zope2.Public (which should always be available to everyone)
+
+ >>> from AccessControl.security import checkPermission
+ >>> checkPermission('zope2.Public', self.folder)
+ True
+
+ b) zope2.Private (which should never available to anyone)
+
+ >>> checkPermission('zope.Private', self.folder)
+ False
+ >>> checkPermission('zope2.Private', self.folder)
+ False
+
+ Any other standard Zope 2 permission will also resolve correctly:
+
+ >>> checkPermission('zope2.AccessContentsInformation', self.folder)
+ True
+
+ Invalid permissions will obviously result in a negative response:
+
+ >>> checkPermission('notapermission', self.folder)
+ False
+
+
+ In addition to using AccessControl's ``checkPermission`` function
+ directly, we also expect the same behaviour when we use zope.security's
+ checkPermission function. Code from within other Zope packages will use
+ that and therefore it should work transparently.
+ For that to work, a new AccessControl "interaction" needs to be started
+ (the old one from placelesssetup needs to be ended first):
+
+ >>> from zope.security.management import endInteraction
+ >>> endInteraction()
+
+ >>> from AccessControl.security import newInteraction
+ >>> newInteraction()
+
+ a) zope2.Public (which should always be available to everyone)
+
+ >>> from zope.security import checkPermission
+ >>> checkPermission('zope2.Public', self.folder)
+ True
+
+ b) zope2.Private (which should never available to anyone)
+
+ >>> checkPermission('zope.Private', self.folder)
+ False
+ >>> checkPermission('zope2.Private', self.folder)
+ False
+
+ Any other standard Zope 2 permission will also resolve correctly:
+
+ >>> checkPermission('zope2.AccessContentsInformation', self.folder)
+ True
+
+ Invalid permissions will obviously result in a negative response:
+
+ >>> checkPermission('notapermission', self.folder)
+ False
+
+ Clean up:
+
+ >>> tearDown()
+ """
+
+def test_register_permission():
+ """This test demonstrates that if the <permission /> directive is used
+ to create a permission that does not already exist, it is created on
+ startup, with roles defaulting to Manager.
+
+ >>> from Testing.ZopeTestCase.placeless import setUp, tearDown
+ >>> setUp()
+
+ First, we need to configure the relevant parts of AccessControl:
+
+ >>> import AccessControl
+ >>> from zope.configuration.xmlconfig import XMLConfig
+ >>> XMLConfig('meta.zcml', AccessControl)()
+ >>> XMLConfig('permissions.zcml', AccessControl)()
+
+ We can now register a permission in ZCML:
+
+ >>> from StringIO import StringIO
+ >>> configure_zcml = StringIO('''
+ ... <configure xmlns="http://namespaces.zope.org/zope"
+ ... i18n_domain="test">
+ ...
+ ... <permission
+ ... id="AccessControl.tests.DummyPermission"
+ ... title="AccessControl: Dummy permission"
+ ... />
+ ...
+ ... </configure>
+ ... ''')
+ >>> from zope.configuration.xmlconfig import xmlconfig
+ >>> xmlconfig(configure_zcml)
+
+ The permission will be made available globally, with default role set
+ of ('Manager',).
+
+ >>> roles = self.app.rolesOfPermission('AccessControl: Dummy permission')
+ >>> sorted(r['name'] for r in roles if r['selected'])
+ ['Manager']
+
+ Let's also ensure that permissions are not overwritten if they exist
+ already:
+
+ >>> from AccessControl.Permission import _registeredPermissions
+ >>> import Products
+ >>> _registeredPermissions['Dummy: Other dummy'] = 1
+ >>> Products.__ac_permissions__ += (('Dummy: Other dummy', (), (),),)
+ >>> self.app.manage_permission('Dummy: Other dummy', roles=['Anonymous'])
+
+ >>> from StringIO import StringIO
+ >>> configure_zcml = StringIO('''
+ ... <configure xmlns="http://namespaces.zope.org/zope"
+ ... i18n_domain="test">
+ ...
+ ... <permission
+ ... id="AccessControl.tests.OtherDummy"
+ ... title="Dummy: Other dummy"
+ ... />
+ ...
+ ... </configure>
+ ... ''')
+ >>> from zope.configuration.xmlconfig import xmlconfig
+ >>> xmlconfig(configure_zcml)
+
+ >>> roles = self.app.rolesOfPermission('Dummy: Other dummy')
+ >>> sorted(r['name'] for r in roles if r['selected'])
+ ['Anonymous']
+
+ >>> tearDown()
+ """
+
+def test_suite():
+ from Testing.ZopeTestCase import ZopeDocTestSuite
+ return ZopeDocTestSuite()
Modified: Zope/trunk/src/Products/Five/browser/tests/test_zope3security.py
===================================================================
--- Zope/trunk/src/Products/Five/browser/tests/test_zope3security.py 2009-12-31 20:40:13 UTC (rev 107478)
+++ Zope/trunk/src/Products/Five/browser/tests/test_zope3security.py 2009-12-31 21:41:57 UTC (rev 107479)
@@ -1,11 +1,11 @@
def test_check_permission():
- """Code (in Zope 3) often uses
+ """Code (in Zope packages) often uses
zope.security.management.checkPermission to determine whether the
- current user has a certain permission in a given context. Five
+ current user has a certain permission in a given context. Five
inserts its own interaction that assures that such calls still
work.
-
+
>>> configure_zcml = '''
... <configure
... xmlns="http://namespaces.zope.org/zope"
@@ -53,6 +53,80 @@
"""
+def test_allowed_interface():
+ """This test demonstrates that allowed_interface security declarations work
+ as expected.
+
+ >>> from zope.component.testing import setUp, tearDown
+ >>> setUp()
+
+ Before we can make security declarations through ZCML, we need to
+ register the directive and the permission:
+
+ >>> import AccessControl
+ >>> from zope.configuration.xmlconfig import XMLConfig
+ >>> XMLConfig('meta.zcml', AccessControl)()
+ >>> import Products.Five.browser
+ >>> XMLConfig('meta.zcml', Products.Five.browser)()
+ >>> XMLConfig('permissions.zcml', AccessControl)()
+
+ Now we provide some ZCML declarations for ``Dummy1``:
+
+ >>> from StringIO import StringIO
+ >>> configure_zcml = StringIO('''
+ ... <configure xmlns="http://namespaces.zope.org/zope"
+ ... xmlns:browser="http://namespaces.zope.org/browser">
+ ... <browser:page
+ ... for="*"
+ ... name="testview"
+ ... permission="zope2.ViewManagementScreens"
+ ... class="AccessControl.tests.testZCML.Dummy1"
+ ... allowed_interface="AccessControl.tests.testZCML.IDummy" />
+ ... </configure>
+ ... ''')
+ >>> from zope.configuration.xmlconfig import xmlconfig
+ >>> xmlconfig(configure_zcml)
+
+ We are going to check that roles are correctly setup, so we need getRoles.
+
+ >>> from AccessControl.ZopeSecurityPolicy import getRoles
+ >>> from AccessControl import ACCESS_PRIVATE
+
+ Due to the nasty voodoo involved in Five's handling of view classes,
+ browser:page doesn't apply security to Dummy1, but rather to the "magic"
+ view class that is created at ZCML parse time. That means we can't just
+ instanciate with Dummy1() directly and expect a security-aware instance :(.
+ Instead, we'll have to actually lookup the view. The view was declared for
+ "*", so we just use an instance of Dummy1 ;-).
+
+ Instanciate a Dummy1 object to test with.
+
+ >>> from AccessControl.tests.testZCML import Dummy1
+ >>> dummy1 = Dummy1()
+ >>> from zope.component import getMultiAdapter
+ >>> from zope.publisher.browser import TestRequest
+ >>> request = TestRequest()
+ >>> view = getMultiAdapter((dummy1, request), name="testview")
+
+ As 'foo' is defined in IDummy, it should have the 'Manager' role.
+
+ >>> getRoles(view, 'foo', view.foo, ('Def',))
+ ('Manager',)
+
+ As 'wot' is not defined in IDummy, it should be private.
+
+ >>> getRoles(view, 'wot', view.wot, ('Def',)) is ACCESS_PRIVATE
+ True
+
+ But 'superMethod' is defined on IDummy by inheritance from ISuperDummy, and
+ so should have the 'Manager' role setup.
+
+ >>> getRoles(view, 'superMethod', view.superMethod, ('Def',))
+ ('Manager',)
+
+ >>> tearDown()
+ """
+
def test_suite():
from Testing.ZopeTestCase import FunctionalDocTestSuite
from zope.testing.doctest import ELLIPSIS
Modified: Zope/trunk/src/Products/Five/browser/tests/zope3security.py
===================================================================
--- Zope/trunk/src/Products/Five/browser/tests/zope3security.py 2009-12-31 20:40:13 UTC (rev 107478)
+++ Zope/trunk/src/Products/Five/browser/tests/zope3security.py 2009-12-31 21:41:57 UTC (rev 107479)
@@ -1,4 +1,4 @@
-from Products.Five import BrowserView
+from zope.publisher.browser import BrowserView
from zope.security.management import checkPermission
class Zope3SecurityView(BrowserView):
Modified: Zope/trunk/src/Products/Five/meta.zcml
===================================================================
--- Zope/trunk/src/Products/Five/meta.zcml 2009-12-31 20:40:13 UTC (rev 107478)
+++ Zope/trunk/src/Products/Five/meta.zcml 2009-12-31 21:41:57 UTC (rev 107479)
@@ -2,8 +2,8 @@
xmlns="http://namespaces.zope.org/zope"
xmlns:meta="http://namespaces.zope.org/meta">
+ <include package="AccessControl" file="meta.zcml" />
<include package="zope.component" file="meta.zcml" />
- <include package="zope.security" file="meta.zcml" />
<include package="zope.i18n" file="meta.zcml" />
<include package=".browser" file="meta.zcml" />
@@ -17,35 +17,6 @@
handler="zope.component.zcml.view"
/>
- <meta:complexDirective
- name="class"
- schema="zope.security.metadirectives.IClassDirective"
- handler=".metaconfigure.ClassDirective"
- >
-
- <meta:subdirective
- name="implements"
- schema="zope.security.metadirectives.IImplementsSubdirective"
- />
-
- <meta:subdirective
- name="require"
- schema="zope.security.metadirectives.IRequireSubdirective"
- />
-
- <meta:subdirective
- name="allow"
- schema="zope.security.metadirectives.IAllowSubdirective"
- />
-
- </meta:complexDirective>
-
- <meta:directive
- name="securityPolicy"
- schema="zope.security.zcml.ISecurityPolicyDirective"
- handler="zope.security.zcml.securityPolicy"
- />
-
</meta:directives>
<meta:directives namespace="http://namespaces.zope.org/five">
Modified: Zope/trunk/src/Products/Five/metaconfigure.py
===================================================================
--- Zope/trunk/src/Products/Five/metaconfigure.py 2009-12-31 20:40:13 UTC (rev 107478)
+++ Zope/trunk/src/Products/Five/metaconfigure.py 2009-12-31 21:41:57 UTC (rev 107479)
@@ -1,49 +1,2 @@
-##############################################################################
-#
-# Copyright (c) 2004, 2005 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# 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.
-# 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.
-#
-##############################################################################
-"""Generic Components ZCML Handlers
-
-$Id$
-"""
-import warnings
-from zope.security import metaconfigure
-from AccessControl.security import protectName
-from App.class_init import InitializeClass
-
-class ClassDirective(metaconfigure.ClassDirective):
-
- def __protectName(self, name, permission_id):
- self.__context.action(
- discriminator = ('five:protectName', self.__class, name),
- callable = protectName,
- args = (self.__class, name, permission_id)
- )
-
- def __protectSetAttributes(self, names, permission_id):
- warnings.warn("The set_attribute option of the <require /> directive is not supported in Zope 2. " + \
- "Ignored for %s" % str(self.__class), stacklevel=3)
-
- def __protectSetSchema(self, schema, permission):
- warnings.warn("The set_schema option of the <require /> directive is not supported in Zope 2. " + \
- "Ignored for %s" % str(self.__class), stacklevel=3)
-
- def __mimic(self, _context, class_):
- warnings.warn("The like_class option of the <require /> directive is not supported in Zope 2. " + \
- "Ignored for %s" % str(self.__class), stacklevel=3)
-
- def __call__(self):
- return self.__context.action(
- discriminator = None,
- callable = InitializeClass,
- args = (self.__class,)
- )
+# BBB
+from AccessControl.metaconfigure import ClassDirective
Deleted: Zope/trunk/src/Products/Five/tests/test_security.py
===================================================================
--- Zope/trunk/src/Products/Five/tests/test_security.py 2009-12-31 20:40:13 UTC (rev 107478)
+++ Zope/trunk/src/Products/Five/tests/test_security.py 2009-12-31 21:41:57 UTC (rev 107479)
@@ -1,445 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004, 2005 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# 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.
-# 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 security induced by ZCML
-
-$Id$
-"""
-
-from zope.interface import implements
-from zope.interface import Interface
-from zope.schema import TextLine
-from AccessControl.SecurityInfo import ClassSecurityInfo
-
-class ISuperDummy(Interface):
- """
- """
-
- def superMethod():
- """
- """
-
-class IDummy(ISuperDummy):
- """Just a marker interface"""
-
- def foo():
- """
- """
-
-class Dummy1:
- implements(IDummy)
- def foo(self): pass
- def bar(self): pass
- def baz(self): pass
- def keg(self): pass
- def wot(self): pass
- def superMethod(self): pass
-
-class Dummy2(Dummy1):
- security = ClassSecurityInfo()
- security.declarePublic('foo')
- security.declareProtected('View management screens', 'bar')
- security.declarePrivate('baz')
- security.declareProtected('View management screens', 'keg')
-
-class IDummy3(Interface):
- attr = TextLine(title=u"Attribute")
-
-class Dummy3:
- implements(IDummy3)
- attr = None
-
-class Dummy4:
- foo = None
-
-def test_security_equivalence():
- """This test demonstrates that the traditional declarative security of
- Zope 2 can be replaced by ZCML statements without any loss of
- information.
-
- >>> from zope.component.testing import setUp, tearDown
- >>> setUp()
-
- We start out with two classes, ``Dummy1`` and ``Dummy2``. They
- are identical in every way, except that ``Dummy2`` has security
- declarations and ``Dummy1`` does not. Before we do anything, none
- of them have security access controls:
-
- >>> from Products.Five.tests.test_security import Dummy1, Dummy2
- >>> hasattr(Dummy1, '__ac_permissions__')
- False
- >>> hasattr(Dummy2, '__ac_permissions__')
- False
-
- Before we can make security declarations through ZCML, we need to
- register the directive and the permission:
-
- >>> import Products.Five
- >>> from Products.Five import zcml
- >>> zcml.load_config('meta.zcml', Products.Five)
- >>> zcml.load_config('permissions.zcml', Products.Five)
-
- Now we initialize the security for ``Dummy2`` and provide some
- ZCML declarations for ``Dummy1``:
-
- >>> configure_zcml = '''
- ... <configure xmlns="http://namespaces.zope.org/zope">
- ... <class class="Products.Five.tests.test_security.Dummy1">
- ... <allow attributes="foo" />
- ... <!--deny attributes="baz" /--> <!-- XXX not yet supported -->
- ... </class>
- ... <class class="Products.Five.tests.test_security.Dummy1">
- ... <require attributes="bar keg"
- ... permission="zope2.ViewManagementScreens"
- ... />
- ... </class>
- ... </configure>
- ... '''
- >>> zcml.load_string(configure_zcml)
-
- >>> from App.class_init import InitializeClass
- >>> InitializeClass(Dummy2)
-
- Now we compare their access controls:
-
- >>> ac1 = getattr(Dummy1, '__ac_permissions__')
- >>> ac2 = getattr(Dummy2, '__ac_permissions__')
- >>> ac1 == ac2
- True
-
- Now we look at the individual permissions:
-
- >>> from AccessControl.ZopeSecurityPolicy import getRoles
- >>> from AccessControl import ACCESS_PUBLIC
- >>> from AccessControl import ACCESS_PRIVATE
-
- >>> dummy1 = Dummy1()
- >>> getRoles(dummy1, 'bar', dummy1.bar, ('Def',))
- ('Manager',)
-
- >>> getRoles(dummy1, 'keg', dummy1.keg, ('Def',))
- ('Manager',)
-
- >>> getRoles(dummy1, 'foo', dummy1.foo, ('Def',)) is ACCESS_PUBLIC
- True
-
- #>>> getRoles(dummy1, 'baz', dummy1.baz, ('Def',)) is ACCESS_PRIVATE
- #True XXX Not yet supported.
-
- >>> dummy2 = Dummy2()
- >>> getRoles(dummy2, 'bar', dummy2.bar, ('Def',))
- ('Manager',)
-
- >>> getRoles(dummy2, 'keg', dummy2.keg, ('Def',))
- ('Manager',)
-
- >>> getRoles(dummy2, 'foo', dummy2.foo, ('Def',)) is ACCESS_PUBLIC
- True
-
- >>> getRoles(dummy2, 'baz', dummy2.baz, ('Def',)) is ACCESS_PRIVATE
- True
-
- Before we end we should clean up after ourselves:
-
- >>> from AccessControl.security import clearSecurityInfo
- >>> clearSecurityInfo(Dummy1)
- >>> clearSecurityInfo(Dummy2)
-
- >>> tearDown()
- """
-
-def test_allowed_interface():
- """This test demonstrates that allowed_interface security declarations work
- as expected.
-
- >>> from zope.component.testing import setUp, tearDown
- >>> setUp()
-
- Before we can make security declarations through ZCML, we need to
- register the directive and the permission:
-
- >>> import Products.Five
- >>> from Products.Five import zcml
- >>> zcml.load_config('meta.zcml', Products.Five)
- >>> import Products.Five.browser
- >>> zcml.load_config('meta.zcml', Products.Five.browser)
- >>> zcml.load_config('permissions.zcml', Products.Five)
-
- Now we provide some ZCML declarations for ``Dummy1``:
-
- >>> configure_zcml = '''
- ... <configure xmlns="http://namespaces.zope.org/zope"
- ... xmlns:browser="http://namespaces.zope.org/browser">
- ... <browser:page
- ... for="*"
- ... name="testview"
- ... permission="zope2.ViewManagementScreens"
- ... class="Products.Five.tests.test_security.Dummy1"
- ... allowed_interface="Products.Five.tests.test_security.IDummy" />
- ... </configure>
- ... '''
- >>> zcml.load_string(configure_zcml)
-
- We are going to check that roles are correctly setup, so we need getRoles.
-
- >>> from AccessControl.ZopeSecurityPolicy import getRoles
- >>> from AccessControl import ACCESS_PRIVATE
-
- Due to the nasty voodoo involved in Five's handling of view classes,
- browser:page doesn't apply security to Dummy1, but rather to the "magic"
- view class that is created at ZCML parse time. That means we can't just
- instanciate with Dummy1() directly and expect a security-aware instance :(.
- Instead, we'll have to actually lookup the view. The view was declared for
- "*", so we just use an instance of Dummy1 ;-).
-
- Instanciate a Dummy1 object to test with.
-
- >>> from Products.Five.tests.test_security import Dummy1
- >>> dummy1 = Dummy1()
- >>> from zope.component import getMultiAdapter
- >>> from zope.publisher.browser import TestRequest
- >>> request = TestRequest()
- >>> view = getMultiAdapter((dummy1, request), name="testview")
-
- As 'foo' is defined in IDummy, it should have the 'Manager' role.
-
- >>> getRoles(view, 'foo', view.foo, ('Def',))
- ('Manager',)
-
- As 'wot' is not defined in IDummy, it should be private.
-
- >>> getRoles(view, 'wot', view.wot, ('Def',)) is ACCESS_PRIVATE
- True
-
- But 'superMethod' is defined on IDummy by inheritance from ISuperDummy, and
- so should have the 'Manager' role setup.
-
- >>> getRoles(view, 'superMethod', view.superMethod, ('Def',))
- ('Manager',)
-
- >>> tearDown()
- """
-
-def test_set_warnings():
- """This test demonstrates that set_attributes and set_schema will result
- in warnings, not errors. This type of protection doesn't make sense in
- Zope 2, but we want to be able to re-use pure Zope 3 packages that use
- them without error.
-
- >>> from zope.component.testing import setUp, tearDown
- >>> setUp()
-
- Before we can make security declarations through ZCML, we need to
- register the directive and the permission:
-
- >>> import Products.Five
- >>> from Products.Five import zcml
- >>> zcml.load_config('meta.zcml', Products.Five)
- >>> zcml.load_config('permissions.zcml', Products.Five)
-
- Now we provide some ZCML declarations for ``Dummy1``:
-
- >>> configure_zcml = '''
- ... <configure xmlns="http://namespaces.zope.org/zope">
- ...
- ... <class class="Products.Five.tests.test_security.Dummy3">
- ... <require
- ... permission="zope2.View"
- ... interface="Products.Five.tests.test_security.IDummy3"
- ... />
- ... <require
- ... permission="cmf.ModifyPortalContent"
- ... set_schema="Products.Five.tests.test_security.IDummy3"
- ... />
- ... </class>
- ...
- ... <class class="Products.Five.tests.test_security.Dummy4">
- ... <require
- ... permission="cmf.ModifyPortalContent"
- ... set_attributes="foo"
- ... />
- ... </class>
- ...
- ... </configure>
- ... '''
-
- Running this should not throw an exception (but will print a warning to
- stderr)
-
- >>> zcml.load_string(configure_zcml)
- >>> tearDown()
- """
-
-def test_checkPermission():
- """
- Test checkPermission
-
- >>> from zope.component.testing import setUp, tearDown
- >>> setUp()
-
- Zope 3 has a function zope.security.checkPermission which provides
- an easy way of checking whether the currently authenticated user
- has the permission to access an object. The function delegates to
- the security policy's checkPermission() method.
-
- Zope2 has the same function, AccessControl.security.checkPermission,
- but in a Zope2-compatible implementation. It too uses the currently
- active security policy of Zope 2 for the actual permission
- checking.
-
- >>> import Products.Five
- >>> from Products.Five import zcml
- >>> zcml.load_config('meta.zcml', Products.Five)
- >>> zcml.load_config('permissions.zcml', Products.Five)
-
- In the following we want to test Five's checkPermission function.
- We do that by taking the test's folder and asserting several
- standard permissions. What we want to assure is that
- checkPermission translates the Zope 2 permissions correctly,
- especially the edge cases:
-
- a) zope2.Public (which should always be available to everyone)
-
- >>> from AccessControl.security import checkPermission
- >>> checkPermission('zope2.Public', self.folder)
- True
-
- b) zope2.Private (which should never available to anyone)
-
- >>> checkPermission('zope.Private', self.folder)
- False
- >>> checkPermission('zope2.Private', self.folder)
- False
-
- Any other standard Zope 2 permission will also resolve correctly:
-
- >>> checkPermission('zope2.AccessContentsInformation', self.folder)
- True
-
- Invalid permissions will obviously result in a negative response:
-
- >>> checkPermission('notapermission', self.folder)
- False
-
-
- In addition to using Five's ``checkPermission`` function directly,
- we also expect the same behaviour when we use Zope 3's
- zope.security.checkPermission function. Code from within Zope 3
- will use that and therefore it should work transparently. For
- that to work, a new Five "interaction" needs to be started (the
- old one from placelesssetup needs to be ended first):
-
- >>> from zope.security.management import endInteraction
- >>> endInteraction()
-
- >>> from AccessControl.security import newInteraction
- >>> newInteraction()
-
- a) zope2.Public (which should always be available to everyone)
-
- >>> from zope.security import checkPermission
- >>> checkPermission('zope2.Public', self.folder)
- True
-
- b) zope2.Private (which should never available to anyone)
-
- >>> checkPermission('zope.Private', self.folder)
- False
- >>> checkPermission('zope2.Private', self.folder)
- False
-
- Any other standard Zope 2 permission will also resolve correctly:
-
- >>> checkPermission('zope2.AccessContentsInformation', self.folder)
- True
-
- Invalid permissions will obviously result in a negative response:
-
- >>> checkPermission('notapermission', self.folder)
- False
-
-
- Clean up:
-
- >>> tearDown()
- """
-
-def test_register_permission():
- """This test demonstrates that if the <permission /> directive is used
- to create a permission that does not already exist, it is created on
- startup, with roles defaulting to Manager.
-
- >>> from Testing.ZopeTestCase.placeless import setUp, tearDown
- >>> setUp()
-
- First, we need to configure the relevant parts of Five.
-
- >>> import Products.Five
- >>> from Products.Five import zcml
- >>> zcml.load_config('meta.zcml', Products.Five)
- >>> zcml.load_config('permissions.zcml', Products.Five)
-
- We can now register a permission in ZCML:
-
- >>> configure_zcml = '''
- ... <configure xmlns="http://namespaces.zope.org/zope"
- ... i18n_domain="fivetest">
- ...
- ... <permission
- ... id="Products.Five.tests.DummyPermission"
- ... title="Five: Dummy permission"
- ... />
- ...
- ... </configure>
- ... '''
- >>> zcml.load_string(configure_zcml)
-
- The permission will be made available globally, with default role set
- of ('Manager',).
-
- >>> roles = self.app.rolesOfPermission('Five: Dummy permission')
- >>> sorted(r['name'] for r in roles if r['selected'])
- ['Manager']
-
- Let's also ensure that permissions are not overwritten if they exist
- already:
-
- >>> from AccessControl.Permission import _registeredPermissions
- >>> import Products
- >>> _registeredPermissions['Five: Other dummy'] = 1
- >>> Products.__ac_permissions__ += (('Five: Other dummy', (), (),),)
- >>> self.app.manage_permission('Five: Other dummy', roles=['Anonymous'])
-
- >>> configure_zcml = '''
- ... <configure xmlns="http://namespaces.zope.org/zope"
- ... i18n_domain="fivetest">
- ...
- ... <permission
- ... id="Products.Five.tests.OtherDummy"
- ... title="Five: Other dummy"
- ... />
- ...
- ... </configure>
- ... '''
- >>> zcml.load_string(configure_zcml)
-
- >>> roles = self.app.rolesOfPermission('Five: Other dummy')
- >>> sorted(r['name'] for r in roles if r['selected'])
- ['Anonymous']
-
- >>> tearDown()
- """
-
-def test_suite():
- from Testing.ZopeTestCase import ZopeDocTestSuite
- return ZopeDocTestSuite()
More information about the Zope-Checkins
mailing list