diff --git a/requirements b/requirements index 6576973..0e6d119 100644 --- a/requirements +++ b/requirements @@ -1,2 +1,3 @@ django>=1.8,<=1.11 ua_parser==0.7.1 +python-dateutil==2.8.0 diff --git a/security/middleware.py b/security/middleware.py index 0aed2bf..73a4cc5 100644 --- a/security/middleware.py +++ b/security/middleware.py @@ -1,5 +1,6 @@ # Copyright (c) 2011, SD Elements. See LICENSE.txt for details. +import dateutil.parser import importlib import json import logging @@ -906,6 +907,44 @@ class SessionExpiryPolicyMiddleware(CustomLogoutMixin, BaseMiddleware): START_TIME_KEY = 'starttime' LAST_ACTIVITY_KEY = 'lastactivity' + @classmethod + def _get_datetime_in_session(cls, key, session): + return dateutil.parser.parse(session[key]) + + @classmethod + def _set_datetime_in_session(cls, key, value, session): + session[key] = str(value) + + @classmethod + def get_start_time(cls, request): + return cls._get_datetime_in_session( + cls.START_TIME_KEY, + request.session + ) + + @classmethod + def set_start_time(cls, request, date): + cls._set_datetime_in_session( + cls.START_TIME_KEY, + date, + request.session + ) + + @classmethod + def get_last_activity(cls, request): + return cls._get_datetime_in_session( + cls.LAST_ACTIVITY_KEY, + request.session + ) + + @classmethod + def set_last_activity(cls, request, date): + cls._set_datetime_in_session( + cls.LAST_ACTIVITY_KEY, + date, + request.session + ) + def load_setting(self, setting, value): if setting == 'SESSION_COOKIE_AGE': self.SESSION_COOKIE_AGE = value or self.SECONDS_PER_DAY @@ -944,8 +983,8 @@ def process_request(self, request): if ( self.START_TIME_KEY not in request.session or self.LAST_ACTIVITY_KEY not in request.session or - timezone.is_naive(request.session[self.START_TIME_KEY]) or - timezone.is_naive(request.session[self.LAST_ACTIVITY_KEY]) + timezone.is_naive(self.get_start_time(request)) or + timezone.is_naive(self.get_last_activity(request)) ): response = self.process_new_session(request) else: @@ -959,14 +998,14 @@ def process_new_session(self, request): session = request.session logger.debug("New session %s started: %s", session.session_key, now) - session[self.START_TIME_KEY] = now - session[self.LAST_ACTIVITY_KEY] = now + self.set_start_time(request, now) + self.set_last_activity(request, now) def process_existing_session(self, request): now = timezone.now() session = request.session - start_time = session[self.START_TIME_KEY] - last_activity_time = session[self.LAST_ACTIVITY_KEY] + start_time = self.get_start_time(request) + last_activity_time = self.get_last_activity(request) logger.debug("Session %s started: %s", session.session_key, @@ -997,7 +1036,7 @@ def process_existing_session(self, request): return response logger.debug("Session %s is still active.", session.session_key) - session[self.LAST_ACTIVITY_KEY] = now + self.set_last_activity(request, now) def get_diff_in_seconds(self, now, time): diff = now - time diff --git a/setup.py b/setup.py index 3b2c79a..d15dadb 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ def run(self): long_description=readme, maintainer="SD Elements", maintainer_email="django-security@sdelements.com", - version="0.9.10", + version="0.10.0", packages=["security", "security.south_migrations", "security.migrations", "security.auth_throttling"], url='https://github.com/sdelements/django-security', @@ -52,5 +52,6 @@ def run(self): install_requires=[ 'django>=1.8', 'ua_parser>=0.7.1', + 'python-dateutil==2.8.0', ], cmdclass={'test': Test}) diff --git a/testing/settings.py b/testing/settings.py index 919694e..8fa0f2c 100644 --- a/testing/settings.py +++ b/testing/settings.py @@ -159,9 +159,6 @@ def is_version(version): P3P_POLICY_URL = '/w3c/p3p.xml' P3P_COMPACT_POLICY = 'PRIVATE' -# Django 1.6 uses JSONSerializer which can't handle datetime -SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' - LOGGING = { 'version': 1, 'disable_existing_loggers': False, diff --git a/testing/tests/tests.py b/testing/tests/tests.py index b98881e..dd13acb 100644 --- a/testing/tests/tests.py +++ b/testing/tests/tests.py @@ -337,12 +337,14 @@ def test_session_variables_are_set(self): self.client.get('/home/') now = timezone.now() - start_time = self.client.session[ - SessionExpiryPolicyMiddleware.START_TIME_KEY - ] - last_activity = self.client.session[ - SessionExpiryPolicyMiddleware.LAST_ACTIVITY_KEY - ] + start_time = SessionExpiryPolicyMiddleware._get_datetime_in_session( + SessionExpiryPolicyMiddleware.START_TIME_KEY, + self.client.session + ) + last_activity = SessionExpiryPolicyMiddleware._get_datetime_in_session( + SessionExpiryPolicyMiddleware.LAST_ACTIVITY_KEY, + self.client.session + ) self.assertTrue(now - start_time < datetime.timedelta(seconds=10)) self.assertTrue(now - last_activity < datetime.timedelta(seconds=10)) @@ -354,7 +356,11 @@ def session_expiry_test(self, key, expired): """ self.assertTrue(self.client.get('/home/').status_code, 200) session = self.client.session - session[key] = expired + SessionExpiryPolicyMiddleware._set_datetime_in_session( + key, + expired, + session + ) session.save() response = self.client.get('/home/') self.assertRedirects(response, @@ -392,7 +398,11 @@ def test_exempted_session_expiry_urls(self): self.assertTrue(self.client.get('/home/').status_code, 200) session = self.client.session - session[SessionExpiryPolicyMiddleware().LAST_ACTIVITY_KEY] = expired + SessionExpiryPolicyMiddleware._set_datetime_in_session( + SessionExpiryPolicyMiddleware.LAST_ACTIVITY_KEY, + expired, + session + ) session.save() exempted_response = self.client.get('/accounts/login/')