[Checkins] SVN: zope.security/trunk/ Added to zope.security the implementation of the simple <module>

Brandon Rhodes brandon at rhodesmill.org
Wed Jan 28 11:00:23 EST 2009


Log message for revision 95342:
  Added to zope.security the implementation of the simple <module>
  directive, so that everyone needing it will no longer have to rely,
  for just that reason, upon the monstrous zope.app.security.
  

Changed:
  U   zope.security/trunk/CHANGES.txt
  U   zope.security/trunk/src/zope/security/meta.zcml
  U   zope.security/trunk/src/zope/security/metaconfigure.py
  U   zope.security/trunk/src/zope/security/metadirectives.py
  A   zope.security/trunk/src/zope/security/tests/redefineperms.zcml
  A   zope.security/trunk/src/zope/security/tests/test_module_directives.py

-=-
Modified: zope.security/trunk/CHANGES.txt
===================================================================
--- zope.security/trunk/CHANGES.txt	2009-01-28 15:59:18 UTC (rev 95341)
+++ zope.security/trunk/CHANGES.txt	2009-01-28 16:00:22 UTC (rev 95342)
@@ -10,6 +10,9 @@
 - Moved the `protectclass` module from `zope.app.security` to this
   package to reduce the number of dependencies on `zope.app.security`.
 
+- Moved the <module> directive implementation from `zope.app.security`
+  to this package.
+
 - Moved the <class> directive implementation from `zope.app.component`
   to this package.
 

Modified: zope.security/trunk/src/zope/security/meta.zcml
===================================================================
--- zope.security/trunk/src/zope/security/meta.zcml	2009-01-28 15:59:18 UTC (rev 95341)
+++ zope.security/trunk/src/zope/security/meta.zcml	2009-01-28 16:00:22 UTC (rev 95342)
@@ -51,4 +51,23 @@
 
     </meta:complexDirective>
   </meta:directives>
+
+  <meta:groupingDirective
+      name="module"
+      namespace="http://namespaces.zope.org/zope"
+      schema=".metadirectives.IModule"
+      handler="zope.configuration.config.GroupingContextDecorator" />
+
+  <meta:directive
+      name="allow"
+      namespace="http://namespaces.zope.org/zope"
+      schema=".metadirectives.IAllow"
+      handler=".metaconfigure.allow" />
+
+  <meta:directive
+      name="require"
+      namespace="http://namespaces.zope.org/zope"
+      schema=".metadirectives.IRequire"
+      handler=".metaconfigure.require" />
+
 </configure>

Modified: zope.security/trunk/src/zope/security/metaconfigure.py
===================================================================
--- zope.security/trunk/src/zope/security/metaconfigure.py	2009-01-28 15:59:18 UTC (rev 95341)
+++ zope.security/trunk/src/zope/security/metaconfigure.py	2009-01-28 16:00:22 UTC (rev 95342)
@@ -27,6 +27,8 @@
 from zope.schema.interfaces import IField
 from zope.configuration.exceptions import ConfigurationError
 
+from zope.security.checker import moduleChecker, Checker, defineChecker
+from zope.security.checker import CheckerPublic
 from zope.security.protectclass import protectLikeUnto, protectName
 from zope.security.protectclass import protectSetAttribute
 
@@ -170,3 +172,57 @@
         # same namespace, despite the utilities/content division
         utility(_context, IFactory, factoryObj,
                 permission=PublicPermission, name=id)
+
+
+def protectModule(module, name, permission):
+    """Set up a module checker to require a permission to access a name
+
+    If there isn't a checker for the module, create one.
+    """
+
+    checker = moduleChecker(module)
+    if checker is None:
+        checker = Checker({}, {})
+        defineChecker(module, checker)
+
+    if permission == 'zope.Public':
+        # Translate public permission to CheckerPublic
+        permission = CheckerPublic
+
+    # We know a dictionary get method was used because we set it
+    protections = checker.get_permissions
+    protections[name] = permission
+
+
+def _names(attributes, interfaces):
+    seen = {}
+    for name in attributes:
+        if not name in seen:
+            seen[name] = 1
+            yield name
+    for interface in interfaces:
+        for name in interface:
+            if not name in seen:
+                seen[name] = 1
+                yield name
+
+
+def allow(context, attributes=(), interface=()):
+
+    for name in _names(attributes, interface):
+        context.action(
+            discriminator=('http://namespaces.zope.org/zope:module',
+                           context.module, name),
+            callable = protectModule,
+            args = (context.module, name, 'zope.Public'),
+            )
+
+
+def require(context, permission, attributes=(), interface=()):
+    for name in _names(attributes, interface):
+        context.action(
+            discriminator=('http://namespaces.zope.org/zope:module',
+                           context.module, name),
+            callable = protectModule,
+            args = (context.module, name, permission),
+            )

Modified: zope.security/trunk/src/zope/security/metadirectives.py
===================================================================
--- zope.security/trunk/src/zope/security/metadirectives.py	2009-01-28 15:59:18 UTC (rev 95341)
+++ zope.security/trunk/src/zope/security/metadirectives.py	2009-01-28 16:00:22 UTC (rev 95342)
@@ -18,11 +18,15 @@
 __docformat__ = 'restructuredtext'
 
 import zope.configuration.fields
