From 3389c5ea229884a1943873fe7e7ffc2800cefc22 Mon Sep 17 00:00:00 2001 From: Tore Lundqvist Date: Fri, 8 Jan 2016 17:08:08 +0100 Subject: Fixed #21608 -- Prevented logged out sessions being resurrected by concurrent requests. Thanks Simon Charette for the review. --- tests/defer_regress/tests.py | 2 +- tests/sessions_tests/tests.py | 47 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/defer_regress/tests.py b/tests/defer_regress/tests.py index ffb0b6e775..2594ffcdb8 100644 --- a/tests/defer_regress/tests.py +++ b/tests/defer_regress/tests.py @@ -131,7 +131,7 @@ class DeferRegressionTest(TestCase): s = SessionStore(SESSION_KEY) s.clear() s["item"] = item - s.save() + s.save(must_create=True) s = SessionStore(SESSION_KEY) s.modified = True diff --git a/tests/sessions_tests/tests.py b/tests/sessions_tests/tests.py index 7b3feec565..bb8ca2b635 100644 --- a/tests/sessions_tests/tests.py +++ b/tests/sessions_tests/tests.py @@ -8,6 +8,7 @@ import unittest from datetime import timedelta from django.conf import settings +from django.contrib.sessions.backends.base import UpdateError from django.contrib.sessions.backends.cache import SessionStore as CacheSession from django.contrib.sessions.backends.cached_db import \ SessionStore as CacheDBSession @@ -174,6 +175,7 @@ class SessionTestsMixin(object): prev_key = self.session.session_key prev_data = list(self.session.items()) self.session.cycle_key() + self.assertFalse(self.session.exists(prev_key)) self.assertNotEqual(self.session.session_key, prev_key) self.assertEqual(list(self.session.items()), prev_data) @@ -349,6 +351,28 @@ class SessionTestsMixin(object): # provided unknown key was cycled, not reused self.assertNotEqual(session.session_key, 'someunknownkey') + def test_session_save_does_not_resurrect_session_logged_out_in_other_context(self): + """ + Sessions shouldn't be resurrected by a concurrent request. + """ + # Create new session. + s1 = self.backend() + s1['test_data'] = 'value1' + s1.save(must_create=True) + + # Logout in another context. + s2 = self.backend(s1.session_key) + s2.delete() + + # Modify session in first context. + s1['test_data'] = 'value2' + with self.assertRaises(UpdateError): + # This should throw an exception as the session is deleted, not + # resurrect the session. + s1.save() + + self.assertEqual(s1.load(), {}) + class DatabaseSessionTests(SessionTestsMixin, TestCase): @@ -657,6 +681,25 @@ class SessionMiddlewareTests(TestCase): # Check that the value wasn't saved above. self.assertNotIn('hello', request.session.load()) + def test_session_update_error_redirect(self): + path = '/foo/' + request = RequestFactory().get(path) + response = HttpResponse() + middleware = SessionMiddleware() + + request.session = DatabaseSession() + 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) + def test_session_delete_on_end(self): request = RequestFactory().get('/') response = HttpResponse('Session test') @@ -808,3 +851,7 @@ class CookieSessionTests(SessionTestsMixin, unittest.TestCase): @unittest.skip("Cookie backend doesn't have an external store to create records in.") def test_session_load_does_not_create_record(self): pass + + @unittest.skip("CookieSession is stored in the client and there is no way to query it.") + def test_session_save_does_not_resurrect_session_logged_out_in_other_context(self): + pass -- cgit v1.3