[z3-checkins] r5183 - in z3/Five/trunk: . directives handlers security tests

dreamcatcher at codespeak.net dreamcatcher at codespeak.net
Sun Jun 20 17:17:54 MEST 2004


Author: dreamcatcher
Date: Sun Jun 20 17:17:53 2004
New Revision: 5183

Modified:
   z3/Five/trunk/directives/content.py
   z3/Five/trunk/fiveconfigure.py
   z3/Five/trunk/handlers/content.py
   z3/Five/trunk/meta.zcml
   z3/Five/trunk/monkey.py
   z3/Five/trunk/permissions.zcml
   z3/Five/trunk/security/permission.py
   z3/Five/trunk/tests/test_security.py
   z3/Five/trunk/viewable.py
   z3/Five/trunk/zcml.py
Log:
Add deny directive. Add one test to make sure declarations are equivalent. Tried to make security stick on auto-generated metaclasses, but its not as easy as it seems. The code in question is marked with XXX.

Modified: z3/Five/trunk/directives/content.py
==============================================================================
--- z3/Five/trunk/directives/content.py	(original)
+++ z3/Five/trunk/directives/content.py	Sun Jun 20 17:17:53 2004
@@ -92,3 +92,21 @@
         value_type=GlobalObject()
         )
 
+class IDenySubdirective(Interface):
+    """
+    Declare a part of the class to be private (that is,
+    can't be accessed through the web). Only one of the following
+    two attributes may be used.
+    """
+
+    attributes = Tokens(
+        title=u"Attributes",
+        required=False,
+        value_type=PythonIdentifier()
+        )
+
+    interface = Tokens(
+        title=u"Interface",
+        required=False,
+        value_type=GlobalObject()
+        )

Modified: z3/Five/trunk/fiveconfigure.py
==============================================================================
--- z3/Five/trunk/fiveconfigure.py	(original)
+++ z3/Five/trunk/fiveconfigure.py	Sun Jun 20 17:17:53 2004
@@ -11,6 +11,7 @@
 from viewable import Viewable
 from api import BrowserView
 from metaclass import makeClass
+from security.permission import getSecurityInfo
 
 #def handler(serviceName, methodName, *args, **kwargs):
 #    method=getattr(getService(serviceName), methodName)
@@ -22,7 +23,7 @@
 
 def page(_context, name, for_,
          layer='default', template=None, class_=None,
-         attribute='__call__', menu=None, title=None, 
+         attribute='__call__', menu=None, title=None,
          ):
 
     try:
@@ -53,12 +54,18 @@
                 raise ConfigurationError(
                     "The provided class doesn't have the specified attribute "
                     )
+        cdict = getSecurityInfo(class_)
+        # XXX this is not working currently
+        # because by the time the metaclass is created,
+        # the security decls directives haven't been
+        # executed yet.
         if template:
             # class and template
             new_class = SimpleViewClass(
-                template, bases=(class_, ))
+                template, bases=(class_, ),
+                cdict=cdict)
         else:
-            cdict = {'__page_attribute__': attribute }
+            cdict.update({'__page_attribute__': attribute})
             new_class = makeClass(class_.__name__,
                              (class_, simple),
                              cdict)
@@ -83,7 +90,7 @@
             discriminator = None,
             callable = provideInterface,
             args = ('', for_)
-            )        
+            )
 
 def implements(_context, class_, interface):
     for interface in interface:
@@ -110,7 +117,7 @@
         callable = classViewable,
         args = (class_,)
         )
