Tres Seaver
2016-05-31 455778d138ea623d224c9206e5001fd2a1fd7e1c
middleware: Avoid passing extracted 'identity' to 'remember' during egress.

The app may have called 'api.forget()'.

Fixes #21.
3 files modified
42 ■■■■■ changed files
CHANGES.rst 3 ●●●●● patch | view | raw | blame | history
repoze/who/middleware.py 5 ●●●●● patch | view | raw | blame | history
repoze/who/tests/test_middleware.py 34 ●●●●● patch | view | raw | blame | history
CHANGES.rst
@@ -8,6 +8,9 @@
- Drop support for Python 2.6 and 3.2.
- ``middleware``:  avoid passing extracted ``identity`` to ``remember``
  during egress (the app may have called ``api.forget()``).  See #21.
- ``_auth_tkt`` / ``plugins.auth_tkt``:  add support for any hash algorithm
  supported by the ``hashlib`` module in Python's standard library.
  Fixes #22 via #23.
repoze/who/middleware.py
@@ -72,8 +72,7 @@
        logger = self.logger
        path_info = environ.get('PATH_INFO', None)
        logger and logger.info(_STARTED % path_info)
        identity = None
        identity = api.authenticate()
        api.authenticate()  # identity saved in environ
        # allow identifier plugins to replace the downstream
        # application (to do redirection and unauthorized themselves
@@ -114,7 +113,7 @@
                raise RuntimeError('no challengers found')
        else:
            logger and logger.info('no challenge required')
            remember_headers = api.remember(identity)
            remember_headers = api.remember()
            wrapper.finish_response(remember_headers)
        logger and logger.info(_ENDED % path_info)
repoze/who/tests/test_middleware.py
@@ -224,6 +224,29 @@
        self.assertEqual(start_response.status, '200 OK')
        self.assertEqual(start_response.headers, headers)
    def test_call_200_no_challengers_app_calls_forget(self):
        # See https://github.com/repoze/repoze.who/issues/21
        environ = self._makeEnviron()
        remember_headers = [('remember', '1')]
        forget_headers = [('forget', '1')]
        app = DummyLogoutApp('200 OK')
        credentials = {'login':'chris', 'password':'password'}
        identifier = DummyIdentifier(
            credentials,
            remember_headers=remember_headers,
            forget_headers=forget_headers)
        identifiers = [ ('identifier', identifier) ]
        authenticator = DummyAuthenticator()
        authenticators = [ ('authenticator', authenticator) ]
        mw = self._makeOne(
            app=app, identifiers=identifiers, authenticators=authenticators)
        start_response = DummyStartResponse()
        result = mw(environ, start_response)
        self.assertEqual(mw.app.environ, environ)
        self.assertEqual(result, ['body'])
        self.assertEqual(start_response.status, '200 OK')
        self.assertEqual(start_response.headers, forget_headers)
    def test_call_401_no_identifiers(self):
        from webob.exc import HTTPUnauthorized
        environ = self._makeEnviron()
@@ -607,6 +630,17 @@
        start_response(self.status, self.headers)
        return ['body']
class DummyLogoutApp(object):
    def __init__(self, status):
        self.status = status
    def __call__(self, environ, start_response):
        self.environ = environ
        api = environ['repoze.who.api']
        headers = api.logout()
        start_response(self.status, headers)
        return ['body']
class DummyGeneratorApp(object):
    def __init__(self, status, headers):
        self.status = status