fix: language cookie "samesite" attribute

The language cookie "samesite" attribute was always set to "None", even in
non-secure environments, such as the devstack. This was causing client-side
warnings in non-https environments, and the language cookie was not properly
set.
This commit is contained in:
Régis Behmo
2021-11-25 23:35:21 +01:00
parent b401ecb3e7
commit 53b8a80668
5 changed files with 48 additions and 37 deletions

View File

@@ -16,7 +16,7 @@ from django.utils.deprecation import MiddlewareMixin
from openedx.core.djangoapps.dark_lang import DARK_LANGUAGE_KEY
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
from openedx.core.djangoapps.lang_pref import COOKIE_DURATION
from openedx.core.djangoapps.lang_pref.helpers import set_language_cookie
from openedx.core.djangoapps.site_configuration.helpers import get_value
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
@@ -110,13 +110,7 @@ class DarkLangMiddleware(MiddlewareMixin):
language = get_value('LANGUAGE_CODE', None)
if language:
request.session[LANGUAGE_SESSION_KEY] = language
response.set_cookie(
settings.LANGUAGE_COOKIE_NAME,
value=language,
domain=settings.SHARED_COOKIE_DOMAIN,
max_age=COOKIE_DURATION,
secure=request.is_secure()
)
set_language_cookie(request, response, language)
def _fuzzy_match(self, lang_code):
"""Returns a fuzzy match for lang_code"""
@@ -174,10 +168,4 @@ class DarkLangMiddleware(MiddlewareMixin):
# Set the session key to the requested preview lang
request.session[LANGUAGE_SESSION_KEY] = preview_lang
response.set_cookie(
settings.LANGUAGE_COOKIE_NAME,
value=preview_lang,
domain=settings.SHARED_COOKIE_DOMAIN,
max_age=COOKIE_DURATION,
secure=request.is_secure()
)
set_language_cookie(request, response, preview_lang)

View File

@@ -0,0 +1,36 @@
"""
Language preference cookie helper functions
"""
from django.conf import settings
from openedx.core.djangoapps.lang_pref import COOKIE_DURATION
def get_language_cookie(request, default=None):
"""
Return the language cookie stored in the request object.
"""
return request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME, default)
def set_language_cookie(request, response, value):
"""
Set the language cookie in the response object.
"""
response.set_cookie(
settings.LANGUAGE_COOKIE_NAME,
value=value,
domain=settings.SHARED_COOKIE_DOMAIN,
max_age=COOKIE_DURATION,
secure=request.is_secure(),
samesite="None" if request.is_secure() else "Lax",
)
def unset_language_cookie(response):
"""
Remove the language cookie from the response object.
"""
response.delete_cookie(
settings.LANGUAGE_COOKIE_NAME, domain=settings.SHARED_COOKIE_DOMAIN
)

View File

@@ -3,14 +3,14 @@ Middleware for Language Preferences
"""
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
from django.utils.translation import LANGUAGE_SESSION_KEY
from django.utils.translation.trans_real import parse_accept_lang_header
from openedx.core.djangoapps.dark_lang import DARK_LANGUAGE_KEY
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
from openedx.core.djangoapps.lang_pref import COOKIE_DURATION, LANGUAGE_HEADER, LANGUAGE_KEY
from openedx.core.djangoapps.lang_pref import LANGUAGE_HEADER, LANGUAGE_KEY
from openedx.core.djangoapps.lang_pref import helpers as lang_pref_helpers
from openedx.core.djangoapps.user_api.errors import UserAPIInternalError, UserAPIRequestError
from openedx.core.djangoapps.user_api.preferences.api import get_user_preference, set_user_preference
from openedx.core.lib.mobile_utils import is_request_from_mobile_app
@@ -29,7 +29,7 @@ class LanguagePreferenceMiddleware(MiddlewareMixin):
If a user's UserPreference contains a language preference, use the user's preference.
Save the current language preference cookie as the user's preferred language.
"""
cookie_lang = request.COOKIES.get(settings.LANGUAGE_COOKIE_NAME, None)
cookie_lang = lang_pref_helpers.get_language_cookie(request)
if cookie_lang:
if request.user.is_authenticated:
# DarkLangMiddleware will take care of this so don't change anything
@@ -82,17 +82,8 @@ class LanguagePreferenceMiddleware(MiddlewareMixin):
# If set, set the user_pref in the LANGUAGE_COOKIE_NAME
if user_pref and not is_request_from_mobile_app(request):
response.set_cookie(
settings.LANGUAGE_COOKIE_NAME,
value=user_pref,
domain=settings.SHARED_COOKIE_DOMAIN,
max_age=COOKIE_DURATION,
secure=request.is_secure()
)
lang_pref_helpers.set_language_cookie(request, response, user_pref)
else:
response.delete_cookie(
settings.LANGUAGE_COOKIE_NAME,
domain=settings.SHARED_COOKIE_DOMAIN
)
lang_pref_helpers.unset_language_cookie(response)
return response

View File

@@ -75,6 +75,7 @@ class TestUserPreferenceMiddleware(CacheIsolationTestCase):
domain=settings.SESSION_COOKIE_DOMAIN,
max_age=COOKIE_DURATION,
secure=self.request.is_secure(),
samesite="Lax"
)
else:
response.delete_cookie.assert_called_with(

View File

@@ -10,7 +10,8 @@ from django.http import HttpResponse
from django.utils.translation import LANGUAGE_SESSION_KEY
from django.views.decorators.csrf import ensure_csrf_cookie
from openedx.core.djangoapps.lang_pref import COOKIE_DURATION, LANGUAGE_KEY
from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY
from openedx.core.djangoapps.lang_pref.helpers import set_language_cookie
@ensure_csrf_cookie
@@ -24,11 +25,5 @@ def update_session_language(request):
language = data.get(LANGUAGE_KEY, settings.LANGUAGE_CODE)
if request.session.get(LANGUAGE_SESSION_KEY, None) != language:
request.session[LANGUAGE_SESSION_KEY] = str(language)
response.set_cookie(
settings.LANGUAGE_COOKIE_NAME,
language,
domain=settings.SHARED_COOKIE_DOMAIN,
max_age=COOKIE_DURATION,
secure=request.is_secure(),
)
set_language_cookie(request, response, language)
return response