Commit 3389c5ea authored by Tore Lundqvist's avatar Tore Lundqvist Committed by Tim Graham
Browse files

Fixed #21608 -- Prevented logged out sessions being resurrected by concurrent requests.

Thanks Simon Charette for the review.
parent 3938b3cc
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -720,6 +720,7 @@ answer newbie questions, and generally made Django that much better:
    Tom Insam
    Tommy Beadle <tbeadle@gmail.com>
    Tom Tobin
    Tore Lundqvist <tore.lundqvist@gmail.com>
    torne-django@wolfpuppy.org.uk
    Travis Cline <travis.cline@gmail.com>
    Travis Pinney
+11 −2
Original line number Diff line number Diff line
@@ -28,6 +28,13 @@ class CreateError(Exception):
    pass


class UpdateError(Exception):
    """
    Occurs if Django tries to update a session that was deleted.
    """
    pass


class SessionBase(object):
    """
    Base class for all Session classes.
@@ -301,6 +308,7 @@ class SessionBase(object):
        key = self.session_key
        self.create()
        self._session_cache = data
        if key:
            self.delete(key)

    # Methods that child classes must implement.
@@ -323,7 +331,8 @@ class SessionBase(object):
        """
        Saves the session data. If 'must_create' is True, a new session object
        is created (otherwise a CreateError exception is raised). Otherwise,
        save() can update an existing object with the same key.
        save() only updates an existing object and does not create one
        (an UpdateError is raised).
        """
        raise NotImplementedError('subclasses of SessionBase must provide a save() method')

+6 −2
Original line number Diff line number Diff line
from django.conf import settings
from django.contrib.sessions.backends.base import CreateError, SessionBase
from django.contrib.sessions.backends.base import (
    CreateError, SessionBase, UpdateError,
)
from django.core.cache import caches
from django.utils.six.moves import range

@@ -55,8 +57,10 @@ class SessionStore(SessionBase):
            return self.create()
        if must_create:
            func = self._cache.add
        else:
        elif self._cache.get(self.session_key) is not None:
            func = self._cache.set
        else:
            raise UpdateError
        result = func(self.cache_key,
                      self._get_session(no_load=must_create),
                      self.get_expiry_age())
+9 −3
Original line number Diff line number Diff line
import logging

from django.contrib.sessions.backends.base import CreateError, SessionBase
from django.contrib.sessions.backends.base import (
    CreateError, SessionBase, UpdateError,
)
from django.core.exceptions import SuspiciousOperation
from django.db import IntegrityError, router, transaction
from django.db import DatabaseError, IntegrityError, router, transaction
from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.functional import cached_property
@@ -83,11 +85,15 @@ class SessionStore(SessionBase):
        using = router.db_for_write(self.model, instance=obj)
        try:
            with transaction.atomic(using=using):
                obj.save(force_insert=must_create, using=using)
                obj.save(force_insert=must_create, force_update=not must_create, using=using)
        except IntegrityError:
            if must_create:
                raise CreateError
            raise
        except DatabaseError:
            if not must_create:
                raise UpdateError
            raise

    def delete(self, session_key=None):
        if session_key is None:
+5 −3
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ import tempfile

from django.conf import settings
from django.contrib.sessions.backends.base import (
    VALID_KEY_CHARS, CreateError, SessionBase,
    VALID_KEY_CHARS, CreateError, SessionBase, UpdateError,
)
from django.contrib.sessions.exceptions import InvalidSessionKey
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
@@ -129,15 +129,17 @@ class SessionStore(SessionBase):
        try:
            # Make sure the file exists.  If it does not already exist, an
            # empty placeholder file is created.
            flags = os.O_WRONLY | os.O_CREAT | getattr(os, 'O_BINARY', 0)
            flags = os.O_WRONLY | getattr(os, 'O_BINARY', 0)
            if must_create:
                flags |= os.O_EXCL
                flags |= os.O_EXCL | os.O_CREAT
            fd = os.open(session_file_name, flags)
            os.close(fd)

        except OSError as e:
            if must_create and e.errno == errno.EEXIST:
                raise CreateError
            if not must_create and e.errno == errno.ENOENT:
                raise UpdateError
            raise

        # Write the session file without interfering with other threads
Loading