Commit 596564e8 authored by Tim Graham's avatar Tim Graham
Browse files

[1.8.x] Fixed #24161 -- Stored the user primary key as a serialized value in the session.

This allows using a UUIDField primary key along with the JSON session
serializer.

Thanks to Trac alias jamesbeith for the report and Simon Charette
for the initial patch.

Backport of 0f7f5bc9 from master
parent 1904022f
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -53,6 +53,12 @@ def _clean_credentials(credentials):
    return credentials


def _get_user_session_key(request):
    # This value in the session is always serialized to a string, so we need
    # to convert it back to Python whenever we access it.
    return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY])


def authenticate(**credentials):
    """
    If the given credentials are valid, return a User object.
@@ -93,7 +99,7 @@ def login(request, user):
        session_auth_hash = user.get_session_auth_hash()

    if SESSION_KEY in request.session:
        if request.session[SESSION_KEY] != user.pk or (
        if _get_user_session_key(request) != user.pk or (
                session_auth_hash and
                request.session.get(HASH_SESSION_KEY) != session_auth_hash):
            # To avoid reusing another user's session, create a new, empty
@@ -102,7 +108,7 @@ def login(request, user):
            request.session.flush()
    else:
        request.session.cycle_key()
    request.session[SESSION_KEY] = user.pk
    request.session[SESSION_KEY] = user._meta.pk.value_to_string(user)
    request.session[BACKEND_SESSION_KEY] = user.backend
    request.session[HASH_SESSION_KEY] = session_auth_hash
    if hasattr(request, 'user'):
@@ -158,7 +164,7 @@ def get_user(request):
    from .models import AnonymousUser
    user = None
    try:
        user_id = request.session[SESSION_KEY]
        user_id = _get_user_session_key(request)
        backend_path = request.session[BACKEND_SESSION_KEY]
    except KeyError:
        pass
+2 −1
Original line number Diff line number Diff line
@@ -5,9 +5,10 @@ from .invalid_models import (
    CustomUserBadRequiredFields,
)
from .with_foreign_key import CustomUserWithFK, Email
from .uuid_pk import UUIDUser

__all__ = (
    'CustomPermissionsUser', 'CustomUserNonUniqueUsername',
    'CustomUserNonListRequiredFields', 'CustomUserBadRequiredFields',
    'CustomUserWithFK', 'Email', 'IsActiveTestUser1',
    'CustomUserWithFK', 'Email', 'IsActiveTestUser1', 'UUIDUser',
)
+13 −0
Original line number Diff line number Diff line
import uuid

from django.contrib.auth.models import AbstractUser
from django.contrib.auth.tests.custom_user import RemoveGroupsAndPermissions
from django.db import models

with RemoveGroupsAndPermissions():
    class UUIDUser(AbstractUser):
        """A user with a UUID as primary key"""
        id = models.UUIDField(default=uuid.uuid4, primary_key=True)

        class Meta:
            app_label = 'auth'
+16 −2
Original line number Diff line number Diff line
@@ -3,7 +3,9 @@ from __future__ import unicode_literals
from datetime import date

from django.conf import settings
from django.contrib.auth import BACKEND_SESSION_KEY, authenticate, get_user
from django.contrib.auth import (
    BACKEND_SESSION_KEY, SESSION_KEY, authenticate, get_user,
)
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.hashers import MD5PasswordHasher
from django.contrib.auth.models import AnonymousUser, Group, Permission, User
@@ -13,7 +15,7 @@ from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.http import HttpRequest
from django.test import TestCase, modify_settings, override_settings

from .models import CustomPermissionsUser
from .models import CustomPermissionsUser, UUIDUser


class CountingMD5PasswordHasher(MD5PasswordHasher):
@@ -287,6 +289,18 @@ class CustomUserModelBackendAuthenticateTest(TestCase):
        self.assertEqual(test_user, authenticated_user)


@override_settings(AUTH_USER_MODEL='auth.UUIDUser')
class UUIDUserTests(TestCase):

    def test_login(self):
        """
        A custom user with a UUID primary key should be able to login.
        """
        user = UUIDUser.objects.create_user(username='uuid', password='test')
        self.assertTrue(self.client.login(username='uuid', password='test'))
        self.assertEqual(UUIDUser.objects.get(pk=self.client.session[SESSION_KEY]), user)


class TestObj(object):
    pass