summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2020-02-15 12:20:37 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-03-02 12:16:48 +0100
commitd4fff711d4c97356bd6ba1273d2a5e349326eb5f (patch)
treea8522faded6f99d2bd3299e4cb439b22b848ea38
parentdaaa894960e1b2bce8ee31b7c109be84f598a84e (diff)
downloaddjango-d4fff711d4c97356bd6ba1273d2a5e349326eb5f.tar.gz
Fixed #31274 -- Used signing infrastructure in SessionBase.encode()/decode().
Thanks Mariusz Felisiak and Florian Apolloner for the reviews.
-rw-r--r--django/contrib/sessions/backends/base.py22
-rw-r--r--docs/internals/deprecation.txt2
-rw-r--r--docs/releases/3.1.txt4
-rw-r--r--tests/sessions_tests/tests.py12
4 files changed, 37 insertions, 3 deletions
diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
index 453f533e90..b5453160a5 100644
--- a/django/contrib/sessions/backends/base.py
+++ b/django/contrib/sessions/backends/base.py
@@ -6,6 +6,7 @@ from datetime import datetime, timedelta
from django.conf import settings
from django.contrib.sessions.exceptions import SuspiciousSession
+from django.core import signing
from django.core.exceptions import SuspiciousOperation
from django.utils import timezone
from django.utils.crypto import (
@@ -71,6 +72,10 @@ class SessionBase:
del self._session[key]
self.modified = True
+ @property
+ def key_salt(self):
+ return 'django.contrib.sessions.' + self.__class__.__qualname__
+
def get(self, key, default=None):
return self._session.get(key, default)
@@ -97,16 +102,27 @@ class SessionBase:
del self[self.TEST_COOKIE_NAME]
def _hash(self, value):
+ # RemovedInDjango40Warning: pre-Django 3.1 format will be invalid.
key_salt = "django.contrib.sessions" + self.__class__.__name__
return salted_hmac(key_salt, value).hexdigest()
def encode(self, session_dict):
"Return the given session dictionary serialized and encoded as a string."
- serialized = self.serializer().dumps(session_dict)
- hash = self._hash(serialized)
- return base64.b64encode(hash.encode() + b":" + serialized).decode('ascii')
+ return signing.dumps(
+ session_dict, salt=self.key_salt, serializer=self.serializer,
+ compress=True,
+ )
def decode(self, session_data):
+ try:
+ return signing.loads(session_data, salt=self.key_salt, serializer=self.serializer)
+ # RemovedInDjango40Warning: when the deprecation ends, handle here
+ # exceptions similar to what _legacy_decode() does now.
+ except Exception:
+ return self._legacy_decode(session_data)
+
+ def _legacy_decode(self, session_data):
+ # RemovedInDjango40Warning: pre-Django 3.1 format will be invalid.
encoded_data = base64.b64decode(session_data.encode('ascii'))
try:
# could produce ValueError if there is no ':'
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 2d7a72ae2f..3774afa59e 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -52,6 +52,8 @@ details on these changes.
* Support for the pre-Django 3.1 password reset tokens in the admin site (that
use the SHA-1 hashing algorithm) will be removed.
+* Support for the pre-Django 3.1 encoding format of sessions will be removed.
+
* The ``get_request`` argument for
``django.utils.deprecation.MiddlewareMixin.__init__()`` will be required and
won't accept ``None``.
diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt
index d4ab35a310..669f2ca01e 100644
--- a/docs/releases/3.1.txt
+++ b/docs/releases/3.1.txt
@@ -539,6 +539,10 @@ Miscellaneous
from the format generated by older versions of Django. Support for the old
format remains until Django 4.0.
+* The encoding format of sessions is different from the format generated by
+ older versions of Django. Support for the old format remains until Django
+ 4.0.
+
.. _removed-features-3.1:
Features removed in 3.1
diff --git a/tests/sessions_tests/tests.py b/tests/sessions_tests/tests.py
index fa675fe63d..6c6d7dd3f2 100644
--- a/tests/sessions_tests/tests.py
+++ b/tests/sessions_tests/tests.py
@@ -311,6 +311,18 @@ class SessionTestsMixin:
encoded = self.session.encode(data)
self.assertEqual(self.session.decode(encoded), data)
+ @override_settings(SECRET_KEY='django_tests_secret_key')
+ def test_decode_legacy(self):
+ # RemovedInDjango40Warning: pre-Django 3.1 sessions will be invalid.
+ legacy_encoded = (
+ 'OWUzNTNmNWQxNTBjOWExZmM4MmQ3NzNhMDRmMjU4NmYwNDUyNGI2NDp7ImEgdGVzd'
+ 'CBrZXkiOiJhIHRlc3QgdmFsdWUifQ=='
+ )
+ self.assertEqual(
+ self.session.decode(legacy_encoded),
+ {'a test key': 'a test value'},
+ )
+
def test_decode_failure_logged_to_security(self):
bad_encode = base64.b64encode(b'flaskdj:alkdjf').decode('ascii')
with self.assertLogs('django.security.SuspiciousSession', 'WARNING') as cm: