diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-05-26 00:44:17 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-05-26 00:44:17 +0000 |
| commit | 08ead74d05e25f58c83712f6f8651484ddc983d0 (patch) | |
| tree | 8a14ba839615678ab1eb4510782595af2d51f4d5 | |
| parent | 9b1876725d2268af42961e36dbccfdc990fa4dd1 (diff) | |
| download | pyramid-08ead74d05e25f58c83712f6f8651484ddc983d0.tar.gz pyramid-08ead74d05e25f58c83712f6f8651484ddc983d0.tar.bz2 pyramid-08ead74d05e25f58c83712f6f8651484ddc983d0.zip | |
Revert all work towards creating a "forbidden" API on the security policy; I'll do this work on the authchanges branch first.
| -rw-r--r-- | CHANGES.txt | 63 | ||||
| -rw-r--r-- | docs/narr/hooks.rst | 72 | ||||
| -rw-r--r-- | repoze/bfg/interfaces.py | 46 | ||||
| -rw-r--r-- | repoze/bfg/router.py | 78 | ||||
| -rw-r--r-- | repoze/bfg/security.py | 40 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_router.py | 213 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_security.py | 19 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_wsgi.py | 4 | ||||
| -rw-r--r-- | repoze/bfg/wsgi.py | 2 |
9 files changed, 158 insertions, 379 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 6df0c8171..40a810305 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,66 +1,3 @@ -Next release -============ - -Features --------- - -- It is now possible to register a custom - ``repoze.bfg.interfaces.IForbiddenResponseFactory`` for a given - application. This feature replaces the - ``repoze.bfg.interfaces.IUnauthorizedAppFactory`` feature previously - described in the Hooks chapter. The IForbiddenResponseFactory will - be called when the framework detects an authorization failure; it - should accept a context object and a request object; it should - return an IResponse object (a webob response, basically). Read the - below point for more info and see the Hooks narrative chapter of the - BFG docs for more info; this registration trumps the security policy - ``forbidden`` feature when it is registered. - -- It is now possible to register a security policy that returns a - customized ``Forbidden`` response when BFG cannot authorize an - invocation of a view. To this end, ISecurityPolicy objects must now - have a ``forbidden`` method that accepts two arguments: ``context`` - and ``request``. The ``context`` will be the context found by the - router, the ``request`` will be the current request. This method - should return an IResponse (a webob response). The returned - response application should be appropriate when access to a view - resource was forbidden by the security policy (e.g. perhaps a login - page or a general "forbidden" page). ``repoze.bfg`` is willing to - operate with a custom security policy that does not have a - ``forbidden`` method, but it will issue a warning; eventually - security policies without a ``forbidden`` method will cease to work - under ``repoze.bfg``. - - Note that the ``forbidden`` method of a security policy is not used - if a developer has registered an IForbiddenResponseFactory (see the - "Hooks" narrative chapter); the explicitly registered - IForbiddenResponseFactory will be preferred over the (more general) - security policy forbidden method. - -- All default security policies now have a ``forbidden`` callable - attached to them. This particular callable returns an IResponse (a - webob response) with a ``401 Unauthorized`` status for backwards - compatibility (had backwards compatibility not been an issue, this - callable would have returned a WSGI app that generated a ``403 - Forbidden`` response). - -Backwards Incompatibilities ---------------------------- - -- Custom NotFound and Forbidden (nee' Unauthorized) WSGI applications - (registered as a utility for INotFoundAppFactory and - IUnauthorizedAppFactory) could rely on an environment key named - ``message`` describing the circumstance of the response. This key - has been renamed to ``repoze.bfg.message`` (as per the WSGI spec, - which requires environment extensions to contain dots). - -Deprecations ------------- - -- The ``repoze.bfg.interfaces.IUnauthorizedAppFactory`` interface has - been deprecated in favor of using the new - ``repoze.bfg.interfaces.IForbiddenResponseFactory`` mechanism. - 0.8.1 (2009-05-21) ================== diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 6428408e8..21906e466 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -88,7 +88,7 @@ an object that implements any particular interface; it simply needs have a ``status`` attribute, a ``headerlist`` attribute, and and ``app_iter`` attribute. -Changing the NotFound Application +Changing the NotFound application --------------------------------- When :mod:`repoze.bfg` can't map a URL to code, it creates and invokes @@ -119,56 +119,54 @@ sample code that implements a minimal NotFound application factory: .. note:: When a NotFound application factory is invoked, it is passed the WSGI environ and the WSGI ``start_response`` handler by :mod:`repoze.bfg`. Within the WSGI environ will be a key named - ``repoze.bfg.message`` that has a value explaining why the not - found error was raised. This error will be different when the - ``debug_notfound`` environment setting is true than it is when it - is false. + ``message`` that has a value explaining why the not found error was + raised. This error will be different when the ``debug_notfound`` + environment setting is true than it is when it is false. -Changing the Forbidden Response -------------------------------- +Changing the Unauthorized application +------------------------------------- When :mod:`repoze.bfg` can't authorize execution of a view based on -the security policy in use, it invokes a "forbidden response factory". -Usually this forbidden response factory is serviced by the currently -active :term:`security policy`, but it can be overridden as necessary -by placing something like the following ZCML in your -``configure.zcml`` file. +the security policy in use, it creates and invokes an Unauthorized +WSGI application. The application it invokes can be customized by +placing something like the following ZCML in your ``configure.zcml`` +file. .. code-block:: xml :linenos: - <utility provides="repoze.bfg.interfaces.IForbiddenResponseFactory" - component="helloworld.factories.forbidden_response_factory"/> + <utility provides="repoze.bfg.interfaces.IUnauthorizedAppFactory" + component="helloworld.factories.unauthorized_app_factory"/> -Replace ``helloworld.factories.forbidden_app_factory`` with the Python -dotted name to the forbidden response factory you want to use. The -response factory must accept two parameters: ``context`` and -``request``. The ``context`` is the context found by the router when -the view invocation was denied. The ``request`` is the current -:term:`request` representing the denied action. Here's some sample -code that implements a minimal forbidden response factory: +Replace ``helloworld.factories.unauthorized_app_factory`` with the +Python dotted name to the request factory you want to use. Here's +some sample code that implements a minimal Unauthorized application +factory: .. code-block:: python - from repoze.bfg.chameleon_zpt import render_template_to_response + from webob.exc import HTTPUnauthorized - def forbidden_response_factory(context, request): - return render_template_to_response('templates/login_form.pt') + class MyUnauthorized(HTTPUnauthorized): + pass -.. note:: When an forbidden response factory is invoked, it is passed - the request as the second argument. An attribute of the request is - ``environ``, which is the WSGI environment. Within the WSGI - environ will be a key named ``repoze.bfg.message`` that has a value - explaining why the current view invocation was forbidden. This - error will be different when the ``debug_authorization`` - environment setting is true than it is when it is false. + def notfound_app_factory(): + return MyUnauthorized -.. warning:: the default forbidden application factory sends a - response with a ``401 Unauthorized`` status code for backwards - compatibility reasons. You can influence the status code of - Forbidden responses by using an alterate forbidden application - factory. For example, it would make sense to return an forbidden - application with a ``403 Forbidden`` status code. +.. note:: When an Unauthorized application factory is invoked, it is + passed the WSGI environ and the WSGI ``start_response`` handler by + :mod:`repoze.bfg`. Within the WSGI environ will be a key named + ``message`` that has a value explaining why the action was not + authorized. This error will be different when the + ``debug_authorization`` environment setting is true than it is when + it is false. + +.. note:: You can influence the status code of Unauthorized responses + by using an alterate unauthorized application factory. For + example, you may return an unauthorized application with a ``403 + Forbidden`` status code, rather than use the default unauthorized + application factory, which sends a response with a ``401 + Unauthorized`` status code. Changing the Default Routes Context Factory ------------------------------------------- diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py index 78311962f..cecc3a397 100644 --- a/repoze/bfg/interfaces.py +++ b/repoze/bfg/interfaces.py @@ -131,27 +131,6 @@ class ISecurityPolicy(Interface): implementation, in which case, it should raise a ``NotImplementedError`` exception.""" - def forbidden(context, request): - """ This method should return an IResponse object (an object - with the attributes ``status``, ``headerlist``, and - ``app_iter``) as a result of a view invocation denial. The - ``forbidden`` method of a security policy will be called by - ``repoze.bfg`` when view invocation is denied (usually as a - result of the ``permit`` method of the same security policy - returning False to the Router). - - The ``forbidden`` method of a security will not be called when - an ``IForbiddenResponseFactory`` utility is registered; - instead the ``IForbiddenResponseFactory`` utility will serve - the forbidden response. - - Note that the ``repoze.bfg.message`` key in the environ passed - to the WSGI app will contain the 'raw' reason that view - invocation was denied by repoze.bfg. The ``context`` object - passed in will be the context found by ``repoze.bfg`` when the - denial was found and the ``request`` will be the request which - caused the denial.""" - class IViewPermission(Interface): def __call__(security_policy): """ Return True if the permission allows, return False if it denies. """ @@ -218,26 +197,15 @@ class INotFoundAppFactory(Interface): a``message`` key in the WSGI environ provides information pertaining to the reason for the notfound.""" -class IForbiddenResponseFactory(Interface): - """ A utility which returns an IResponse as the result of the - denial of a view invocation by a security policy.""" - def __call__(context, request): - """ Return an object implementing IResponse (an object with - the status, headerlist, and app_iter attributes) as a result - of a view invocation denial by a security policy. - - Note that the ``message`` key in the WSGI environ - (request.environ) provides information pertaining to the - reason for the view invocation denial. The ``context`` passed - to the forbidden app factory will be the context found by the - repoze.bfg router during traversal or url dispatch. The - ``request`` will be the request object which caused the deny.""" - class IUnauthorizedAppFactory(Interface): """ A utility which returns an Unauthorized WSGI application - factory (deprecated in repoze.bfg 0.8.2) in favor of - IForbiddenResponseFactory """ - + factory""" + def __call__(): + """ Return a callable which returns an unauthorized WSGI + application. When the WSGI application is invoked, a + ``message`` key in the WSGI environ provides information + pertaining to the reason for the unauthorized.""" + class IContextURL(Interface): """ An adapter which deals with URLs related to a context. """ diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py index ac3bd53cd..81bc6e4ef 100644 --- a/repoze/bfg/router.py +++ b/repoze/bfg/router.py @@ -17,7 +17,6 @@ from repoze.bfg.interfaces import IRouter from repoze.bfg.interfaces import IRoutesMapper from repoze.bfg.interfaces import ISecurityPolicy from repoze.bfg.interfaces import ISettings -from repoze.bfg.interfaces import IForbiddenResponseFactory from repoze.bfg.interfaces import IUnauthorizedAppFactory from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IViewPermission @@ -31,15 +30,13 @@ from repoze.bfg.registry import populateRegistry from repoze.bfg.request import HTTP_METHOD_FACTORIES from repoze.bfg.request import Request -from repoze.bfg.security import _forbidden - from repoze.bfg.settings import Settings from repoze.bfg.urldispatch import RoutesRootFactory from repoze.bfg.traversal import _traverse from repoze.bfg.view import _view_execution_permitted - +from repoze.bfg.wsgi import Unauthorized from repoze.bfg.wsgi import NotFound _marker = object() @@ -53,65 +50,22 @@ class Router(object): def __init__(self, registry): self.registry = registry - self.logger = registry.queryUtility(ILogger, 'repoze.bfg.debug') self.request_factory = registry.queryUtility(IRequestFactory) - security_policy = registry.queryUtility(ISecurityPolicy) - self.security_policy = security_policy - - unauthorized_app_factory = registry.queryUtility( - IUnauthorizedAppFactory) - - forbidden = None - - if unauthorized_app_factory is not None: - warning = ( - 'Instead of registering a utility against the ' - 'repoze.bfg.interfaces.IUnauthorizedAppFactory interface ' - 'to return a custom forbidden response, you should now ' - 'register a "repoze.interfaces.IForbiddenResponseFactory". ' - 'The IUnauthorizedAppFactory interface was deprecated in ' - 'repoze.bfg 0.8.2 and will be removed in a subsequent version ' - 'of repoze.bfg. See the "Hooks" chapter of the repoze.bfg ' - 'documentation for more information about ' - 'IForbiddenResponseFactory.') - self.logger and self.logger.warn(warning) - def forbidden(context, request): - app = unauthorized_app_factory() - response = request.get_response(app) - return response - - self.forbidden_resp_factory = registry.queryUtility( - IForbiddenResponseFactory, - default=forbidden) - - if security_policy is not None: - if hasattr(security_policy, 'forbidden'): - security_policy_forbidden = security_policy.forbidden - else: - security_policy_forbidden = _forbidden - warning = ('You are running with a security policy (%s) which ' - 'does not have a "forbidden" method; in BFG 0.8.2+ ' - 'the ISecurityPolicy interface in the ' - 'repoze.bfg.interfaces module defines this method ' - 'as required; your application will not work under ' - 'a future release of BFG if you continue using a ' - 'security policy without a "forbidden" method.' % - security_policy) - self.logger and self.logger.warn(warning) - # allow a specifically-registered IForbiddenResponseFactory to - # override the security policy's forbidden - self.forbidden_resp_factory = (self.forbidden_resp_factory or - security_policy_forbidden) - - self.notfound_app_factory = registry.queryUtility(INotFoundAppFactory, - default=NotFound) - + self.security_policy = registry.queryUtility(ISecurityPolicy) + self.notfound_app_factory = registry.queryUtility( + INotFoundAppFactory, + default=NotFound) + self.unauth_app_factory = registry.queryUtility( + IUnauthorizedAppFactory, + default=Unauthorized) + settings = registry.queryUtility(ISettings) if settings is not None: self.debug_authorization = settings.debug_authorization self.debug_notfound = settings.debug_notfound + self.logger = registry.queryUtility(ILogger, 'repoze.bfg.debug') self.root_factory = registry.getUtility(IRootFactory) self.root_policy = self.root_factory # b/w compat self.traverser_warned = {} @@ -190,18 +144,14 @@ class Router(object): 'context %r): %s' % ( request.url, view_name, context, permitted) ) - if not permitted: if debug_authorization: msg = str(permitted) else: msg = 'Unauthorized: failed security policy check' - - environ['repoze.bfg.message'] = msg - - response = self.forbidden_resp_factory(context, request) - start_response(response.status, response.headerlist) - return response.app_iter + environ['message'] = msg + unauth_app = self.unauth_app_factory() + return unauth_app(environ, start_response) response = registry.queryMultiAdapter( (context, request), IView, name=view_name) @@ -218,7 +168,7 @@ class Router(object): logger and logger.debug(msg) else: msg = request.url - environ['repoze.bfg.message'] = msg + environ['message'] = msg notfound_app = self.notfound_app_factory() return notfound_app(environ, start_response) diff --git a/repoze/bfg/security.py b/repoze/bfg/security.py index 14423ffdc..90916bac2 100644 --- a/repoze/bfg/security.py +++ b/repoze/bfg/security.py @@ -1,6 +1,3 @@ -from cgi import escape -from webob import Response - from zope.component import queryUtility from zope.deprecation import deprecated from zope.interface import implements @@ -10,7 +7,6 @@ from repoze.bfg.location import lineage from repoze.bfg.interfaces import ISecurityPolicy from repoze.bfg.interfaces import IViewPermission from repoze.bfg.interfaces import IViewPermissionFactory -from repoze.bfg.interfaces import IResponseFactory Everyone = 'system.Everyone' Authenticated = 'system.Authenticated' @@ -78,31 +74,9 @@ def principals_allowed_by_permission(context, permission): return [Everyone] return policy.principals_allowed_by_permission(context, permission) -def _forbidden(context, request): - status = '401 Unauthorized' - try: - msg = escape(request.environ['repoze.bfg.message']) - except KeyError: - msg = '' - html = """ - <html> - <title>%s</title> - <body> - <h1>%s</h1> - <code>%s</code> - </body> - </html> - """ % (status, status, msg) - headers = [('Content-Length', str(len(html))), - ('Content-Type', 'text/html')] - response_factory = queryUtility(IResponseFactory, default=Response) - return response_factory(status = status, - headerlist = headers, - app_iter = [html]) - class ACLSecurityPolicy(object): implements(ISecurityPolicy) - + def __init__(self, get_principals): self.get_principals = get_principals @@ -171,9 +145,6 @@ class ACLSecurityPolicy(object): return [] - def forbidden(self, context, request): - return _forbidden(context, request) - class InheritingACLSecurityPolicy(object): """ A security policy which uses ACLs in the following ways: @@ -218,7 +189,7 @@ class InheritingACLSecurityPolicy(object): ``authenticated_userid``). """ implements(ISecurityPolicy) - + def __init__(self, get_principals): self.get_principals = get_principals @@ -297,9 +268,6 @@ class InheritingACLSecurityPolicy(object): return allowed - def forbidden(self, context, request): - return _forbidden(context, request) - def get_remoteuser(request): user_id = request.environ.get('REMOTE_USER') if user_id: @@ -515,7 +483,6 @@ def WhoInheritingACLSecurityPolicy(): """ return InheritingACLSecurityPolicy(get_who_principals) - class PermitsResult(int): def __new__(cls, s, *args): inst = int.__new__(cls, cls.boolval) @@ -628,3 +595,6 @@ class ViewPermissionFactory(object): class Unauthorized(Exception): pass + + + diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py index 29ebf61d5..db47f832e 100644 --- a/repoze/bfg/tests/test_router.py +++ b/repoze/bfg/tests/test_router.py @@ -78,12 +78,9 @@ class RouterTests(unittest.TestCase): from repoze.bfg.interfaces import IViewPermission self.registry.registerAdapter(permission, for_, IViewPermission, name) - def _registerSecurityPolicy(self, secpol=None): - if secpol is None: - secpol = DummySecurityPolicy() + def _registerSecurityPolicy(self, secpol): from repoze.bfg.interfaces import ISecurityPolicy self.registry.registerUtility(secpol, ISecurityPolicy) - return secpol def _registerEventListener(self, iface): L = [] @@ -92,11 +89,9 @@ class RouterTests(unittest.TestCase): self.registry.registerHandler(listener, (iface,)) return L - def _registerRootFactory(self, val): - rootfactory = make_rootfactory(val) + def _registerRootFactory(self, root_factory): from repoze.bfg.interfaces import IRootFactory - self.registry.registerUtility(rootfactory, IRootFactory) - return rootfactory + self.registry.registerUtility(root_factory, IRootFactory) def _getTargetClass(self): from repoze.bfg.router import Router @@ -118,93 +113,21 @@ class RouterTests(unittest.TestCase): return environ def test_root_policy(self): + rootfactory = make_rootfactory(None) environ = self._makeEnviron() context = DummyContext() self._registerTraverserFactory(context) - rootfactory = self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() self.assertEqual(router.root_policy, rootfactory) - def test_secpol_no_forbidden(self): - environ = self._makeEnviron() - context = DummyContext() - self._registerTraverserFactory(context) - rootfactory = self._registerRootFactory(None) - logger = self._registerLogger() - class Dummy: - pass - self._registerSecurityPolicy(Dummy()) - router = self._makeOne() - self.assertEqual(len(logger.messages), 1) - self.failUnless('which does not have a "forbidden" method' - in logger.messages[0]) - class DummyRequest: - environ = {} - req = DummyRequest() - resp = router.forbidden_resp_factory(None, req) - self.assertEqual(resp.status, '401 Unauthorized') - - def test_secpol_with_iunauthorized_appfactory(self): - from repoze.bfg.interfaces import IUnauthorizedAppFactory - environ = self._makeEnviron() - context = DummyContext() - self._registerTraverserFactory(context) - rootfactory = self._registerRootFactory(None) - logger = self._registerLogger() - secpol = self._registerSecurityPolicy() - def factory(): - return 'yo' - self.registry.registerUtility(factory, IUnauthorizedAppFactory) - router = self._makeOne() - self.assertEqual(len(logger.messages), 1) - self.failUnless('IForbiddenResponseFactory' in logger.messages[0]) - class DummyRequest: - def get_response(self, app): - return app - req = DummyRequest() - self.assertEqual(router.forbidden_resp_factory(None, req), 'yo') - - def test_inotfound_appfactory_override(self): - from repoze.bfg.interfaces import INotFoundAppFactory - def app(): - """ """ - self.registry.registerUtility(app, INotFoundAppFactory) - self._registerRootFactory(None) - router = self._makeOne() - self.assertEqual(router.notfound_app_factory, app) - - def test_iforbidden_respfactory_override_withsecpol(self): - from repoze.bfg.interfaces import IForbiddenResponseFactory - def app(): - """ """ - self.registry.registerUtility(app, IForbiddenResponseFactory) - self._registerSecurityPolicy() - self._registerRootFactory(None) - router = self._makeOne() - self.assertEqual(router.forbidden_resp_factory, app) - - def test_iforbidden_responsefactory_override_nosecpol(self): - from repoze.bfg.interfaces import IForbiddenResponseFactory - def app(): - """ """ - self.registry.registerUtility(app, IForbiddenResponseFactory) - self._registerRootFactory(None) - router = self._makeOne() - self.assertEqual(router.forbidden_resp_factory, app) - - def test_iforbidden_responsefactory_nooverride(self): - secpol = self._registerSecurityPolicy() - context = DummyContext() - self._registerRootFactory(None) - router = self._makeOne() - self.assertEqual(router.forbidden_resp_factory, secpol.forbidden) - def test_call_no_view_registered_no_isettings(self): + rootfactory = make_rootfactory(None) environ = self._makeEnviron() context = DummyContext() self._registerTraverserFactory(context) logger = self._registerLogger() - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -225,7 +148,8 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context) environ = self._makeEnviron() start_response = DummyStartResponse() - self._registerRootFactory(NotFound()) + rootfactory = make_rootfactory(NotFound()) + self._registerRootFactory(rootfactory) router = self._makeOne() result = router(environ, start_response) status = start_response.status @@ -233,12 +157,13 @@ class RouterTests(unittest.TestCase): self.failUnless('http://localhost:8080' in result[0], result) def test_call_no_view_registered_debug_notfound_false(self): + rootfactory = make_rootfactory(None) environ = self._makeEnviron() context = DummyContext() self._registerTraverserFactory(context) logger = self._registerLogger() self._registerSettings(debug_notfound=False) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -251,12 +176,13 @@ class RouterTests(unittest.TestCase): self.assertEqual(len(logger.messages), 0) def test_call_no_view_registered_debug_notfound_true(self): + rootfactory = make_rootfactory(None) environ = self._makeEnviron() context = DummyContext() self._registerTraverserFactory(context) self._registerSettings(debug_notfound=True) logger = self._registerLogger() - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -279,17 +205,19 @@ class RouterTests(unittest.TestCase): self.failUnless("subpath: []" in message) def test_call_view_returns_nonresponse(self): + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context) environ = self._makeEnviron() view = make_view('abc') self._registerView(view, '', None, None) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() self.assertRaises(ValueError, router, environ, start_response) def test_call_view_registered_nonspecific_default_path(self): + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context) response = DummyResponse() @@ -297,7 +225,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron() self._registerView(view, '', None, None) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -310,6 +238,7 @@ class RouterTests(unittest.TestCase): self.assertEqual(environ['webob.adhoc_attrs']['root'], None) def test_call_deprecation_warning(self): + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context, _deprecation_warning='abc') response = DummyResponse() @@ -317,7 +246,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron() self._registerView(view, '', None, None) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() logger = self._registerLogger() router.logger = logger @@ -327,6 +256,7 @@ class RouterTests(unittest.TestCase): self.assertEqual(logger.messages[0], 'abc') def test_call_view_registered_nonspecific_nondefault_path_and_subpath(self): + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context, view_name='foo', subpath=['bar'], @@ -336,7 +266,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron() self._registerView(view, 'foo', None, None) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -349,6 +279,7 @@ class RouterTests(unittest.TestCase): self.assertEqual(environ['webob.adhoc_attrs']['root'], None) def test_call_view_registered_specific_success(self): + rootfactory = make_rootfactory(None) from zope.interface import Interface from zope.interface import directlyProvides class IContext(Interface): @@ -362,7 +293,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -375,6 +306,7 @@ class RouterTests(unittest.TestCase): self.assertEqual(environ['webob.adhoc_attrs']['root'], None) def test_call_view_registered_specific_fail(self): + rootfactory = make_rootfactory(None) from zope.interface import Interface from zope.interface import directlyProvides class IContext(Interface): @@ -389,7 +321,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -397,6 +329,7 @@ class RouterTests(unittest.TestCase): self.failUnless('404' in result[0]) def test_call_view_registered_security_policy_permission_none(self): + rootfactory = make_rootfactory(None) from zope.interface import Interface from zope.interface import directlyProvides class IContext(Interface): @@ -409,14 +342,16 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) - self._registerSecurityPolicy() - self._registerRootFactory(None) + secpol = DummySecurityPolicy() + self._registerSecurityPolicy(secpol) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) self.assertEqual(start_response.status, '200 OK') def test_call_view_registered_security_policy_permission_succeeds(self): + rootfactory = make_rootfactory(None) from zope.interface import Interface from zope.interface import directlyProvides class IContext(Interface): @@ -427,12 +362,13 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() view = make_view(response) + secpol = DummySecurityPolicy() permissionfactory = make_permission_factory(True) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) - secpol = self._registerSecurityPolicy() + self._registerSecurityPolicy(secpol) self._registerPermission(permissionfactory, '', IContext, IRequest) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -440,6 +376,7 @@ class RouterTests(unittest.TestCase): self.assertEqual(permissionfactory.checked_with, secpol) def test_call_view_permission_fails_nosettings(self): + rootfactory = make_rootfactory(None) from zope.interface import Interface from zope.interface import directlyProvides class IContext(Interface): @@ -450,24 +387,26 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() view = make_view(response) + secpol = DummySecurityPolicy() from repoze.bfg.security import ACLDenied permissionfactory = make_permission_factory( ACLDenied('ace', 'acl', 'permission', ['principals'], context) ) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) - secpol = self._registerSecurityPolicy() + self._registerSecurityPolicy(secpol) self._registerPermission(permissionfactory, '', IContext, IRequest) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) self.assertEqual(start_response.status, '401 Unauthorized') - message = environ['repoze.bfg.message'] - self.assertEqual(message, 'Unauthorized: failed security policy check') + message = result[0] + self.failUnless('failed security policy check' in message) self.assertEqual(permissionfactory.checked_with, secpol) def test_call_view_permission_fails_no_debug_auth(self): + rootfactory = make_rootfactory(None) from zope.interface import Interface from zope.interface import directlyProvides class IContext(Interface): @@ -478,25 +417,27 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() view = make_view(response) + secpol = DummySecurityPolicy() from repoze.bfg.security import ACLDenied permissionfactory = make_permission_factory( ACLDenied('ace', 'acl', 'permission', ['principals'], context) ) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) - secpol = self._registerSecurityPolicy() + self._registerSecurityPolicy(secpol) self._registerPermission(permissionfactory, '', IContext, IRequest) self._registerSettings(debug_authorization=False) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) self.assertEqual(start_response.status, '401 Unauthorized') - message = environ['repoze.bfg.message'] + message = result[0] self.failUnless('failed security policy check' in message) self.assertEqual(permissionfactory.checked_with, secpol) def test_call_view_permission_fails_with_debug_auth(self): + rootfactory = make_rootfactory(None) from zope.interface import Interface from zope.interface import directlyProvides class IContext(Interface): @@ -507,22 +448,23 @@ class RouterTests(unittest.TestCase): self._registerTraverserFactory(context, subpath=['']) response = DummyResponse() view = make_view(response) + secpol = DummySecurityPolicy() from repoze.bfg.security import ACLDenied permissionfactory = make_permission_factory( ACLDenied('ace', 'acl', 'permission', ['principals'], context) ) environ = self._makeEnviron() self._registerView(view, '', IContext, IRequest) - secpol = self._registerSecurityPolicy() + self._registerSecurityPolicy(secpol) self._registerPermission(permissionfactory, '', IContext, IRequest) self._registerSettings(debug_authorization=True) logger = self._registerLogger() - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) self.assertEqual(start_response.status, '401 Unauthorized') - message = environ['repoze.bfg.message'] + message = result[0] self.failUnless( "ACLDenied permission 'permission' via ACE 'ace' in ACL 'acl' " "on context" in message) @@ -540,6 +482,7 @@ class RouterTests(unittest.TestCase): "for principals ['principals']" in logged) def test_call_eventsends(self): + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context) response = DummyResponse() @@ -551,7 +494,7 @@ class RouterTests(unittest.TestCase): from repoze.bfg.interfaces import INewResponse request_events = self._registerEventListener(INewRequest) response_events = self._registerEventListener(INewResponse) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() result = router(environ, start_response) @@ -565,6 +508,7 @@ class RouterTests(unittest.TestCase): from repoze.bfg.interfaces import IPOSTRequest from repoze.bfg.interfaces import IPUTRequest from repoze.bfg.interfaces import IRequest + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context) response = DummyResponse() @@ -572,7 +516,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron(REQUEST_METHOD='POST') self._registerView(view, '', None, None) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() request_events = self._registerEventListener(INewRequest) @@ -587,6 +531,7 @@ class RouterTests(unittest.TestCase): from repoze.bfg.interfaces import IPUTRequest from repoze.bfg.interfaces import IPOSTRequest from repoze.bfg.interfaces import IRequest + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context) response = DummyResponse() @@ -594,7 +539,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron(REQUEST_METHOD='PUT') self._registerView(view, '', None, None) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() request_events = self._registerEventListener(INewRequest) @@ -607,6 +552,7 @@ class RouterTests(unittest.TestCase): def test_call_unknown_method(self): from repoze.bfg.interfaces import INewRequest from repoze.bfg.interfaces import IRequest + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context) response = DummyResponse() @@ -614,7 +560,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron(REQUEST_METHOD='UNKNOWN') self._registerView(view, '', None, None) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() request_events = self._registerEventListener(INewRequest) @@ -627,6 +573,7 @@ class RouterTests(unittest.TestCase): from repoze.bfg.interfaces import IRequestFactory from repoze.bfg.testing import DummyRequest self.registry.registerUtility(DummyRequest, IRequestFactory) + rootfactory = make_rootfactory(None) context = DummyContext() self._registerTraverserFactory(context) response = DummyResponse() @@ -634,7 +581,7 @@ class RouterTests(unittest.TestCase): view = make_view(response) environ = self._makeEnviron() self._registerView(view, '', None, None) - self._registerRootFactory(None) + self._registerRootFactory(rootfactory) router = self._makeOne() start_response = DummyStartResponse() request_events = self._registerEventListener(INewRequest) @@ -646,6 +593,40 @@ class RouterTests(unittest.TestCase): self.assertEqual(request.view_name, '') self.assertEqual(request.subpath, []) + def test_call_inotfound_appfactory_override(self): + from repoze.bfg.interfaces import INotFoundAppFactory + def app(): + """ """ + self.registry.registerUtility(app, INotFoundAppFactory) + rootfactory = make_rootfactory(None) + context = DummyContext() + self._registerTraverserFactory(context) + response = DummyResponse() + response.app_iter = ['Hello world'] + view = make_view(response) + environ = self._makeEnviron() + self._registerView(view, '', None, None) + self._registerRootFactory(rootfactory) + router = self._makeOne() + self.assertEqual(router.notfound_app_factory, app) + + def test_call_iunauth_appfactory_override(self): + from repoze.bfg.interfaces import IUnauthorizedAppFactory + def app(): + """ """ + self.registry.registerUtility(app, IUnauthorizedAppFactory) + rootfactory = make_rootfactory(None) + context = DummyContext() + self._registerTraverserFactory(context) + response = DummyResponse() + response.app_iter = ['Hello world'] + view = make_view(response) + environ = self._makeEnviron() + self._registerView(view, '', None, None) + self._registerRootFactory(rootfactory) + router = self._makeOne() + self.assertEqual(router.unauth_app_factory, app) + class MakeAppTests(unittest.TestCase): def setUp(self): cleanUp() @@ -793,11 +774,5 @@ class DummyResponse: app_iter = () class DummySecurityPolicy: - def forbidden(self, context, request): - self.request = request - ob = DummyResponse() - ob.status = '401 Unauthorized' - ob.app_iter = ['Unauthorized'] - ob.headerlist = () - return ob + pass diff --git a/repoze/bfg/tests/test_security.py b/repoze/bfg/tests/test_security.py index b9f9624d4..03a466e7c 100644 --- a/repoze/bfg/tests/test_security.py +++ b/repoze/bfg/tests/test_security.py @@ -243,16 +243,6 @@ class TestACLSecurityPolicy(unittest.TestCase): result = policy.principals_allowed_by_permission(None, 'read') self.assertEqual(result, []) - def test_forbidden(self): - policy = self._makeOne(lambda *arg: None) - context = DummyContext() - request = DummyRequest({}) - response = policy.forbidden(context, request) - self.failUnless('401 Unauthorized' in response.app_iter[0]) - self.assertEqual(response.status, '401 Unauthorized') - self.assertEqual(len(response.headerlist), 2) - - class TestInheritingACLSecurityPolicy(unittest.TestCase): def setUp(self): cleanUp() @@ -440,15 +430,6 @@ class TestInheritingACLSecurityPolicy(unittest.TestCase): result = policy.authenticated_userid(request) self.assertEqual(result, None) - def test_forbidden(self): - policy = self._makeOne(lambda *arg: None) - context = DummyContext() - request = DummyRequest({}) - response = policy.forbidden(context, request) - self.failUnless('401 Unauthorized' in response.app_iter[0]) - self.assertEqual(response.status, '401 Unauthorized') - self.assertEqual(len(response.headerlist), 2) - class TestAllPermissionsList(unittest.TestCase): def setUp(self): cleanUp() diff --git a/repoze/bfg/tests/test_wsgi.py b/repoze/bfg/tests/test_wsgi.py index 893364635..b9568eb82 100644 --- a/repoze/bfg/tests/test_wsgi.py +++ b/repoze/bfg/tests/test_wsgi.py @@ -131,7 +131,7 @@ class TestNotFound(unittest.TestCase): ('Content-Type', 'text/html')]) def test_with_message(self): - environ = {'repoze.bfg.message':'<hi!>'} + environ = {'message':'<hi!>'} L = [] def start_response(status, headers): L.append((status, headers)) @@ -166,7 +166,7 @@ class TestUnauthorized(unittest.TestCase): ('Content-Type', 'text/html')]) def test_with_message(self): - environ = {'repoze.bfg.message':'<hi!>'} + environ = {'message':'<hi!>'} L = [] def start_response(status, headers): L.append((status, headers)) diff --git a/repoze/bfg/wsgi.py b/repoze/bfg/wsgi.py index 027345673..abe7ebead 100644 --- a/repoze/bfg/wsgi.py +++ b/repoze/bfg/wsgi.py @@ -105,7 +105,7 @@ def wsgiapp2(wrapped): class HTTPException(object): def __call__(self, environ, start_response, exc_info=False): try: - msg = escape(environ['repoze.bfg.message']) + msg = escape(environ['message']) except KeyError: msg = '' html = """<body> |
