mirror of
https://github.com/suitenumerique/django-lasuite
synced 2026-04-25 17:15:14 +02:00
👔(oidc) consider urls as refreshable no matter the HTTP method
Currently, only `GET` method as considered as refreshable url as it could be weird to return a redirect response for other kind of HTTP methods. On our side, we assume to be always in a XHR context so we don't want to be bothered by redirects and in case the session has expired we returned a 401 status. So we can safely ignore the request HTTP method to check if the url is refreshable.
This commit is contained in:
@@ -11,6 +11,7 @@ and this project adheres to
|
||||
### Changed
|
||||
|
||||
- 🐛(joserfc) refactor JWT handling with joserfc library updates #35
|
||||
- 👔(oidc) consider urls as refreshable no matter the HTTP method
|
||||
|
||||
## [0.0.17] - 2025-10-27
|
||||
|
||||
|
||||
@@ -12,13 +12,15 @@ import time
|
||||
from urllib.parse import quote, urlencode
|
||||
|
||||
import requests
|
||||
from django.contrib.auth import BACKEND_SESSION_KEY
|
||||
from django.http import JsonResponse
|
||||
from django.urls import reverse
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.module_loading import import_string
|
||||
from mozilla_django_oidc.middleware import SessionRefresh
|
||||
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_401_UNAUTHORIZED
|
||||
|
||||
from lasuite.oidc_login.backends import get_oidc_refresh_token, store_tokens
|
||||
from lasuite.oidc_login.backends import OIDCAuthenticationBackend, get_oidc_refresh_token, store_tokens
|
||||
|
||||
try:
|
||||
from mozilla_django_oidc.middleware import (
|
||||
@@ -83,6 +85,34 @@ class RefreshOIDCAccessToken(SessionRefresh):
|
||||
query = urlencode(auth_params, quote_via=quote)
|
||||
return f"{auth_url}?{query}"
|
||||
|
||||
def is_refreshable_url(self, request):
|
||||
"""
|
||||
Take a request and returns whether it triggers a refresh examination.
|
||||
|
||||
In the original implementation [1], the request method is checked to be
|
||||
GET. This is relevant as if the session has expired, the user will be
|
||||
redirected to a login page, that can be problematic for XHR requests.
|
||||
Like the `finish` method documentation explains, in our implementation
|
||||
we consider all requests as XHR requests, so in our case we can safely
|
||||
ignore the request method check as in case of expired token,
|
||||
a 401 status code will be always returned.
|
||||
|
||||
1. https://github.com/mozilla/mozilla-django-oidc/blob/774b140/mozilla_django_oidc/middleware.py#L96-L117
|
||||
"""
|
||||
# Do not attempt to refresh the session if the OIDC backend is not used
|
||||
backend_session = request.session.get(BACKEND_SESSION_KEY)
|
||||
is_oidc_enabled = True
|
||||
if backend_session:
|
||||
auth_backend = import_string(backend_session)
|
||||
is_oidc_enabled = issubclass(auth_backend, OIDCAuthenticationBackend)
|
||||
|
||||
return (
|
||||
request.user.is_authenticated
|
||||
and is_oidc_enabled
|
||||
and request.path not in self.exempt_urls
|
||||
and not any(pattern.match(request.path) for pattern in self.exempt_url_patterns)
|
||||
)
|
||||
|
||||
def is_expired(self, request):
|
||||
"""Check whether the access token is expired and needs to be refreshed."""
|
||||
if not self.is_refreshable_url(request):
|
||||
|
||||
@@ -113,11 +113,12 @@ def test_basic_auth_disabled(oidc_settings): # pylint: disable=unused-argument
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_successful_token_refresh(oidc_settings): # pylint: disable=unused-argument
|
||||
"""Test that the middleware successfully refreshes the token."""
|
||||
@pytest.mark.parametrize("http_method", ["get", "post", "put", "patch", "delete", "head", "options"])
|
||||
def test_successful_token_refresh(oidc_settings, http_method): # pylint: disable=unused-argument
|
||||
"""Test that the middleware successfully refreshes the token for any HTTP method."""
|
||||
user = factories.UserFactory()
|
||||
|
||||
request = RequestFactory().get("/test")
|
||||
request = getattr(RequestFactory(), http_method)("/test")
|
||||
request.user = user
|
||||
|
||||
get_response = MagicMock()
|
||||
@@ -166,10 +167,14 @@ def test_non_expired_token(oidc_settings): # pylint: disable=unused-argument
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_refresh_token_request_timeout(oidc_settings): # pylint: disable=unused-argument
|
||||
"""Test that the middleware returns a 401 response when the token refresh request times out."""
|
||||
@pytest.mark.parametrize("http_method", ["get", "post", "put", "patch", "delete", "head", "options"])
|
||||
def test_refresh_token_request_timeout(oidc_settings, http_method): # pylint: disable=unused-argument
|
||||
"""
|
||||
Test that the middleware returns a 401 response when the token
|
||||
refresh request times out for any HTTP method.
|
||||
"""
|
||||
user = factories.UserFactory()
|
||||
request = RequestFactory().get("/test")
|
||||
request = getattr(RequestFactory(), http_method)("/test")
|
||||
request.user = user
|
||||
|
||||
get_response = MagicMock()
|
||||
|
||||
Reference in New Issue
Block a user