From c7b7adbaed26c9d6b2f4f72754da8615f5aa579c Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 19 Jun 2009 11:58:19 +0000 Subject: - Move BBB logic for registering an IAuthenticationPolicy/IForbiddenView/INotFoundView based on older concepts from the router module's ``make_app`` function into the ``repoze.bfg.zcml.zcml_configure`` callable, to service compatibility with scripts that use "zope.configuration.xmlconfig" (replace with ``repoze.bfg.zml.zcml_configure`` as necessary to get BBB logic) --- CHANGES.txt | 8 ++++ repoze/bfg/router.py | 78 ++------------------------------------ repoze/bfg/tests/test_router.py | 76 ++++++------------------------------- repoze/bfg/tests/test_zcml.py | 84 ++++++++++++++++++++++++++++++++++++++--- repoze/bfg/zcml.py | 75 ++++++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 144 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index c4897660b..f5d9eca37 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -161,6 +161,14 @@ Bug Fixes - The ``bfg_alchemy`` Paster template named "repoze.tm" in its pipeline rather than "repoze.tm2", causing the startup to fail. +- Move BBB logic for registering an + IAuthenticationPolicy/IForbiddenView/INotFoundView based on older + concepts from the router module's ``make_app`` function into the + ``repoze.bfg.zcml.zcml_configure`` callable, to service + compatibility with scripts that use "zope.configuration.xmlconfig" + (replace with ``repoze.bfg.zml.zcml_configure`` as necessary to get + BBB logic) + Documentation ------------- diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py index 145e0ad7c..0a863f93a 100644 --- a/repoze/bfg/router.py +++ b/repoze/bfg/router.py @@ -15,7 +15,6 @@ from repoze.bfg.events import NewResponse from repoze.bfg.events import WSGIApplicationCreatedEvent from repoze.bfg.interfaces import ILogger -from repoze.bfg.interfaces import ISecurityPolicy from repoze.bfg.interfaces import IResponseFactory from repoze.bfg.interfaces import IRootFactory from repoze.bfg.interfaces import IRouter @@ -23,8 +22,6 @@ from repoze.bfg.interfaces import IRoutesMapper from repoze.bfg.interfaces import ISettings from repoze.bfg.interfaces import IForbiddenView from repoze.bfg.interfaces import INotFoundView -from repoze.bfg.interfaces import IUnauthorizedAppFactory -from repoze.bfg.interfaces import INotFoundAppFactory from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IViewPermission from repoze.bfg.interfaces import IAuthorizationPolicy @@ -38,8 +35,6 @@ from repoze.bfg.registry import populateRegistry from repoze.bfg.request import request_factory -from repoze.bfg.secpols import registerBBBAuthn - from repoze.bfg.security import Allowed from repoze.bfg.settings import Settings @@ -64,65 +59,15 @@ class Router(object): def __init__(self, registry): self.registry = registry self.logger = registry.queryUtility(ILogger, 'repoze.bfg.debug') - - forbidden = None - - unauthorized_app_factory = registry.queryUtility( - IUnauthorizedAppFactory) - - 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.IForbiddenView.' - 'The IUnauthorizedAppFactory interface was deprecated in ' - 'repoze.bfg 0.9 and will be removed in a subsequent version ' - 'of repoze.bfg. See the "Hooks" chapter of the repoze.bfg ' - 'documentation for more information about ' - 'IForbiddenView.') - self.logger and self.logger.warn(warning) - def forbidden(context, request): - app = unauthorized_app_factory() - response = request.get_response(app) - return response - - forbidden = registry.queryUtility(IForbiddenView, default=forbidden) - - self.forbidden_view = forbidden or default_forbidden_view - - notfound = None - - notfound_app_factory = registry.queryUtility(INotFoundAppFactory) - - if notfound_app_factory is not None: - warning = ( - 'Instead of registering a utility against the ' - 'repoze.bfg.interfaces.INotFoundAppFactory interface ' - 'to return a custom notfound response, you should use the ' - '"notfound_view" ZCML directive. The ' - 'INotFoundAppFactory interface was deprecated in' - 'repoze.bfg 0.9 and will be removed in a subsequent version ' - 'of repoze.bfg. See the "Hooks" chapter of the repoze.bfg ' - 'documentation for more information about ' - 'the "notfound_view" directive.') - self.logger and self.logger.warn(warning) - def notfound(context, request): - app = notfound_app_factory() - response = request.get_response(app) - return response - - notfound = registry.queryUtility(INotFoundView, default=notfound) - - self.notfound_view = notfound or default_notfound_view - + self.forbidden_view = registry.queryUtility( + IForbiddenView, default=default_forbidden_view) + self.notfound_view = registry.queryUtility( + INotFoundView, default=default_notfound_view) settings = registry.queryUtility(ISettings) if settings is not None: self.debug_authorization = settings.debug_authorization self.debug_notfound = settings.debug_notfound - self.secured = not not registry.queryUtility(IAuthenticationPolicy) - self.root_factory = registry.queryUtility(IRootFactory, default=DefaultRootFactory) self.root_policy = self.root_factory # b/w compat @@ -344,21 +289,6 @@ def make_app(root_factory, package=None, filename='configure.zcml', populateRegistry(registry, filename, package) - if not authentication_policy: - # deal with bw compat of <= 0.8 security policies (deprecated) - secpol = registry.queryUtility(ISecurityPolicy) - if secpol is not None: - debug_logger.warn( - 'Your application is using a repoze.bfg ``ISecurityPolicy`` ' - '(probably registered via ZCML). This form of security policy ' - 'has been deprecated in BFG 0.9. See the "Security" chapter ' - 'of the repoze.bfg documentation to see how to register a more ' - 'up to date set of security policies (an authentication ' - 'policy and an authorization policy). ISecurityPolicy-based ' - 'security policies will cease to work in a later BFG ' - 'release.') - registerBBBAuthn(secpol, registry) - if mapper.has_routes(): # if the user had any statements in his configuration, # use the RoutesRootFactory as the IRootFactory; otherwise use the diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py index 1049fa752..389920029 100644 --- a/repoze/bfg/tests/test_router.py +++ b/repoze/bfg/tests/test_router.py @@ -15,9 +15,11 @@ class RouterTests(unittest.TestCase): cleanUp() def _registerLogger(self): + from zope.component import getSiteManager + gsm = getSiteManager() from repoze.bfg.interfaces import ILogger logger = DummyLogger() - self.registry.registerUtility(logger, ILogger, name='repoze.bfg.debug') + gsm.registerUtility(logger, ILogger, name='repoze.bfg.debug') return logger def _registerSettings(self, **kw): @@ -155,42 +157,6 @@ class RouterTests(unittest.TestCase): from repoze.bfg.router import default_notfound_view self.assertEqual(router.notfound_view, default_notfound_view) - def test_iunauthorized_appfactory_BBB(self): - from repoze.bfg.interfaces import IUnauthorizedAppFactory - environ = self._makeEnviron() - context = DummyContext() - self._registerTraverserFactory(context) - logger = self._registerLogger() - def factory(): - return 'yo' - self.registry.registerUtility(factory, IUnauthorizedAppFactory) - router = self._makeOne() - self.assertEqual(len(logger.messages), 1) - self.failUnless('IForbiddenView' in logger.messages[0]) - class DummyRequest: - def get_response(self, app): - return app - req = DummyRequest() - self.assertEqual(router.forbidden_view(None, req), 'yo') - - def test_inotfound_appfactory_BBB(self): - from repoze.bfg.interfaces import INotFoundAppFactory - environ = self._makeEnviron() - context = DummyContext() - self._registerTraverserFactory(context) - logger = self._registerLogger() - def factory(): - return 'yo' - self.registry.registerUtility(factory, INotFoundAppFactory) - router = self._makeOne() - self.assertEqual(len(logger.messages), 1) - self.failUnless('notfound_view' in logger.messages[0]) - class DummyRequest: - def get_response(self, app): - return app - req = DummyRequest() - self.assertEqual(router.notfound_view(None, req), 'yo') - def test_call_no_view_registered_no_isettings(self): environ = self._makeEnviron() context = DummyContext() @@ -843,22 +809,6 @@ class MakeAppTests(unittest.TestCase): self.assertEqual(app.registry.getUtility(IAuthorizationPolicy), authzpolicy) - def test_secpol_BBB_registrations(self): - from repoze.bfg.interfaces import IAuthorizationPolicy - from repoze.bfg.interfaces import IAuthenticationPolicy - from repoze.bfg.interfaces import ISecurityPolicy - secpol = DummySecurityPolicy() - from zope.component import getGlobalSiteManager - gsm = getGlobalSiteManager() - gsm.registerUtility(secpol, ISecurityPolicy) - from repoze.bfg.tests import routesapp - logger = DummyLogger() - app = self._callFUT(None, routesapp, registry=gsm, debug_logger=logger) - self.failUnless(app.registry.queryUtility(IAuthenticationPolicy)) - self.failUnless(app.registry.queryUtility(IAuthorizationPolicy)) - self.assertEqual(len(logger.messages), 1) - self.failUnless('ISecurityPolicy' in logger.messages[0]) - class TestDefaultForbiddenView(unittest.TestCase): def _callFUT(self, context, request): from repoze.bfg.router import default_forbidden_view @@ -929,22 +879,11 @@ class DummyResponse: headerlist = () app_iter = () -class DummySecurityPolicy: - pass - class DummyRequest: def __init__(self, environ): self.environ = environ -class DummyLogger: - def __init__(self): - self.messages = [] - def info(self, msg): - self.messages.append(msg) - warn = info - debug = info - class DummyThreadLocalManager: def __init__(self): self.pushed = [] @@ -958,3 +897,12 @@ class DummyThreadLocalManager: class DummyAuthenticationPolicy: pass + +class DummyLogger: + def __init__(self): + self.messages = [] + def info(self, msg): + self.messages.append(msg) + warn = info + debug = info + diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py index 7fe33e56b..30938d101 100644 --- a/repoze/bfg/tests/test_zcml.py +++ b/repoze/bfg/tests/test_zcml.py @@ -950,6 +950,10 @@ class TestRouteDirective(unittest.TestCase): class TestZCMLConfigure(unittest.TestCase): i = 0 + def _callFUT(self, path, package): + from repoze.bfg.zcml import zcml_configure + return zcml_configure(path, package) + def setUp(self): cleanUp() self.tempdir = None @@ -979,19 +983,72 @@ class TestZCMLConfigure(unittest.TestCase): sys.path.pop(0) shutil.rmtree(self.tempdir) - def test_file_configure(self): - from repoze.bfg.zcml import file_configure - actions = file_configure('configure.zcml', self.module) + def test_zcml_configure(self): + actions = self._callFUT('configure.zcml', self.module) self.failUnless(actions) self.failUnless(isinstance(actions, list)) - def test_file_configure_nonexistent_configure_dot_zcml(self): + def test_zcml_configure_nonexistent_configure_dot_zcml(self): import os - from repoze.bfg.zcml import file_configure os.remove(os.path.join(self.packagepath, 'configure.zcml')) - self.assertRaises(IOError, file_configure, 'configure.zcml', + self.assertRaises(IOError, self._callFUT, 'configure.zcml', self.module) + def test_secpol_BBB(self): + from repoze.bfg.interfaces import IAuthorizationPolicy + from repoze.bfg.interfaces import IAuthenticationPolicy + from repoze.bfg.interfaces import ISecurityPolicy + from repoze.bfg.interfaces import ILogger + secpol = DummySecurityPolicy() + from zope.component import getGlobalSiteManager + gsm = getGlobalSiteManager() + gsm.registerUtility(secpol, ISecurityPolicy) + logger = DummyLogger() + gsm.registerUtility(logger, ILogger, name='repoze.bfg.debug') + self._callFUT('configure.zcml', self.module) + self.failUnless(gsm.queryUtility(IAuthenticationPolicy)) + self.failUnless(gsm.queryUtility(IAuthorizationPolicy)) + self.assertEqual(len(logger.messages), 1) + self.failUnless('ISecurityPolicy' in logger.messages[0]) + + def test_iunauthorized_appfactory_BBB(self): + from repoze.bfg.interfaces import IUnauthorizedAppFactory + from repoze.bfg.interfaces import IForbiddenView + from zope.component import getGlobalSiteManager + from repoze.bfg.interfaces import ILogger + context = DummyContext() + def factory(): + return 'yo' + logger = DummyLogger() + gsm = getGlobalSiteManager() + gsm.registerUtility(factory, IUnauthorizedAppFactory) + logger = DummyLogger() + gsm.registerUtility(logger, ILogger, name='repoze.bfg.debug') + self._callFUT('configure.zcml', self.module) + self.assertEqual(len(logger.messages), 1) + self.failUnless('forbidden' in logger.messages[0]) + forbidden = gsm.getUtility(IForbiddenView) + self.assertEqual(forbidden(None, DummyRequest()), 'yo') + + def test_inotfound_appfactory_BBB(self): + from repoze.bfg.interfaces import INotFoundAppFactory + from repoze.bfg.interfaces import INotFoundView + from zope.component import getGlobalSiteManager + from repoze.bfg.interfaces import ILogger + context = DummyContext() + def factory(): + return 'yo' + logger = DummyLogger() + gsm = getGlobalSiteManager() + gsm.registerUtility(factory, INotFoundAppFactory) + logger = DummyLogger() + gsm.registerUtility(logger, ILogger, name='repoze.bfg.debug') + self._callFUT('configure.zcml', self.module) + self.assertEqual(len(logger.messages), 1) + self.failUnless('notfound' in logger.messages[0]) + notfound = gsm.getUtility(INotFoundView) + self.assertEqual(notfound(None,DummyRequest()), 'yo') + class TestBFGViewFunctionGrokker(unittest.TestCase): def setUp(self): cleanUp() @@ -1302,3 +1359,18 @@ from zope.interface import Interface class IDummy(Interface): pass +class DummySecurityPolicy: + pass + +class DummyLogger: + def __init__(self): + self.messages = [] + def info(self, msg): + self.messages.append(msg) + warn = info + debug = info + +class DummyRequest: + def get_response(self, app): + return app + diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index 1b66839d6..8020cdd9f 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -20,15 +20,23 @@ from zope.schema import TextLine from repoze.bfg.interfaces import IRoutesMapper from repoze.bfg.interfaces import IViewPermission +from repoze.bfg.interfaces import INotFoundAppFactory from repoze.bfg.interfaces import INotFoundView from repoze.bfg.interfaces import IForbiddenView +from repoze.bfg.interfaces import IAuthenticationPolicy +from repoze.bfg.interfaces import ISecurityPolicy from repoze.bfg.interfaces import IView +from repoze.bfg.interfaces import IUnauthorizedAppFactory +from repoze.bfg.interfaces import ILogger from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES from repoze.bfg.request import named_request_factories from repoze.bfg.security import ViewPermissionFactory +from repoze.bfg.secpols import registerBBBAuthn + + import martian def handler(methodName, *args, **kwargs): @@ -363,6 +371,73 @@ def zcml_configure(name, package): context.package = package xmlconfig.include(context, name, package) context.execute_actions(clear=False) + + logger = queryUtility(ILogger, name='repoze.bfg.debug') + registry = getSiteManager() + + # persistence means always having to say you're sorry + + authentication_policy = registry.queryUtility(IAuthenticationPolicy) + + if not authentication_policy: + # deal with bw compat of <= 0.8 security policies (deprecated) + secpol = registry.queryUtility(ISecurityPolicy) + if secpol is not None: + logger and logger.warn( + 'Your application is using a repoze.bfg ``ISecurityPolicy`` ' + '(probably registered via ZCML). This form of security policy ' + 'has been deprecated in BFG 0.9. See the "Security" chapter ' + 'of the repoze.bfg documentation to see how to register a more ' + 'up to date set of security policies (an authentication ' + 'policy and an authorization policy). ISecurityPolicy-based ' + 'security policies will cease to work in a later BFG ' + 'release.') + registerBBBAuthn(secpol, registry) + + forbidden_view = registry.queryUtility(IForbiddenView) + unauthorized_app_factory = registry.queryUtility(IUnauthorizedAppFactory) + + if unauthorized_app_factory is not None: + if forbidden_view is None: + warning = ( + 'Instead of registering a utility against the ' + 'repoze.bfg.interfaces.IUnauthorizedAppFactory interface ' + 'to return a custom forbidden response, you should now ' + 'use the "forbidden" ZCML directive.' + 'The IUnauthorizedAppFactory interface was deprecated in ' + 'repoze.bfg 0.9 and will be removed in a subsequent version ' + 'of repoze.bfg. See the "Hooks" chapter of the repoze.bfg ' + 'documentation for more information about ' + 'the forbidden directive.') + logger and logger.warn(warning) + def forbidden(context, request): + app = unauthorized_app_factory() + response = request.get_response(app) + return response + registry.registerUtility(forbidden, IForbiddenView) + + notfound_view = registry.queryUtility(INotFoundView) + notfound_app_factory = registry.queryUtility(INotFoundAppFactory) + + if notfound_app_factory is not None: + if notfound_view is None: + warning = ( + 'Instead of registering a utility against the ' + 'repoze.bfg.interfaces.INotFoundAppFactory interface ' + 'to return a custom notfound response, you should use the ' + '"notfound" ZCML directive. The ' + 'INotFoundAppFactory interface was deprecated in' + 'repoze.bfg 0.9 and will be removed in a subsequent version ' + 'of repoze.bfg. See the "Hooks" chapter of the repoze.bfg ' + 'documentation for more information about ' + 'the "notfound" directive.') + logger and logger.warn(warning) + def notfound(context, request): + app = notfound_app_factory() + response = request.get_response(app) + return response + registry.registerUtility(notfound, INotFoundView) + return context.actions file_configure = zcml_configure # backwards compat (>0.8.1) -- cgit v1.2.3