+from zope.configuration.fields import GlobalObject, GlobalInterface
+from zope.configuration.fields import Tokens, PythonIdentifier
 import zope.interface
 import zope.schema
+from zope.interface import Interface
 
 import zope.security.zcml
 from zope.security.i18n import ZopeMessageFactory as _
+from zope.security.zcml import Permission
 
 class IClassDirective(zope.interface.Interface):
     """Make statements about a class"""
@@ -141,3 +145,53 @@
                       " factory does"),
         required=False,
         )
+
+class IModule(Interface):
+    """Group security declarations about a module"""
+
+    module = GlobalObject(
+        title=u"Module",
+        description=u"Pointer to the module object.",
+        required=True)
+
+
+class IAllow(Interface):
+    """Allow access to selected module attributes
+
+    Access is unconditionally allowed to any names provided directly
+    in the attributes attribute or to any names defined by
+    interfaces listed in the interface attribute.
+    """
+
+    attributes = Tokens(
+        title=u"Attributes",
+        description=u"The attributes to provide access to.",
+        value_type = PythonIdentifier(),
+        required=False)
+
+    interface = Tokens(
+        title=u"Interface",
+        description=u"Interfaces whos names to provide access to. Access "
+                    u"will be provided to all of the names defined by the "
+                    u"interface(s). Multiple interfaces can be supplied.",
+        value_type = GlobalInterface(),
+        required=False)
+
+
+class IRequire(Interface):
+    """Require a permission to access selected module attributes
+
+    The given permission is required to access any names provided
+    directly in the attributes attribute or any names defined by
+    interfaces listed in the interface attribute.  
+    """
+
+    attributes = Tokens(
+        title=u"Attributes",
+        description=u"The attributes to require permission for.",
+        value_type = PythonIdentifier(),
+        required=False)
+
+    permission = Permission(
+        title=u"Permission ID",
+        description=u"The id of the permission to require.")

Copied: zope.security/trunk/src/zope/security/tests/redefineperms.zcml (from rev 95329, zope.app.security/trunk/src/zope/app/security/tests/redefineperms.zcml)
===================================================================
--- zope.security/trunk/src/zope/security/tests/redefineperms.zcml	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/redefineperms.zcml	2009-01-28 16:00:22 UTC (rev 95342)
@@ -0,0 +1,33 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:meta="http://namespaces.zope.org/meta"
+    i18n_domain="zope"
+    >
+
+  <include package="zope.security" file="meta.zcml" />
+
+  <meta:directive
+      name="dummy"
+      namespace="http://namespaces.zope.org/zope"
+      schema=".test_module_directives.IDummy"
+      handler=".test_module_directives.dummy" />
+
+  <permission
+      id="zope.View"
+      title="[view-permission] View"
+      />
+
+  <permission
+      id="zope.Security"
+      title="[change-security-settings-permission] Change security settings"
+      />
+
+  <meta:redefinePermission
+      from="zope.View"
+      to="zope.Security"
+      />
+
+  <dummy
+      perm="zope.View" />
+
+</configure>


Property changes on: zope.security/trunk/src/zope/security/tests/redefineperms.zcml
___________________________________________________________________
Added: cvs2svn:cvs-rev
   + 1.1
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native

