Skip to content
Snippets Groups Projects
Commit d06924ed authored by Antoine Lambert's avatar Antoine Lambert
Browse files

django/backends: Improve error message when a bearer token expired

This replaces the Keycloak error message by a more comprehensible one
for end users.

Unfortunately, there is no way to get the bearer token validity period
apart using Keycloak Admin REST API but we clearly do not want to query
it in a django authentication backend.

Related to T3121
parent 9d9a0a33
No related branches found
Tags v0.5.1
No related merge requests found
......@@ -21,7 +21,12 @@ from swh.auth.django.utils import (
oidc_user_from_decoded_token,
oidc_user_from_profile,
)
from swh.auth.keycloak import ExpiredSignatureError, KeycloakOpenIDConnect
from swh.auth.keycloak import (
ExpiredSignatureError,
KeycloakError,
KeycloakOpenIDConnect,
keycloak_error_message,
)
def _update_cached_oidc_profile(
......@@ -194,6 +199,15 @@ class OIDCBearerTokenAuthentication(BaseAuthentication):
except UnicodeEncodeError as e:
sentry_sdk.capture_exception(e)
raise ValidationError("Invalid bearer token")
except KeycloakError as ke:
error_msg = keycloak_error_message(ke)
if error_msg == "invalid_grant: Offline user session not found":
error_msg = (
"Bearer token expired after a long period of inactivity; "
"please generate a new one."
)
sentry_sdk.capture_exception(ke)
raise AuthenticationFailed(error_msg)
except Exception as e:
sentry_sdk.capture_exception(e)
raise AuthenticationFailed(str(e))
......
......@@ -3,11 +3,22 @@
# License: GNU Affero General Public License version 3, or any later version
# See top-level LICENSE file for more information
import json
from django.contrib.auth.models import AnonymousUser, User
from django.core.cache import cache
import pytest
from swh.auth.django.models import OIDCUser
from swh.auth.django.utils import reverse
from swh.auth.keycloak import KeycloakError
@pytest.fixture
def api_client(api_client):
# ensure django cache is cleared before each test
cache.clear()
return api_client
@pytest.mark.django_db
......@@ -107,3 +118,34 @@ def test_drf_oidc_auth_invalid_or_missing_authorization_type(keycloak_oidc, api_
request = response.wsgi_request
assert isinstance(request.user, AnonymousUser)
@pytest.mark.django_db
def test_drf_oidc_bearer_token_expired_token(keycloak_oidc, api_client):
url = reverse("api-test")
oidc_profile = keycloak_oidc.login()
refresh_token = oidc_profile["refresh_token"]
api_client.credentials(HTTP_AUTHORIZATION=f"Bearer {refresh_token}")
kc_error_dict = {
"error": "invalid_grant",
"error_description": "Offline user session not found",
}
keycloak_oidc.refresh_token.side_effect = KeycloakError(
error_message=json.dumps(kc_error_dict).encode(), response_code=400
)
response = api_client.get(url)
expected_error_msg = (
"Bearer token expired after a long period of inactivity; "
"please generate a new one."
)
assert response.status_code == 403
assert expected_error_msg in json.dumps(response.data)
request = response.wsgi_request
assert isinstance(request.user, AnonymousUser)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment