testing.py 3.18 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
"""
Test overrides to support Safe Cookies with Test Clients.
"""

from django.test.client import Client


def safe_cookie_test_session_patch():
    """
    Override the Test Client's methods in order to support Safe Cookies.
    If there's a better way to patch this, we should do so.
    """
    if getattr(safe_cookie_test_session_patch, 'has_run', False):
        return

    def using_safe_cookie_data(settings):
        """
        Returns whether or not Safe Cookies is actually being
        used, by checking the middleware settings.
        """
        return (
            'openedx.core.djangoapps.safe_sessions.middleware.SafeSessionMiddleware' in settings.MIDDLEWARE_CLASSES
        )

    ## session_id --> safe_cookie_data ##

    # Override Client.login method to update cookies with safe
    # cookies.
    patched_client_login = Client.login

    def login_with_safe_session(self, **credentials):
        """
        Call the original Client.login method, but update the
        session cookie with a freshly computed safe_cookie_data
        before returning.
        """
        from django.conf import settings
        from django.contrib.auth import SESSION_KEY
        from .middleware import SafeSessionMiddleware

        if not patched_client_login(self, **credentials):
            return False
        if using_safe_cookie_data(settings):
            SafeSessionMiddleware.update_with_safe_session_cookie(self.cookies, self.session[SESSION_KEY])
        return True
    Client.login = login_with_safe_session

    ## safe_cookie_data --> session_id ##

    # Override Client.session so any safe cookies are parsed before
    # use.
    def get_safe_session(self):
        """
        Here, we are duplicating the original Client._session code
        in order to allow conversion of the safe_cookie_data back
        to the raw session_id, if needed.  Since test code may
        access the session_id before it's actually converted,
        we use a try-except clause here to check both cases.
        """
        from django.apps import apps
        from django.conf import settings
62
        from importlib import import_module
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
        from .middleware import SafeCookieData, SafeCookieError, SafeSessionMiddleware

        if apps.is_installed('django.contrib.sessions'):
            engine = import_module(settings.SESSION_ENGINE)
            cookie = self.cookies.get(settings.SESSION_COOKIE_NAME, None)
            if cookie:
                session_id = cookie.value
                if using_safe_cookie_data(settings):
                    try:
                        session_id = SafeCookieData.parse(session_id).session_id
                    except SafeCookieError:
                        pass  # The safe cookie hasn't yet been created.
                return engine.SessionStore(session_id)
            else:
                session = engine.SessionStore()
                session.save()
                self.cookies[settings.SESSION_COOKIE_NAME] = session.session_key
                SafeSessionMiddleware.update_with_safe_session_cookie(self.cookies, user_id=None)
                return session
        return {}
    Client.session = property(get_safe_session)

    safe_cookie_test_session_patch.has_run = True