-        
+
 def layer(_context, name):
 
     _context.action(
@@ -153,15 +160,16 @@
 from zope.app.pagetemplate.simpleviewclass import simple as svc_simple
 from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
 
-def SimpleViewClass(src, offering=None, used_for=None, bases=()):
+def SimpleViewClass(src, offering=None, used_for=None, bases=(), cdict=None):
     if offering is None:
         offering = sys._getframe(1).f_globals
-        
-    #bases += (svc_simple, )
 
-    class_ = makeClass("SimpleViewClass from %s" % src, bases,
-                       {'index': ViewPageTemplateFile(src, offering),
-                        })
+    #bases += (svc_simple, )
+    # XXX needs to deal with security from the bases?
+    if cdict is None:
+        cdict = {}
+    cdict.update({'index': ViewPageTemplateFile(src, offering)})
+    class_ = makeClass("SimpleViewClass from %s" % src, bases, cdict)
 
     if used_for is not None:
         class_.__used_for__ = used_for

Modified: z3/Five/trunk/handlers/content.py
==============================================================================
--- z3/Five/trunk/handlers/content.py	(original)
+++ z3/Five/trunk/handlers/content.py	Sun Jun 20 17:17:53 2004
@@ -25,7 +25,7 @@
 from Globals import InitializeClass
 from Products.Five.metaconfigure import interface as provideInterface
 from Products.Five.security.interfaces import IPermission
-from Products.Five.security.permission import CheckerPublic
+from Products.Five.security.permission import CheckerPublic, CheckerPrivate
 
 def dottedName(klass):
     if klass is None:
@@ -76,6 +76,9 @@
         """Like require, but with permission_id zope.Public"""
         return self.require(_context, CheckerPublic, attributes, interface)
 
+    def deny(self, _context, attributes=None, interface=None):
+        """Like require, but with permission_id zope.Private"""
+        return self.require(_context, CheckerPrivate, attributes, interface)
 
     def __protectByInterface(self, interface, permission_id):
         "Set a permission on names in an interface."
@@ -121,9 +124,14 @@
 def protectName(klass, name, permission_id):
     print klass, name, permission_id
     security = _getSecurity(klass)
+    # Zope 2 uses string, not unicode yet
+    name = str(name)
     if permission_id == CheckerPublic:
         security.declarePublic(name)
+    elif permission_id == CheckerPrivate:
+        security.declarePrivate(name)
     else:
         permission = getUtility(IPermission, name=permission_id)
-        security.declareProtected(permission.title, name)
-
+        # Zope 2 uses string, not unicode yet
+        perm = str(permission.title)
+        security.declareProtected(perm, name)

Modified: z3/Five/trunk/meta.zcml
==============================================================================
--- z3/Five/trunk/meta.zcml	(original)
+++ z3/Five/trunk/meta.zcml	Sun Jun 20 17:17:53 2004
@@ -92,6 +92,11 @@
           schema=".directives.content.IAllowSubdirective"
           />
 
+      <meta:subdirective
+          name="deny"
+          schema=".directives.content.IDenySubdirective"
+          />
+
     </meta:complexDirective>
 
     <!-- specific to Five -->

Modified: z3/Five/trunk/monkey.py
==============================================================================
--- z3/Five/trunk/monkey.py	(original)
+++ z3/Five/trunk/monkey.py	Sun Jun 20 17:17:53 2004
@@ -1,24 +1,24 @@
 
 def monkeyPatch():
     """Trigger all monkey patches needed to make Five work.
-    
+
     This adjusts Zope 2 classes to make them work with Zope 3.
 
     Monkey patches are kept to a minimum level.
     """
-    
+
     from ZPublisher.HTTPRequest import HTTPRequest
-    
+
     def getPresentationSkin(self):
         return getattr(self, '_presentation_skin', None)
 
     def setPresentationSkin(self, skin):
         self._presentation_skin = skin
-        
+
     HTTPRequest.getPresentationSkin = getPresentationSkin
     HTTPRequest.setPresentationSkin = setPresentationSkin
     HTTPRequest.debug = DebugFlags()
-    
+
 class DebugFlags(object):
     """Debugging flags."""
 

Modified: z3/Five/trunk/permissions.zcml
==============================================================================
--- z3/Five/trunk/permissions.zcml	(original)
+++ z3/Five/trunk/permissions.zcml	Sun Jun 20 17:17:53 2004
@@ -3,7 +3,7 @@
 
   <permission
     id="zope.ViewManagementScreens"
-    title="View Management Screens"
+    title="View management screens"
     />
 
 </configure>

Modified: z3/Five/trunk/security/permission.py
==============================================================================
--- z3/Five/trunk/security/permission.py	(original)
+++ z3/Five/trunk/security/permission.py	Sun Jun 20 17:17:53 2004
@@ -3,6 +3,17 @@
 from Products.Five.security.interfaces import IPermission
 
 CheckerPublic = 'zope.Public'
+CheckerPrivate = 'zope.Private'
+
+def getSecurityInfo(klass):
+    sec = {}
+    info = vars(klass)
+    if info.has_key('__ac_permissions__'):
+        sec['__ac_permissions__'] = info['__ac_permissions__']
+    for k, v in info.items():
+        if k.endswith('__roles__'):
+            sec[k] = v
+    return sec
 
 def checkPermission(context, permission_id):
     """Check whether a given permission exists in the provided context.

Modified: z3/Five/trunk/tests/test_security.py
==============================================================================
--- z3/Five/trunk/tests/test_security.py	(original)
+++ z3/Five/trunk/tests/test_security.py	Sun Jun 20 17:17:53 2004
@@ -23,29 +23,24 @@
 
 ZopeTestCase.installProduct('Five')
 
+from zope.configuration import xmlconfig
+from Products.Five import zcml
 from AccessControl import ClassSecurityInfo
+from Globals import InitializeClass
 
-class Dummy:
-
+class Dummy1:
     def foo(self): pass
     def bar(self): pass
     def baz(self): pass
     def keg(self): pass
     def wot(self): pass
 
-class Dummy1(Dummy):
-
-    security = ClassSecurityInfo()
-    security.declareProtected('View', 'foo')
-
-class Dummy2(Dummy):
-
+class Dummy2(Dummy1):
     security = ClassSecurityInfo()
     security.declarePublic('foo')
-    security.declareProtected('View', 'bar')
+    security.declareProtected('View management screens', 'bar')
     security.declarePrivate('baz')
-    security.declareProtected('Edit', 'keg')
-
+    security.declareProtected('View management screens', 'keg')
 
 class SecurityTestCase(ZopeTestCase.ZopeTestCase):
 
@@ -62,9 +57,58 @@
     def test_initialize(self):
         pass
 
+class SecurityEquivalenceTestCase(ZopeTestCase.ZopeTestCase):
+
+    def setUp(self):
+        self.dummy1 = Dummy1
+        self.dummy2 = Dummy2
+        zcml.initialize()
+
+    def tearDown(self):
+        zcml.reset()
+
+    def test_equivalence(self):
+        self.failIf(hasattr(self.dummy1, '__ac_permissions__'))
+        self.failIf(hasattr(self.dummy2, '__ac_permissions__'))
+
+        decl = """
+        <configure xmlns="http://namespaces.zope.org/zope"
+            xmlns:five="http://namespaces.zope.org/five">
+
+        <five:content
+            class="Five.tests.test_security.Dummy1">
+
+          <allow attributes="foo" />
+
+          <deny attributes="baz" />
+
+          <require attributes="bar keg"
+	      permission="zope.ViewManagementScreens"
+	      />
+
+        </five:content>
+        </configure>
+        """
+        zcml.string(decl)
+        InitializeClass(self.dummy2)
+        import pdb
+        pdb.set_trace()
+        ac1 = getattr(self.dummy1, '__ac_permissions__')
+        ac2 = getattr(self.dummy2, '__ac_permissions__')
+        self.assertEquals(ac1, ac2)
+        foo_roles1 = getattr(self.dummy1, 'foo__roles__')
+        baz_roles1 = getattr(self.dummy1, 'baz__roles__')
+        self.assertEquals(foo_roles1, None)
+        self.assertEquals(baz_roles1, ())
+
+        foo_roles2 = getattr(self.dummy2, 'foo__roles__')
+        baz_roles2 = getattr(self.dummy2, 'baz__roles__')
+        self.assertEquals(foo_roles2, None)
+        self.assertEquals(baz_roles2, ())
 
 def test_suite():
     suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(SecurityEquivalenceTestCase))
     suite.addTest(unittest.makeSuite(SecurityTestCase))
     return suite
 

Modified: z3/Five/trunk/viewable.py
==============================================================================
--- z3/Five/trunk/viewable.py	(original)
+++ z3/Five/trunk/viewable.py	Sun Jun 20 17:17:53 2004
@@ -8,10 +8,10 @@
     implements(IBrowserRequest)
 
     debug = DebugFlags()
-    
+
     def getPresentationSkin(self):
         return None
-    
+
 class Viewable:
     """A mixin to make an object viewable using the Zope 3 system.
     """

Modified: z3/Five/trunk/zcml.py
==============================================================================
--- z3/Five/trunk/zcml.py	(original)
+++ z3/Five/trunk/zcml.py	Sun Jun 20 17:17:53 2004
@@ -13,6 +13,11 @@
     _initialized = True
     return _global_context
 
+def reset():
+    global _initialized, _global_context
+    _initialized = False
+    _global_context = None
+
 def process(file, execute=True, package=None):
     """Process a ZCML file.
 
@@ -23,3 +28,13 @@
     context = initialize()
     return xmlconfig.file(file, context=context, execute=execute,
                           package=package)
+
+def string(s, execute=True):
+    """Process a ZCML string.
+
+    Note that this can be called multiple times, unlike in Zope 3. This
+    is needed because in Zope 2 we don't (yet) have a master ZCML file
+    which can include all the others.
+    """
+    context = initialize()
+    return xmlconfig.string(s, context=context, execute=execute)


More information about the z3-checkins mailing list