diff --git a/swh/auth/django/models.py b/swh/auth/django/models.py --- a/swh/auth/django/models.py +++ b/swh/auth/django/models.py @@ -4,7 +4,7 @@ # See top-level LICENSE file for more information from datetime import datetime -from typing import Optional, Set +from typing import Any, Dict, Optional, Set from django.contrib.auth.models import User @@ -24,9 +24,11 @@ # OIDC tokens and session related data, only relevant when a user # authenticates from a web browser access_token: Optional[str] = None + expires_in: Optional[int] = None expires_at: Optional[datetime] = None id_token: Optional[str] = None refresh_token: Optional[str] = None + refresh_expires_in: Optional[int] = None refresh_expires_at: Optional[datetime] = None scope: Optional[str] = None session_state: Optional[str] = None @@ -84,3 +86,22 @@ return True return any(perm.startswith(app_label) for perm in self.permissions) + + def oidc_profile(self) -> Dict[str, Any]: + """ + Returns OpenID Connect profile associated to the user as a dictionary. + """ + return { + k: getattr(self, k) + for k in ( + "access_token", + "expires_in", + "expires_at", + "id_token", + "refresh_token", + "refresh_expires_in", + "refresh_expires_at", + "scope", + "session_state", + ) + } diff --git a/swh/auth/tests/django/test_utils.py b/swh/auth/tests/django/test_utils.py --- a/swh/auth/tests/django/test_utils.py +++ b/swh/auth/tests/django/test_utils.py @@ -23,18 +23,44 @@ ) +def _check_user(user, is_staff=False, permissions=set()): + assert user.id > 0 + assert user.username == DECODED_TOKEN["preferred_username"] + assert user.password == "" + assert user.first_name == DECODED_TOKEN["given_name"] + assert user.last_name == DECODED_TOKEN["family_name"] + assert user.email == DECODED_TOKEN["email"] + assert user.is_staff == is_staff + assert user.permissions == permissions + assert user.sub == DECODED_TOKEN["sub"] + + date_now = datetime.now() + if user.expires_at is not None: + assert isinstance(user.expires_at, datetime) + assert date_now <= user.expires_at + if user.refresh_expires_at is not None: + assert isinstance(user.refresh_expires_at, datetime) + assert date_now <= user.refresh_expires_at + + assert user.oidc_profile() == { + k: getattr(user, k) + for k in ( + "access_token", + "expires_in", + "expires_at", + "id_token", + "refresh_token", + "refresh_expires_in", + "refresh_expires_at", + "scope", + "session_state", + ) + } + + def test_oidc_user_from_decoded_token(): user = oidc_user_from_decoded_token(DECODED_TOKEN) - - assert user.id == 338521271020811424925120118444075479552 - assert user.username == "johndoe" - assert user.password == "" - assert user.first_name == "John" - assert user.last_name == "Doe" - assert user.email == "john.doe@example.com" - assert user.is_staff is False - assert user.permissions == set() - assert user.sub == "feacd344-b468-4a65-a236-14f61e6b7200" + _check_user(user) def test_oidc_user_from_decoded_token2(): @@ -44,15 +70,7 @@ user = oidc_user_from_decoded_token(decoded_token, client_id=CLIENT_ID) - assert user.id == 338521271020811424925120118444075479552 - assert user.username == "johndoe" - assert user.password == "" - assert user.first_name == "John" - assert user.last_name == "Doe" - assert user.email == "john.doe@example.com" - assert user.is_staff is True - assert user.permissions == {"read-api"} - assert user.sub == "feacd344-b468-4a65-a236-14f61e6b7200" + _check_user(user, is_staff=True, permissions={"read-api"}) @pytest.mark.parametrize( @@ -70,34 +88,13 @@ user = oidc_user_from_decoded_token(decoded_token, client_id=CLIENT_ID) - assert user.id == 338521271020811424925120118444075479552 - assert user.password == "" - assert user.is_staff is False - assert user.permissions == set() - assert user.sub == "feacd344-b468-4a65-a236-14f61e6b7200" # Ensure the missing field is mapped to an empty value assert getattr(user, mapped_key) == "" def test_oidc_user_from_profile(keycloak_mock): - date_now = datetime.now() - user = oidc_user_from_profile(keycloak_mock, OIDC_PROFILE) - - assert user.id == 338521271020811424925120118444075479552 - assert user.username == "johndoe" - assert user.password == "" - assert user.first_name == "John" - assert user.last_name == "Doe" - assert user.email == "john.doe@example.com" - assert user.is_staff is False - assert user.permissions == set() - assert user.sub == "feacd344-b468-4a65-a236-14f61e6b7200" - - assert isinstance(user.expires_at, datetime) - assert date_now <= user.expires_at - assert isinstance(user.refresh_expires_at, datetime) - assert date_now <= user.refresh_expires_at + _check_user(user) def test_keycloak_oidc_client_missing_django_settings():