Fixed #27363 -- Replaced unsafe redirect in SessionMiddleware with SuspiciousOperation.

This commit is contained in:
Andrew Nester 2016-10-25 14:23:14 +03:00 committed by Tim Graham
parent 9c2e1ad6a5
commit 1ce04bcce0
3 changed files with 20 additions and 14 deletions

View File

@ -3,7 +3,7 @@ from importlib import import_module
from django.conf import settings from django.conf import settings
from django.contrib.sessions.backends.base import UpdateError 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.cache import patch_vary_headers
from django.utils.deprecation import MiddlewareMixin from django.utils.deprecation import MiddlewareMixin
from django.utils.http import cookie_date from django.utils.http import cookie_date
@ -57,10 +57,11 @@ class SessionMiddleware(MiddlewareMixin):
try: try:
request.session.save() request.session.save()
except UpdateError: except UpdateError:
# The user is now logged out; redirecting to same raise SuspiciousOperation(
# page will result in a redirect to the login page "The request's session was deleted before the "
# if required. "request completed. The user may have logged "
return redirect(request.path) "out in a concurrent request, for example."
)
response.set_cookie( response.set_cookie(
settings.SESSION_COOKIE_NAME, settings.SESSION_COOKIE_NAME,
request.session.session_key, max_age=max_age, request.session.session_key, max_age=max_age,

View File

@ -26,3 +26,7 @@ Bugfixes
* Prevented ``i18n_patterns()`` from using too much of the URL as the language * 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`). 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`).

View File

@ -25,7 +25,7 @@ from django.contrib.sessions.serializers import (
from django.core import management from django.core import management
from django.core.cache import caches from django.core.cache import caches
from django.core.cache.backends.base import InvalidCacheBackendError 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.http import HttpResponse
from django.test import ( from django.test import (
RequestFactory, TestCase, ignore_warnings, override_settings, RequestFactory, TestCase, ignore_warnings, override_settings,
@ -708,14 +708,15 @@ class SessionMiddlewareTests(TestCase):
request.session.save(must_create=True) request.session.save(must_create=True)
request.session.delete() request.session.delete()
# Handle the response through the middleware. It will try to save the msg = (
# deleted session which will cause an UpdateError that's caught and "The request's session was deleted before the request completed. "
# results in a redirect to the original page. "The user may have logged out in a concurrent request, for example."
response = middleware.process_response(request, response) )
with self.assertRaisesMessage(SuspiciousOperation, msg):
# Check that the response is a redirect. # Handle the response through the middleware. It will try to save
self.assertEqual(response.status_code, 302) # the deleted session which will cause an UpdateError that's caught
self.assertEqual(response['Location'], path) # and raised as a SuspiciousOperation.
middleware.process_response(request, response)
def test_session_delete_on_end(self): def test_session_delete_on_end(self):
request = RequestFactory().get('/') request = RequestFactory().get('/')