Copied: zope.security/trunk/src/zope/security/tests/test_module_directives.py (from rev 95329, zope.app.security/trunk/src/zope/app/security/tests/test_directives.py)
===================================================================
--- zope.security/trunk/src/zope/security/tests/test_module_directives.py	                        (rev 0)
+++ zope.security/trunk/src/zope/security/tests/test_module_directives.py	2009-01-28 16:00:22 UTC (rev 95342)
@@ -0,0 +1,236 @@
+##############################################################################
+#
+# Copyright (c) 2003 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.
+#
+##############################################################################
+"""Directives Tests
+
+$Id$
+"""
+import unittest
+from pprint import PrettyPrinter
+
+import zope.security.zcml
+from zope.interface import Interface, Attribute
+from zope.testing import doctest
+from zope.component.testing import setUp, tearDown, PlacelessSetup
+from zope.configuration import xmlconfig
+
+from zope.security import metaconfigure
+
+def pprint(ob, width=70):
+    PrettyPrinter(width=width).pprint(ob)
+
+class I1(Interface):
+    def x(): pass
+    y = Attribute("Y")
+
+class I2(I1):
+    def a(): pass
+    b = Attribute("B")
+
+test_perm = 'zope.security.metaconfigure.test'
+test_bad_perm = 'zope.security.metaconfigure.bad'
+
+def test_protectModule():
+    """
+    >>> from zope.security.tests import test_directives
+    >>> from zope.security.interfaces import IPermission
+    >>> from zope.security.permission import Permission
+
+    >>> from zope.component import provideUtility
+
+    Initially, there's no checker defined for the module:
+
+    >>> from zope.security.checker import moduleChecker
+    >>> moduleChecker(test_directives)
+        
+    >>> perm = Permission(test_perm, '')
+    >>> provideUtility(perm, IPermission, test_perm)
+    >>> metaconfigure.protectModule(test_directives, 'foo', test_perm)
+
+    Now, the checker should exist and have an access dictionary with the
+    name and permission:
+
+    >>> checker = moduleChecker(test_directives)
+    >>> cdict = checker.get_permissions
+    >>> pprint(cdict)
+    {'foo': 'zope.security.metaconfigure.test'}
+    
+    If we define additional names, they will be added to the dict:
+
+    >>> metaconfigure.protectModule(test_directives, 'bar', test_perm)
+    >>> metaconfigure.protectModule(test_directives, 'baz', test_perm)
+    >>> pprint(cdict)
+    {'bar': 'zope.security.metaconfigure.test',
+     'baz': 'zope.security.metaconfigure.test',
+     'foo': 'zope.security.metaconfigure.test'}
+        
+    """
+
+def test_allow():
+    """
+
+    The allow directive creates actions for each named defined
+    directly, or via interface:
+
+    >>> class Context(object):
+    ...     def __init__(self):
+    ...         self.actions = []
+    ...
+    ...     def action(self, discriminator, callable, args):
+    ...         self.actions.append(
+    ...             {'discriminator': discriminator,
+    ...              'callable': int(callable is metaconfigure.protectModule),
+    ...              'args': args})
+    ...
+    ...     module='testmodule'
+
+    >>> context = Context()
+    >>> metaconfigure.allow(context, attributes=['foo', 'bar'],
+    ...                     interface=[I1, I2])
+
+    >>> context.actions.sort(
+    ...    lambda a, b: cmp(a['discriminator'], b['discriminator']))
+    >>> pprint(context.actions)
+    [{'args': ('testmodule', 'a', 'zope.Public'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'a')},
+     {'args': ('testmodule', 'b', 'zope.Public'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'b')},
+     {'args': ('testmodule', 'bar', 'zope.Public'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'bar')},
+     {'args': ('testmodule', 'foo', 'zope.Public'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'foo')},
+     {'args': ('testmodule', 'x', 'zope.Public'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'x')},
+     {'args': ('testmodule', 'y', 'zope.Public'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'y')}]
+
+    """
+
+def test_require():
+    """
+
+    The allow directive creates actions for each named defined
+    directly, or via interface:
+
+    >>> class Context(object):
+    ...     def __init__(self):
+    ...         self.actions = []
+    ...
+    ...     def action(self, discriminator, callable, args):
+    ...         self.actions.append(
+    ...             {'discriminator': discriminator,
+    ...              'callable': int(callable is metaconfigure.protectModule),
+    ...              'args': args})
+    ...
+    ...     module='testmodule'
+
+    >>> context = Context()
+    >>> metaconfigure.require(context, attributes=['foo', 'bar'],
+    ...                       interface=[I1, I2], permission='p')
+
+    >>> context.actions.sort(
+    ...    lambda a, b: cmp(a['discriminator'], b['discriminator']))
+    >>> pprint(context.actions)
+    [{'args': ('testmodule', 'a', 'p'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'a')},
+     {'args': ('testmodule', 'b', 'p'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'b')},
+     {'args': ('testmodule', 'bar', 'p'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'bar')},
+     {'args': ('testmodule', 'foo', 'p'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'foo')},
+     {'args': ('testmodule', 'x', 'p'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'x')},
+     {'args': ('testmodule', 'y', 'p'),
+      'callable': 1,
+      'discriminator': ('http://namespaces.zope.org/zope:module',
+                        'testmodule',
+                        'y')}]
+    
+    """
+
+class IDummy(Interface):
+
+    perm = zope.security.zcml.Permission(title=u'')
+
+perms = []
+
+def dummy(context_, perm):
+    global perms
+    perms.append(perm)
+
+
+class DirectivesTest(PlacelessSetup, unittest.TestCase):
+
+    def setUp(self):
+        super(DirectivesTest, self).setUp()
+        from zope.security import tests
+        self.context = xmlconfig.file("redefineperms.zcml", tests)
+
+    def tearDown(self):
+        super(DirectivesTest, self).tearDown()
+        perms.remove('zope.Security')
+
+    def testRedefinePermission(self):
+        self.assertEqual(perms, ['zope.Security'])
+
+def setUpAuth(test=None):
+    setUp(test)
+
+def zcml(s):
+    context = xmlconfig.file('meta.zcml', package=zope.security)
+    xmlconfig.string(s, context)
+
+def reset():
+    tearDown()
+    setUpAuth()
+
+def test_suite():
+    return unittest.TestSuite((
+        doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
+        doctest.DocTestSuite('zope.security.zcml'),
+        unittest.makeSuite(DirectivesTest),
+        ))


Property changes on: zope.security/trunk/src/zope/security/tests/test_module_directives.py
___________________________________________________________________
Added: cvs2svn:cvs-rev
   + 1.2
Added: svn:keywords
   + Id
Added: svn:mergeinfo
   + 
Added: svn:eol-style
   + native



More information about the Checkins mailing list