[z3-checkins] r5188 - in z3/Five/trunk: . demo/FiveViewsDemo
directives handlers security tests
dreamcatcher at codespeak.net
dreamcatcher at codespeak.net
Mon Jun 21 02:08:58 MEST 2004
Author: dreamcatcher
Date: Mon Jun 21 02:08:57 2004
New Revision: 5188
Modified:
z3/Five/trunk/browser.py
z3/Five/trunk/demo/FiveViewsDemo/configure.zcml
z3/Five/trunk/demo/FiveViewsDemo/interfaces.py
z3/Five/trunk/demo/FiveViewsDemo/simplecontent.py
z3/Five/trunk/directives/content.py
z3/Five/trunk/fiveconfigure.py
z3/Five/trunk/fivedirectives.py
z3/Five/trunk/handlers/content.py
z3/Five/trunk/security/permission.py
z3/Five/trunk/tests/test_security.py
z3/Five/trunk/viewattribute.py
Log:
Implement security for five:page directive. Use five:content for SimpleContent. Add a test for five:page and improve test for five:content security decls.
Modified: z3/Five/trunk/browser.py
==============================================================================
--- z3/Five/trunk/browser.py (original)
+++ z3/Five/trunk/browser.py Mon Jun 21 02:08:57 2004
@@ -1,25 +1,32 @@
import Acquisition
-from AccessControl import ClassSecurityInfo
+from AccessControl import ClassSecurityInfo, getSecurityManager
+from zExceptions import Unauthorized
from Globals import InitializeClass
class BrowserView(Acquisition.Explicit):
security = ClassSecurityInfo()
-
+
def __init__(self, context, request):
self.context = context
self.request = request
# XXX do not create any methods on the subclass called index_html,
# as this makes Zope 2 traverse into that first!
-
+
def __call__(self, *args, **kw):
# XXX this is definitely not the way Zope 3 does it..
if hasattr(self, 'index'):
- return self.index(self, *args, **kw)
- attr = self.__page_attribute__
+ attr = 'index'
+ else:
+ attr = self.__page_attribute__
+ meth = getattr(self, attr)
+ security_manager = getSecurityManager()
+ if not security_manager.validate(meth, self, attr, meth):
+ raise Unauthorized
if attr == '__call__':
raise AttributeError("__call__")
- meth = getattr(self, attr)
+ elif attr == 'index':
+ return meth(self, *args, **kw)
return meth(*args, **kw)
-
+
InitializeClass(BrowserView)
Modified: z3/Five/trunk/demo/FiveViewsDemo/configure.zcml
==============================================================================
--- z3/Five/trunk/demo/FiveViewsDemo/configure.zcml (original)
+++ z3/Five/trunk/demo/FiveViewsDemo/configure.zcml Mon Jun 21 02:08:57 2004
@@ -6,6 +6,7 @@
class=".browser.SimpleContentView"
attribute="eagle"
name="eagle.txt"
+ permission="zope.ViewManagementScreens"
/>
<five:implements
@@ -22,28 +23,19 @@
class=".browser.SimpleFolderView"
attribute="eagle"
name="eagle.txt"
+ permission="zope.Public"
/>
- <five:content class=".browser.SimpleContentView">
+ <five:content class=".simplecontent.SimpleContent">
- <five:require attributes="eagle"
- permission="zope.ViewManagementScreens"
- />
-
- </five:content>
+ <allow interface=".interfaces.IPublicSimpleContent" />
- <five:content class=".browser.SimpleFolderView">
+ <deny interface=".interfaces.IPrivateSimpleContent" />
- <implements interface=".interfaces.ISimpleFolderView"
- />
-
- <require interface=".interfaces.IWriteSimpleFolderView"
- permission="zope.ViewManagementScreens"
+ <require permission="zope.ViewManagementScreens"
+ interface=".interfaces.IProtectedSimpleContent"
/>
- <allow interface=".interfaces.IReadSimpleFolderView"
- />
-
</five:content>
</configure>
Modified: z3/Five/trunk/demo/FiveViewsDemo/interfaces.py
==============================================================================
--- z3/Five/trunk/demo/FiveViewsDemo/interfaces.py (original)
+++ z3/Five/trunk/demo/FiveViewsDemo/interfaces.py Mon Jun 21 02:08:57 2004
@@ -1,9 +1,26 @@
from zope.interface import Interface
-class ISimpleContent(Interface):
+class IPublicSimpleContent(Interface):
+
def mymethod():
"""This is just a sample method.
"""
+class IPrivateSimpleContent(Interface):
+
+ def myprivatemethod():
+ """This is just a sample method.
+ """
+
+class IProtectedSimpleContent(Interface):
+
+ def myprotectedmethod():
+ """This is just a sample method.
+ """
+
+class ISimpleContent(IPublicSimpleContent,
+ IPrivateSimpleContent,
+ IProtectedSimpleContent):
+ """A Simple Content Interface"""
class IFolder(Interface):
pass
Modified: z3/Five/trunk/demo/FiveViewsDemo/simplecontent.py
==============================================================================
--- z3/Five/trunk/demo/FiveViewsDemo/simplecontent.py (original)
+++ z3/Five/trunk/demo/FiveViewsDemo/simplecontent.py Mon Jun 21 02:08:57 2004
@@ -1,28 +1,33 @@
+from zope.interface import implements
+
from OFS.SimpleItem import SimpleItem
-from Globals import InitializeClass
-from AccessControl import ClassSecurityInfo
-from helpers import add_and_edit
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.Five.api import Viewable
-from zope.interface import implements
+
from interfaces import ISimpleContent
+from helpers import add_and_edit
class SimpleContent(SimpleItem, Viewable):
+ """A Simple Content"""
implements(ISimpleContent)
-
meta_type = 'SimpleContent'
- security = ClassSecurityInfo()
def __init__(self, id, title):
self.id = id
self.title = title
-
- security.declarePublic('mymethod')
+
def mymethod(self):
+ """A public method"""
return "Hello world"
-InitializeClass(SimpleContent)
+ def myprivatemethod(self):
+ """A private method"""
+ return "Hello private world"
+
+ def myprotectedmethod(self):
+ """A protected method"""
+ return "Hello protected world"
manage_addSimpleContentForm = PageTemplateFile(
"www/simpleContentAdd", globals(),
Modified: z3/Five/trunk/directives/content.py
==============================================================================
--- z3/Five/trunk/directives/content.py (original)
+++ z3/Five/trunk/directives/content.py Mon Jun 21 02:08:57 2004
@@ -18,7 +18,6 @@
from zope.configuration.fields import GlobalObject, Tokens, \
PythonIdentifier, MessageID
from zope.schema import TextLine, Id
-
from Products.Five.security.fields import Permission
class IContentDirective(Interface):
Modified: z3/Five/trunk/fiveconfigure.py
==============================================================================
--- z3/Five/trunk/fiveconfigure.py (original)
+++ z3/Five/trunk/fiveconfigure.py Mon Jun 21 02:08:57 2004
@@ -11,7 +11,8 @@
from viewable import Viewable
from api import BrowserView
from metaclass import makeClass
-from security.permission import getSecurityInfo
+from security.permission import getSecurityInfo, CheckerPublic
+from handlers.content import protectName, initializeClass
#def handler(serviceName, methodName, *args, **kwargs):
# method=getattr(getService(serviceName), methodName)
@@ -24,6 +25,7 @@
def page(_context, name, for_,
layer='default', template=None, class_=None,
attribute='__call__', menu=None, title=None,
+ permission=CheckerPublic
):
try:
@@ -60,6 +62,7 @@
# the security decls directives haven't been
# executed yet.
if template:
+ attribute = 'index'
# class and template
new_class = SimpleViewClass(
template, bases=(class_, ),
@@ -72,6 +75,7 @@
else:
# template
+ attribute = 'index'
new_class = SimpleViewClass(template, bases=(BrowserView,))
_handle_for(_context, for_)
@@ -83,6 +87,17 @@
IBrowserRequest, new_class, name, [for_], Interface, layer,
_context.info),
)
+ _context.action(
+ discriminator = ('five:protectName', new_class, attribute),
+ callable = protectName,
+ args = (new_class, attribute, permission)
+ )
+ _context.action(
+ discriminator = ('five:initialize:class', new_class),
+ callable = initializeClass,
+ args = (new_class,)
+ )
+
def _handle_for(_context, for_):
if for_ is not None:
Modified: z3/Five/trunk/fivedirectives.py
==============================================================================
--- z3/Five/trunk/fivedirectives.py (original)
+++ z3/Five/trunk/fivedirectives.py Mon Jun 21 02:08:57 2004
@@ -2,6 +2,7 @@
from zope.configuration.fields import GlobalObject, Tokens,\
PythonIdentifier, MessageID
from zope.schema import TextLine, Id
+from Products.Five.security.fields import Permission
class IBasicViewInformation(Interface):
"""
@@ -89,6 +90,15 @@
required=False
)
+ permission = Permission(
+ title=u"Permission",
+ description=u"""
+ Specifies the permission by id that will be required to
+ access or mutate the attributes and methods specified.""",
+ required=False
+ )
+
+
class IPageDirective(IPagesDirective, IPagesPageSubdirective):
"""
The page directive is used to create views that provide a single
Modified: z3/Five/trunk/handlers/content.py
==============================================================================
--- z3/Five/trunk/handlers/content.py (original)
+++ z3/Five/trunk/handlers/content.py Mon Jun 21 02:08:57 2004
@@ -89,7 +89,7 @@
def __protectName(self, name, permission_id):
"Set a permission on a particular name."
self.__context.action(
- discriminator = ('protectName', self.__class, name),
+ discriminator = ('five:protectName', self.__class, name),
callable = protectName,
args = (self.__class, name, permission_id)
)
@@ -109,7 +109,6 @@
def initializeClass(klass):
- print 'Initializing class %r' % klass
InitializeClass(klass)
def _getSecurity(klass):
@@ -122,7 +121,6 @@
return security
def protectName(klass, name, permission_id):
- print klass, name, permission_id
security = _getSecurity(klass)
# Zope 2 uses string, not unicode yet
name = str(name)
Modified: z3/Five/trunk/security/permission.py
==============================================================================
--- z3/Five/trunk/security/permission.py (original)
+++ z3/Five/trunk/security/permission.py Mon Jun 21 02:08:57 2004
@@ -15,6 +15,15 @@
sec[k] = v
return sec
+def clearSecurityInfo(klass):
+ sec = {}
+ info = vars(klass)
+ if info.has_key('__ac_permissions__'):
+ delattr(klass, '__ac_permissions__')
+ for k, v in info.items():
+ if k.endswith('__roles__'):
+ delattr(klass, k)
+
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 Mon Jun 21 02:08:57 2004
@@ -24,11 +24,29 @@
ZopeTestCase.installProduct('Five')
from zope.configuration import xmlconfig
+from zope.component import getView
+from zope.interface import Interface, implements
+from zope.testing.cleanup import CleanUp
from Products.Five import zcml
+from Products.Five.browser import BrowserView
+from Products.Five.viewable import FakeRequest
+from Products.Five.security.permission import clearSecurityInfo
from AccessControl import ClassSecurityInfo
+from AccessControl.PermissionRole import PermissionRole
from Globals import InitializeClass
+class IDummy(Interface):
+ """Just a marker interface"""
+
+class DummyView(BrowserView):
+ """A dummy view"""
+
+ def foo(self):
+ """A foo"""
+ return 'A foo view'
+
class Dummy1:
+ implements(IDummy)
def foo(self): pass
def bar(self): pass
def baz(self): pass
@@ -42,29 +60,59 @@
security.declarePrivate('baz')
security.declareProtected('View management screens', 'keg')
-class SecurityTestCase(ZopeTestCase.ZopeTestCase):
+class PageSecurityTestCase(CleanUp, ZopeTestCase.ZopeTestCase):
+
+ def setUp(self):
+ super(PageSecurityTestCase, self).setUp()
+ self.dummy1 = Dummy1
+ zcml.initialize()
- def test_require(self):
- # Need to use xmlconfig() to run a
- # small zcml snippet and then check
- # the class __ac_permissions__ to see
- # if the declaration took effect.
- pass
+ def tearDown(self):
+ super(PageSecurityTestCase, self).tearDown()
+ clearSecurityInfo(self.dummy1)
+ zcml.reset()
- def test_allow(self):
- pass
+ def test_page_security(self):
+ self.failIf(hasattr(self.dummy1, '__ac_permissions__'))
- def test_initialize(self):
- pass
+ decl = """
+ <configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:five="http://namespaces.zope.org/five">
-class SecurityEquivalenceTestCase(ZopeTestCase.ZopeTestCase):
+ <five:page
+ for="Five.tests.test_security.IDummy"
+ class="Five.tests.test_security.DummyView"
+ attribute="foo"
+ name="foo.txt"
+ permission="zope.ViewManagementScreens"
+ />
+
+ </configure>
+ """
+ zcml.string(decl)
+ request = FakeRequest()
+ view = getView(Dummy1(), 'foo.txt', request)
+
+ ac = getattr(view, '__ac_permissions__')
+ ex_ac = (('View management screens', ('foo',)),)
+ self.assertEquals(ac, ex_ac)
+ foo_roles = getattr(view, 'foo__roles__', None)
+ self.failIf(foo_roles is None)
+ self.failIf(foo_roles == ())
+ self.assertEquals(foo_roles.__of__(view), ('Manager',))
+
+class SecurityEquivalenceTestCase(CleanUp, ZopeTestCase.ZopeTestCase):
def setUp(self):
+ super(SecurityEquivalenceTestCase, self).setUp()
self.dummy1 = Dummy1
self.dummy2 = Dummy2
zcml.initialize()
def tearDown(self):
+ super(SecurityEquivalenceTestCase, self).tearDown()
+ clearSecurityInfo(self.dummy1)
+ clearSecurityInfo(self.dummy2)
zcml.reset()
def test_equivalence(self):
@@ -91,23 +139,39 @@
"""
zcml.string(decl)
InitializeClass(self.dummy2)
+
ac1 = getattr(self.dummy1, '__ac_permissions__')
ac2 = getattr(self.dummy2, '__ac_permissions__')
self.assertEquals(ac1, ac2)
+
+ bar_roles1 = getattr(self.dummy1, 'bar__roles__').__of__(self.dummy1)
+ self.assertEquals(bar_roles1.__of__(self.dummy1), ('Manager',))
+
+ keg_roles1 = getattr(self.dummy1, 'keg__roles__').__of__(self.dummy1)
+ self.assertEquals(keg_roles1.__of__(self.dummy1), ('Manager',))
+
foo_roles1 = getattr(self.dummy1, 'foo__roles__')
- baz_roles1 = getattr(self.dummy1, 'baz__roles__')
self.assertEquals(foo_roles1, None)
+
+ baz_roles1 = getattr(self.dummy1, 'baz__roles__')
self.assertEquals(baz_roles1, ())
+ bar_roles2 = getattr(self.dummy2, 'bar__roles__').__of__(self.dummy2)
+ self.assertEquals(bar_roles2.__of__(self.dummy2), ('Manager',))
+
+ keg_roles2 = getattr(self.dummy2, 'keg__roles__').__of__(self.dummy2)
+ self.assertEquals(keg_roles2.__of__(self.dummy2), ('Manager',))
+
foo_roles2 = getattr(self.dummy2, 'foo__roles__')
- baz_roles2 = getattr(self.dummy2, 'baz__roles__')
self.assertEquals(foo_roles2, None)
+
+ baz_roles2 = getattr(self.dummy2, 'baz__roles__')
self.assertEquals(baz_roles2, ())
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(SecurityEquivalenceTestCase))
- suite.addTest(unittest.makeSuite(SecurityTestCase))
+ suite.addTest(unittest.makeSuite(PageSecurityTestCase))
return suite
if __name__ == '__main__':
Modified: z3/Five/trunk/viewattribute.py
==============================================================================
--- z3/Five/trunk/viewattribute.py (original)
+++ z3/Five/trunk/viewattribute.py Mon Jun 21 02:08:57 2004
@@ -8,10 +8,10 @@
pass
class ViewAttribute(Acquisition.Explicit):
-
+
def __init__(self, view_type):
self._view_type = view_type
-
+
def index_html(self):
"""Default method on view
"""
@@ -26,9 +26,9 @@
security_manager = getSecurityManager()
if not security_manager.validate(method_on_view, obj, 'index_html',
method_on_view):
- raise Unauthorized
+ raise Unauthorized
return method_on_view()
-
+
def __getitem__(self, name):
"""Get correct method on view
"""
@@ -40,10 +40,10 @@
view = view.__of__(obj)
# look up method
method_on_view = getattr(view, name, None)
-
+
if method_on_view is None:
# we do not accept calling unknown methods
- raise FiveViewError, "Unknown view method: %s" % name
-
+ raise FiveViewError, "Unknown view method: %s" % name
+
# let the ZPublisher do the calling, its security kicks in
return method_on_view
More information about the z3-checkins
mailing list