[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