Skip to content

Commit

Permalink
Port whitelist creation from zope.browserpage (#643)
Browse files Browse the repository at this point in the history
+ Add tests for allowed_interface and allowed_attributes..
  • Loading branch information
pbauer authored and Michael Howitz committed Jun 18, 2019
1 parent 4b73a0f commit d6e4974
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 14 deletions.
2 changes: 1 addition & 1 deletion constraints.txt
Expand Up @@ -45,7 +45,7 @@ zodbpickle==1.0.4
zope.annotation==4.7.0
zope.browser==2.3
zope.browsermenu==4.4
zope.browserpage==4.3.0
zope.browserpage==4.4.0
zope.browserresource==4.3
zope.cachedescriptors==4.3.1
zope.component==4.5
Expand Down
2 changes: 1 addition & 1 deletion requirements-full.txt
Expand Up @@ -45,7 +45,7 @@ zodbpickle==1.0.4
zope.annotation==4.7.0
zope.browser==2.3
zope.browsermenu==4.4
zope.browserpage==4.3.0
zope.browserpage==4.4.0
zope.browserresource==4.3
zope.cachedescriptors==4.3.1
zope.component==4.5
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -91,7 +91,7 @@ def _read_file(filename):
'z3c.pt',
'zope.browser',
'zope.browsermenu',
'zope.browserpage >= 4.0',
'zope.browserpage >= 4.4.0.dev0',
'zope.browserresource >= 3.11',
'zope.component',
'zope.configuration',
Expand Down
11 changes: 3 additions & 8 deletions src/Products/Five/browser/metaconfigure.py
Expand Up @@ -128,14 +128,7 @@ def page(_context, name, permission, for_=Interface,
# class and template
new_class = SimpleViewClass(template, bases=(class_, ), name=name)
else:
if not hasattr(class_, 'browserDefault'):
cdict = {
'browserDefault':
lambda self, request: (getattr(self, attribute), ())
}
else:
cdict = {}

cdict = {}
cdict['__name__'] = name
cdict['__page_attribute__'] = attribute
cdict.update(getSecurityInfo(class_))
Expand Down Expand Up @@ -171,6 +164,8 @@ def page(_context, name, permission, for_=Interface,
required)

_handle_for(_context, for_)
expected = [attribute, 'browserDefault', '__call__', 'publishTraverse']
new_class._simple__whitelist = set(required) - set(expected)

_configure_z2security(_context, new_class, required)

Expand Down
18 changes: 18 additions & 0 deletions src/Products/Five/browser/tests/pages.py
Expand Up @@ -14,6 +14,7 @@
"""Test browser pages
"""

import zope.interface
from AccessControl.class_init import InitializeClass
from AccessControl.SecurityInfo import ClassSecurityInfo
from OFS.SimpleItem import SimpleItem
Expand Down Expand Up @@ -121,3 +122,20 @@ def private_method(self):


InitializeClass(ProtectedView)


class IHamburger(zope.interface.Interface):

def meat():
pass


class CheeseburgerView(BrowserView):
"""View those `meat` method gets allowed via `IHamburger`."""

def meat(self):
"""Make meat publically available via a docstring."""
return 'yummi'

def cheese(self):
return 'tasty'
15 changes: 13 additions & 2 deletions src/Products/Five/browser/tests/pages.zcml
Expand Up @@ -232,15 +232,15 @@
class=".pages.SimpleView"
permission="zope2.Public"
/>

<!-- A named view with permissions -->
<browser:view
name="permission_view"
for="Products.Five.tests.testing.simplecontent.ISimpleContent"
class=".pages.PermissionView"
permission="zope2.ViewManagementScreens"
/>

<!-- stuff that we'll override in overrides.zcml -->
<browser:page
for="Products.Five.tests.testing.simplecontent.ISimpleContent"
Expand Down Expand Up @@ -274,4 +274,15 @@
permission="zope2.ViewManagementScreens"
/>

<!-- view with allowed_interface declaration -->

<browser:page
for="Products.Five.tests.testing.simplecontent.ISimpleContent"
class=".pages.CheeseburgerView"
name="cheeseburger"
permission="zope2.View"
allowed_interface=".pages.IHamburger"
/>


</configure>
90 changes: 90 additions & 0 deletions src/Products/Five/browser/tests/test_pages.py
Expand Up @@ -15,6 +15,14 @@
"""
import unittest

import Products.Five.browser.tests
import Testing.ZopeTestCase
import zope.component.testing
from Products.Five.tests.testing.simplecontent import manage_addSimpleContent
from Testing.testbrowser import Browser
from Zope2.App import zcml
from zope.testbrowser.browser import HTTPError


def test_view_with_unwrapped_context():
"""
Expand Down Expand Up @@ -66,12 +74,94 @@ def test_view_with_unwrapped_context():
"""


class TestPublishTraverse(Testing.ZopeTestCase.FunctionalTestCase):

def setUp(self):
super(TestPublishTraverse, self).setUp()
zcml.load_config("configure.zcml", Products.Five)
zcml.load_config('pages.zcml', package=Products.Five.browser.tests)
uf = self.app.acl_users
uf.userFolderAddUser('manager', 'manager_pass', ['Manager'], [])
manage_addSimpleContent(self.folder, 'testoid', 'x')
self.browser = Browser()
self.browser.login('manager', 'manager_pass')

def tearDown(self):
zope.component.testing.tearDown()
super(TestPublishTraverse, self).tearDown()

def test_publishTraverse_to_allowed_name(self):
# The ``eagle.method`` view has a method ``eagle`` that is registered
# with ``allowed_attributes`` in pages.zcml. This attribute should be
# reachable through ``publishTraverse`` on the view.

folder = self.folder
view = folder.unrestrictedTraverse('testoid/eagle.method')

# Publishing traversal with the default adapter should work:

from ZPublisher.BaseRequest import DefaultPublishTraverse
request = folder.REQUEST
adapter = DefaultPublishTraverse(view, request)
result = adapter.publishTraverse(request, 'eagle')()
self.assertIn('The eagle has landed', result)

# Publishing via browser works, too:

self.browser.open(
'http://localhost/test_folder_1_/testoid/eagle.method/eagle')
self.assertEqual('The eagle has landed', self.browser.contents)

def test_publishTraverse_to_not_allowed_name(self):
# The ``eagle.method`` view has a method ``mouse`` but it is not
# registered with ``allowed_attributes`` in pages.zcml. This attribute
# should be not be accessible. It leads to a HTTP-404, so we do not
# tell the world about our internal methods:
with self.assertRaises(HTTPError) as err:
self.browser.open(
'http://localhost/test_folder_1_/testoid/eagle.method/mouse')
self.assertEqual('HTTP Error 404: Not Found', str(err.exception))

def test_publishTraverse_to_allowed_interface(self):
# The ``cheeseburger`` view has a method ``meat`` that is
# registered via ``allowed_interface`` in pages.zcml. This attribute
# should be reachable through ``publishTraverse`` on the view.

folder = self.folder
view = folder.unrestrictedTraverse('testoid/cheeseburger')

# Publishing traversal with the default adapter should work:

from ZPublisher.BaseRequest import DefaultPublishTraverse
request = folder.REQUEST
adapter = DefaultPublishTraverse(view, request)
result = adapter.publishTraverse(request, 'meat')()
self.assertIn('yummi', result)

# Publishing via browser works, too:

self.browser.open(
'http://localhost/test_folder_1_/testoid/cheeseburger/meat')
self.assertEqual('yummi', self.browser.contents)

def test_publishTraverse_to_not_allowed_interface(self):
# The ``cheeseburger`` view has a method ``cheese`` but it is not
# registered via ``allowed_interface`` in pages.zcml. This attribute
# should be not be accessible. It leads to a HTTP-404, so we do not
# tell the world about our internal methods:
with self.assertRaises(HTTPError) as err:
self.browser.open(
'http://localhost/test_folder_1_/testoid/cheeseburger/cheese')
self.assertEqual('HTTP Error 404: Not Found', str(err.exception))


def test_suite():
from Testing.ZopeTestCase import FunctionalDocFileSuite
from Testing.ZopeTestCase import ZopeDocFileSuite
from Testing.ZopeTestCase import ZopeDocTestSuite
return unittest.TestSuite((
ZopeDocTestSuite(),
unittest.makeSuite(TestPublishTraverse),
ZopeDocFileSuite('pages.txt', package='Products.Five.browser.tests'),
FunctionalDocFileSuite('pages_ftest.txt',
package='Products.Five.browser.tests'),
Expand Down
2 changes: 1 addition & 1 deletion versions-prod.cfg
Expand Up @@ -50,7 +50,7 @@ zodbpickle = 1.0.4
zope.annotation = 4.7.0
zope.browser = 2.3
zope.browsermenu = 4.4
zope.browserpage = 4.3.0
zope.browserpage = 4.4.0
zope.browserresource = 4.3
zope.cachedescriptors = 4.3.1
zope.component = 4.5
Expand Down

0 comments on commit d6e4974

Please sign in to comment.