From 1ce04bcce0076360623ae164afd3541a5c031af2 Mon Sep 17 00:00:00 2001 From: Andrew Nester Date: Tue, 25 Oct 2016 14:23:14 +0300 Subject: [PATCH] Fixed #27363 -- Replaced unsafe redirect in SessionMiddleware with SuspiciousOperation. --- django/contrib/sessions/middleware.py | 11 ++++++----- docs/releases/1.10.3.txt | 4 ++++ tests/sessions_tests/tests.py | 19 ++++++++++--------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/django/contrib/sessions/middleware.py b/django/contrib/sessions/middleware.py index 5aaff43426..60faa2b328 100644 --- a/django/contrib/sessions/middleware.py +++ b/django/contrib/sessions/middleware.py @@ -3,7 +3,7 @@ from importlib import import_module from django.conf import settings from django.contrib.sessions.backends.base import UpdateError -from django.shortcuts import redirect +from django.core.exceptions import SuspiciousOperation from django.utils.cache import patch_vary_headers from django.utils.deprecation import MiddlewareMixin from django.utils.http import cookie_date @@ -57,10 +57,11 @@ class SessionMiddleware(MiddlewareMixin): try: request.session.save() except UpdateError: - # The user is now logged out; redirecting to same - # page will result in a redirect to the login page - # if required. - return redirect(request.path) + raise SuspiciousOperation( + "The request's session was deleted before the " + "request completed. The user may have logged " + "out in a concurrent request, for example." + ) response.set_cookie( settings.SESSION_COOKIE_NAME, request.session.session_key, max_age=max_age, diff --git a/docs/releases/1.10.3.txt b/docs/releases/1.10.3.txt index ba01287aa5..cc5674f385 100644 --- a/docs/releases/1.10.3.txt +++ b/docs/releases/1.10.3.txt @@ -26,3 +26,7 @@ Bugfixes * Prevented ``i18n_patterns()`` from using too much of the URL as the language to fix a use case for ``prefix_default_language=False`` (:ticket:`27063`). + +* Replaced a possibly incorrect redirect from ``SessionMiddleware`` when a + session is destroyed in a concurrent request with a ``SuspiciousOperation`` + to indicate that the request can't be completed (:ticket:`27363`). diff --git a/tests/sessions_tests/tests.py b/tests/sessions_tests/tests.py index ffc7e9d942..d5690e1668 100644 --- a/tests/sessions_tests/tests.py +++ b/tests/sessions_tests/tests.py @@ -25,7 +25,7 @@ from django.contrib.sessions.serializers import ( from django.core import management from django.core.cache import caches from django.core.cache.backends.base import InvalidCacheBackendError -from django.core.exceptions import ImproperlyConfigured +from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation from django.http import HttpResponse from django.test import ( RequestFactory, TestCase, ignore_warnings, override_settings, @@ -708,14 +708,15 @@ class SessionMiddlewareTests(TestCase): request.session.save(must_create=True) request.session.delete() - # Handle the response through the middleware. It will try to save the - # deleted session which will cause an UpdateError that's caught and - # results in a redirect to the original page. - response = middleware.process_response(request, response) - - # Check that the response is a redirect. - self.assertEqual(response.status_code, 302) - self.assertEqual(response['Location'], path) + msg = ( + "The request's session was deleted before the request completed. " + "The user may have logged out in a concurrent request, for example." + ) + with self.assertRaisesMessage(SuspiciousOperation, msg): + # Handle the response through the middleware. It will try to save + # the deleted session which will cause an UpdateError that's caught + # and raised as a SuspiciousOperation. + middleware.process_response(request, response) def test_session_delete_on_end(self): request = RequestFactory().get('/')