From 455778d138ea623d224c9206e5001fd2a1fd7e1c Mon Sep 17 00:00:00 2001
From: Tres Seaver <tseaver@palladion.com>
Date: Tue, 31 May 2016 19:35:57 +0200
Subject: [PATCH] middleware: Avoid passing extracted 'identity' to 'remember' during egress.

---
 CHANGES.rst                         |    3 +++
 repoze/who/tests/test_middleware.py |   34 ++++++++++++++++++++++++++++++++++
 repoze/who/middleware.py            |    5 ++---
 3 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/CHANGES.rst b/CHANGES.rst
index d507b75..9e4b6eb 100644
--- a/CHANGES.rst
+++ b/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.
diff --git a/repoze/who/middleware.py b/repoze/who/middleware.py
index 8b5771e..d84c4ed 100644
--- a/repoze/who/middleware.py
+++ b/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)
diff --git a/repoze/who/tests/test_middleware.py b/repoze/who/tests/test_middleware.py
index b79998d..f53e81a 100644
--- a/repoze/who/tests/test_middleware.py
+++ b/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

--
Gitblit v1.9.3