summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Bangert <ben@groovie.org>2010-10-27 12:32:49 -0700
committerBen Bangert <ben@groovie.org>2010-10-27 12:32:49 -0700
commita19db34e7ebd99e75259aa14829b5bddf5148572 (patch)
tree8ea2bf94a12b33fe502eace734dc9f6ff2141014
parent49905a3fbd55cee02783d1aa33a7e5e6893ac876 (diff)
parent1ad1dbb5987c74d8e6802221c78af96e24ca1960 (diff)
downloadpyramid-a19db34e7ebd99e75259aa14829b5bddf5148572.tar.gz
pyramid-a19db34e7ebd99e75259aa14829b5bddf5148572.tar.bz2
pyramid-a19db34e7ebd99e75259aa14829b5bddf5148572.zip
Merge branch 'master' of github.com:Pylons/pyramid
-rw-r--r--docs/narr/security.rst15
-rw-r--r--pyramid/configuration.py24
-rw-r--r--pyramid/interfaces.py1
-rw-r--r--pyramid/tests/defpermbugapp/__init__.py14
-rw-r--r--pyramid/tests/defpermbugapp/configure.zcml14
-rw-r--r--pyramid/tests/test_configuration.py22
-rw-r--r--pyramid/tests/test_integration.py16
7 files changed, 91 insertions, 15 deletions
diff --git a/docs/narr/security.rst b/docs/narr/security.rst
index 25d1c2ecf..109009842 100644
--- a/docs/narr/security.rst
+++ b/docs/narr/security.rst
@@ -239,13 +239,16 @@ application:
- The :ref:`default_permission_directive` ZCML directive.
-When a default permission is registered, if a view configuration
-*does* name its own permission, the default permission is ignored for
-that view registration, and the view-configuration-named permission is
-used.
+When a default permission is registered:
-.. note:: All APIs and ZCML directives related to default permissions
- are new in :mod:`pyramid` 1.3.
+- if a view configuration names an explicit ``permission`, the default
+ permission is ignored for that view registration, and the
+ view-configuration-named permission is used.
+
+- if a view configuration names an explicit permission as the string
+ ``__no_permission_required__``, the default permission is ignored,
+ and the view is registered *without* a permission (making it
+ available to all callers regardless of their credentials).
.. index::
single: ACL
diff --git a/pyramid/configuration.py b/pyramid/configuration.py
index bf06143bd..21dce8af1 100644
--- a/pyramid/configuration.py
+++ b/pyramid/configuration.py
@@ -89,8 +89,6 @@ DEFAULT_RENDERERS = (
('string', renderers.string_renderer_factory),
)
-_marker = object()
-
class Configurator(object):
"""
A Configurator is used to configure a :mod:`pyramid`
@@ -746,7 +744,7 @@ class Configurator(object):
return route
- def add_view(self, view=None, name="", for_=None, permission=_marker,
+ def add_view(self, view=None, name="", for_=None, permission=None,
request_type=None, route_name=None, request_method=None,
request_param=None, containment=None, attr=None,
renderer=None, wrapper=None, xhr=False, accept=None,
@@ -783,11 +781,12 @@ class Configurator(object):
:class:`pyramid.configuration.Configurator` constructor's
``default_permission`` argument, or if
:meth:`pyramid.configuration.Configurator.set_default_permission`
- was used prior to this view registration. Pass ``None`` as
- the permission to explicitly indicate that the view should
- always be executable by entirely anonymous users, regardless
- of the default permission, bypassing any
- :term:`authorization policy` that may be in effect.
+ was used prior to this view registration. Pass the string
+ ``__no_permission_required__`` as the permission argument to
+ explicitly indicate that the view should always be
+ executable by entirely anonymous users, regardless of the
+ default permission, bypassing any :term:`authorization
+ policy` that may be in effect.
attr
@@ -1051,10 +1050,11 @@ class Configurator(object):
containment=containment, request_type=request_type,
custom=custom_predicates)
- if permission is _marker:
+ if permission is None:
# intent: will be None if no default permission is registered
permission = self.registry.queryUtility(IDefaultPermission)
+ # NO_PERMISSION_REQUIRED handled by _secure_view
derived_view = self._derive_view(view, permission, predicates, attr,
renderer, wrapper, name, accept, order,
phash)
@@ -2514,6 +2514,12 @@ def _predicate_wrap(view, predicates):
return predicate_wrapper
def _secure_view(view, permission, authn_policy, authz_policy):
+ if permission == '__no_permission_required__':
+ # allow views registered within configurations that have a
+ # default permission to explicitly override the default
+ # permission, replacing it with no permission at all
+ permission = None
+
wrapped_view = view
if authn_policy and authz_policy and (permission is not None):
def _secured_view(context, request):
diff --git a/pyramid/interfaces.py b/pyramid/interfaces.py
index afb0376cd..9b7488f1e 100644
--- a/pyramid/interfaces.py
+++ b/pyramid/interfaces.py
@@ -376,3 +376,4 @@ class IDefaultPermission(Interface):
for all view configurations which do not explicitly declare their
own."""
+NO_PERMISSION_REQUIRED = '__no_permission_required__'
diff --git a/pyramid/tests/defpermbugapp/__init__.py b/pyramid/tests/defpermbugapp/__init__.py
new file mode 100644
index 000000000..3b1a00083
--- /dev/null
+++ b/pyramid/tests/defpermbugapp/__init__.py
@@ -0,0 +1,14 @@
+from webob import Response
+from pyramid.view import bfg_view
+
+@bfg_view(name='x')
+def x_view(request):
+ return Response('this is private!')
+
+@bfg_view(name='y', permission='private2')
+def y_view(request):
+ return Response('this is private too!')
+
+@bfg_view(name='z', permission='__no_permission_required__')
+def z_view(request):
+ return Response('this is public')
diff --git a/pyramid/tests/defpermbugapp/configure.zcml b/pyramid/tests/defpermbugapp/configure.zcml
new file mode 100644
index 000000000..f9680bb04
--- /dev/null
+++ b/pyramid/tests/defpermbugapp/configure.zcml
@@ -0,0 +1,14 @@
+<configure xmlns="http://pylonshq.com/pyramid">
+
+ <include package="pyramid.includes" />
+
+ <scan package="pyramid.tests.defpermbugapp"/>
+
+ <authtktauthenticationpolicy
+ secret="seekt1t"/>
+
+ <aclauthorizationpolicy/>
+
+ <default_permission name="private" />
+
+</configure>
diff --git a/pyramid/tests/test_configuration.py b/pyramid/tests/test_configuration.py
index de2de621f..fa2318fcc 100644
--- a/pyramid/tests/test_configuration.py
+++ b/pyramid/tests/test_configuration.py
@@ -2775,6 +2775,28 @@ class ConfiguratorTests(unittest.TestCase):
permitted = result.__permitted__(None, None)
self.assertEqual(permitted, False)
+ def test__derive_view_debug_auth_permission_authpol_overridden(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self._registerSettings(config,
+ debug_authorization=True, reload_templates=True)
+ logger = self._registerLogger(config)
+ self._registerSecurityPolicy(config, False)
+ result = config._derive_view(view,
+ permission='__no_permission_required__')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest(config)
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): False")
+
def test__derive_view_with_predicates_all(self):
view = lambda *arg: 'OK'
predicates = []
diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py
index 1c6752808..fffd8c03e 100644
--- a/pyramid/tests/test_integration.py
+++ b/pyramid/tests/test_integration.py
@@ -198,6 +198,22 @@ class TestViewPermissionBug(TwillBase):
browser.go('http://localhost:6543/x')
self.assertEqual(browser.get_code(), 401)
+class TestDefaultViewPermissionBug(TwillBase):
+ # default_view_permission bug as reported by Wiggy at http://lists.repoze.org/pipermail/repoze-dev/2010-October/003602.html
+ config = 'pyramid.tests.defpermbugapp:configure.zcml'
+ def test_it(self):
+ import twill.commands
+ browser = twill.commands.get_browser()
+ browser.go('http://localhost:6543/x')
+ self.assertEqual(browser.get_code(), 401)
+ self.failUnless('failed permission check' in browser.get_html())
+ browser.go('http://localhost:6543/y')
+ self.assertEqual(browser.get_code(), 401)
+ self.failUnless('failed permission check' in browser.get_html())
+ browser.go('http://localhost:6543/z')
+ self.assertEqual(browser.get_code(), 200)
+ self.failUnless('public' in browser.get_html())
+
from pyramid.tests.exceptionviewapp.models import AnException, NotAnException
excroot = {'anexception':AnException(),
'notanexception':NotAnException()}