From 9d410f33a0e5c8d1315876cb576a8e2fa855fbf5 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Sat, 25 Nov 2017 18:54:27 +0100 Subject: [PATCH] [SECURITY] Fix handling of session timeouts --- src/pretix/control/middleware.py | 8 +++++--- src/tests/control/test_auth.py | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/pretix/control/middleware.py b/src/pretix/control/middleware.py index 43aa23de1..d1b7dc22e 100644 --- a/src/pretix/control/middleware.py +++ b/src/pretix/control/middleware.py @@ -64,15 +64,17 @@ class PermissionMiddleware(MiddlewareMixin): return self._login_redirect(request) if not settings.PRETIX_LONG_SESSIONS or not request.session.get('pretix_auth_long_session', False): + # If this logic is updated, make sure to also update the logic in pretix/api/auth/permission.py last_used = request.session.get('pretix_auth_last_used', time.time()) if time.time() - request.session.get('pretix_auth_login_time', time.time()) > settings.PRETIX_SESSION_TIMEOUT_ABSOLUTE: logout(request) request.session['pretix_auth_login_time'] = 0 return self._login_redirect(request) - if time.time() - last_used > settings.PRETIX_SESSION_TIMEOUT_RELATIVE and url_name != 'user.reauth': - return redirect(reverse('control:user.reauth') + '?next=' + quote(request.get_full_path())) + if url_name != 'user.reauth': + if time.time() - last_used > settings.PRETIX_SESSION_TIMEOUT_RELATIVE: + return redirect(reverse('control:user.reauth') + '?next=' + quote(request.get_full_path())) - request.session['pretix_auth_last_used'] = int(time.time()) + request.session['pretix_auth_last_used'] = int(time.time()) if 'event' in url.kwargs and 'organizer' in url.kwargs: request.event = Event.objects.filter( diff --git a/src/tests/control/test_auth.py b/src/tests/control/test_auth.py index 877b74c68..1f86d145b 100644 --- a/src/tests/control/test_auth.py +++ b/src/tests/control/test_auth.py @@ -566,6 +566,26 @@ class SessionTimeOutTest(TestCase): response = self.client.get('/control/') self.assertEqual(response.status_code, 200) + def test_log_out_after_relative_timeout_really_enforced(self): + # Regression test added after a security problem in 1.9.1 + # The problem was that, once the relative timeout happened, the user was redirected + # to /control/reauth/, but loading /control/reauth/ was already considered to be + # "session activitiy". Therefore, after loding /control/reauth/, the session was no longer + # in the timeout state and the user was able to access pages again without re-entering the + # password. + session = self.client.session + session['pretix_auth_long_session'] = False + session['pretix_auth_login_time'] = int(time.time()) - 3600 * 6 + session['pretix_auth_last_used'] = int(time.time()) - 3600 * 3 - 60 + session.save() + + response = self.client.get('/control/') + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, '/control/reauth/?next=/control/') + self.client.get('/control/reauth/?next=/control/') + response = self.client.get('/control/') + self.assertEqual(response.status_code, 302) + def test_update_session_activity(self): t1 = int(time.time()) - 5 session = self.client.session