Commit bb56a5d9 by Calen Pennington

Merge pull request #58 from edx/dont-change-user-id-in-session

Don't allow the user id to change in a session loaded from storage.
parents 496022a4 6eace27f
...@@ -42,7 +42,7 @@ DEBUG = False ...@@ -42,7 +42,7 @@ DEBUG = False
TEMPLATE_DEBUG = False TEMPLATE_DEBUG = False
EMAIL_BACKEND = 'django_ses.SESBackend' EMAIL_BACKEND = 'django_ses.SESBackend'
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_ENGINE = 'openedx.core.djangoapps.safe_sessions.backends.cache'
# IMPORTANT: With this enabled, the server must always be behind a proxy that # IMPORTANT: With this enabled, the server must always be behind a proxy that
# strips the header HTTP_X_FORWARDED_PROTO from client requests. Otherwise, # strips the header HTTP_X_FORWARDED_PROTO from client requests. Otherwise,
......
...@@ -394,6 +394,7 @@ DEBUG = False ...@@ -394,6 +394,7 @@ DEBUG = False
TEMPLATE_DEBUG = False TEMPLATE_DEBUG = False
SESSION_COOKIE_SECURE = False SESSION_COOKIE_SECURE = False
SESSION_SAVE_EVERY_REQUEST = False SESSION_SAVE_EVERY_REQUEST = False
SESSION_ENGINE = 'openedx.core.djangoapps.safe_sessions.backends.db'
# Site info # Site info
SITE_ID = 1 SITE_ID = 1
......
...@@ -62,7 +62,7 @@ DEBUG = False ...@@ -62,7 +62,7 @@ DEBUG = False
TEMPLATE_DEBUG = False TEMPLATE_DEBUG = False
EMAIL_BACKEND = 'django_ses.SESBackend' EMAIL_BACKEND = 'django_ses.SESBackend'
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_ENGINE = 'openedx.core.djangoapps.safe_sessions.backends.cache'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage' DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
############################################################## ##############################################################
......
...@@ -73,7 +73,7 @@ def gen_all_identities(): ...@@ -73,7 +73,7 @@ def gen_all_identities():
@ddt @ddt
@override_settings(SESSION_ENGINE='django.contrib.sessions.backends.cache') @override_settings(SESSION_ENGINE='openedx.core.djangoapps.safe_sessions.backends.cache')
class ShibSPTest(SharedModuleStoreTestCase): class ShibSPTest(SharedModuleStoreTestCase):
""" """
Tests for the Shibboleth SP, which communicates via request.META Tests for the Shibboleth SP, which communicates via request.META
......
...@@ -47,7 +47,7 @@ DEBUG = False ...@@ -47,7 +47,7 @@ DEBUG = False
TEMPLATE_DEBUG = False TEMPLATE_DEBUG = False
EMAIL_BACKEND = 'django_ses.SESBackend' EMAIL_BACKEND = 'django_ses.SESBackend'
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_ENGINE = 'openedx.core.djangoapps.safe_sessions.backends.cache'
# IMPORTANT: With this enabled, the server must always be behind a proxy that # IMPORTANT: With this enabled, the server must always be behind a proxy that
# strips the header HTTP_X_FORWARDED_PROTO from client requests. Otherwise, # strips the header HTTP_X_FORWARDED_PROTO from client requests. Otherwise,
......
...@@ -802,6 +802,7 @@ TEMPLATE_DEBUG = False ...@@ -802,6 +802,7 @@ TEMPLATE_DEBUG = False
USE_TZ = True USE_TZ = True
SESSION_COOKIE_SECURE = False SESSION_COOKIE_SECURE = False
SESSION_SAVE_EVERY_REQUEST = False SESSION_SAVE_EVERY_REQUEST = False
SESSION_ENGINE = 'openedx.core.djangoapps.safe_sessions.backends.db'
# CMS base # CMS base
CMS_BASE = 'localhost:8001' CMS_BASE = 'localhost:8001'
......
...@@ -48,7 +48,7 @@ CACHES = { ...@@ -48,7 +48,7 @@ CACHES = {
} }
} }
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_ENGINE = 'openedx.core.djangoapps.safe_sessions.backends.cache'
################################ DEBUG TOOLBAR ################################# ################################ DEBUG TOOLBAR #################################
......
...@@ -61,7 +61,7 @@ DEBUG = False ...@@ -61,7 +61,7 @@ DEBUG = False
TEMPLATE_DEBUG = False TEMPLATE_DEBUG = False
EMAIL_BACKEND = 'django_ses.SESBackend' EMAIL_BACKEND = 'django_ses.SESBackend'
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_ENGINE = 'openedx.core.djangoapps.safe_sessions.backends.cache'
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage' DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
# IMPORTANT: With this enabled, the server must always be behind a proxy that # IMPORTANT: With this enabled, the server must always be behind a proxy that
......
from django.contrib.auth import SESSION_KEY
class SessionUserChanged(Exception):
def __init__(self, key, new, stored):
self.key = key
self.new = new
self.stored = stored
super(SessionUserChanged, self).__init__(
"Cannot change session {} from user {} to user {}".format(
self.key,
self.stored,
self.new,
)
)
class SafeSessionMixin(object):
"""
Mixin to prevent a session from being changed from one userid to another.
"""
def __init__(self, *args, **kwargs):
self.__stored_user = None
super(SafeSessionMixin, self).__init__(*args, **kwargs)
def __setitem__(self, key, value):
if (
key == SESSION_KEY and
self.__stored_user is not None and
value != self.__stored_user
):
raise SessionUserChanged(self.session_key, value, self.__stored_user)
return super(SafeSessionMixin, self).__setitem__(key, value)
def pop(self, key, *args):
if key == SESSION_KEY and self.__stored_user is None:
self.__stored_user = self._session.get(SESSION_KEY)
return super(SafeSessionMixin, self).pop(key, *args)
def setdefault(self, key, value):
if (
key == SESSION_KEY and
self.__stored_user is not None and
value != self.__stored_user
):
raise SessionUserChanged(self.session_key, value, self.__stored_user)
return super(SafeSessionMixin, self).setdefault(key, value)
def update(self, dict_):
if (
SESSION_KEY in dict_ and
self.__stored_user is not None and
dict_[SESSION_KEY] != self.__stored_user
):
raise SessionUserChanged(self.session_key, dict_[SESSION_KEY], self.__stored_user)
return super(SafeSessionMixin, self).save(must_create=must_create)
def clear(self):
super(SafeSessionMixin, self).clear()
self.__stored_user = None
def save(self, must_create=False):
"""
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.
"""
if (
SESSION_KEY in self._session and
self.__stored_user is not None and
self._session[SESSION_KEY] != self.__stored_user
):
raise SessionUserChanged(self.session_key, self._session[SESSION_KEY], self.__stored_user)
return super(SafeSessionMixin, self).save(must_create=must_create)
def load(self):
"""
Loads the session data and returns a dictionary.
"""
session_data = super(SafeSessionMixin, self).load()
self.__stored_user = session_data.get(SESSION_KEY)
return session_data
from django.contrib.sessions.backends.cache import SessionStore
from .base import SafeSessionMixin
class SessionStore(SafeSessionMixin, SessionStore):
pass
from django.contrib.sessions.backends.cached_db import SessionStore
from .base import SafeSessionMixin
class SessionStore(SafeSessionMixin, SessionStore):
pass
from django.contrib.sessions.backends.db import SessionStore
from .base import SafeSessionMixin
class SessionStore(SafeSessionMixin, SessionStore):
pass
from django.contrib.sessions.backends.file import SessionStore
from .base import SafeSessionMixin
class SessionStore(SafeSessionMixin, SessionStore):
pass
from django.contrib.sessions.backends.signed_cookies import SessionStore
from .base import SafeSessionMixin
class SessionStore(SafeSessionMixin, SessionStore):
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment