diff --git a/api/gdpr/views.py b/api/gdpr/views.py index 9d25b37e5..590bb7182 100644 --- a/api/gdpr/views.py +++ b/api/gdpr/views.py @@ -35,16 +35,15 @@ def has_permission(self, request: Request, view: TilavarauspalveluGDPRAPIView) - # Ensure request is made with by a strongly authenticated user, # following best practices set by the City of Helsinki. loa = request.auth.data.get("loa", "").lower() - required_loa = ["substantial", "high"] - has_correct_loa = loa in required_loa + allowed_loa = ["substantial", "high"] + has_correct_loa = loa in allowed_loa details = { "request_method": request_method, - "request_api_scopes": list(request.auth._authorized_api_scopes), # noqa: SLF001 - "request_loa": loa, - "allowed_loa": required_loa, + "allowed_loa": allowed_loa, "required_query_scope": settings.GDPR_API_QUERY_SCOPE, "required_delete_scope": settings.GDPR_API_DELETE_SCOPE, + "auth_claims": request.auth.data, } if request.method == "GET": diff --git a/tests/test_gdpr_api/helpers.py b/tests/test_gdpr_api/helpers.py index 6a1ffa06c..3f3b31d6e 100644 --- a/tests/test_gdpr_api/helpers.py +++ b/tests/test_gdpr_api/helpers.py @@ -29,7 +29,6 @@ def patch_oidc_config(): def get_gdpr_auth_header(user: User, *, scopes: list[str], loa: Literal["substantial", "high", "low"] = "high") -> str: audience = api_token_auth_settings.AUDIENCE issuer = api_token_auth_settings.ISSUER - auth_field = api_token_auth_settings.API_AUTHORIZATION_FIELD now = datetime.datetime.now(tz=get_default_timezone()) expire = now + datetime.timedelta(days=14) @@ -41,7 +40,7 @@ def get_gdpr_auth_header(user: User, *, scopes: list[str], loa: Literal["substan "iat": int(now.timestamp()), "exp": int(expire.timestamp()), "loa": loa, - auth_field: scopes, + "authorization": {"permissions": [{"scopes": scopes}]}, } encoded_jwt = jwt.encode(jwt_data, key=RSA.private_key_pem, algorithm=RSA.jose_algorithm) return f"{api_token_auth_settings.AUTH_SCHEME} {encoded_jwt}" diff --git a/tests/test_gdpr_api/test_gdpr_api.py b/tests/test_gdpr_api/test_gdpr_api.py index 4079127e9..129bc0405 100644 --- a/tests/test_gdpr_api/test_gdpr_api.py +++ b/tests/test_gdpr_api/test_gdpr_api.py @@ -6,6 +6,7 @@ from dateutil.relativedelta import relativedelta from django.urls import reverse from django.utils import timezone +from freezegun import freeze_time from rest_framework.exceptions import ErrorDetail from merchants.enums import OrderStatus @@ -439,6 +440,7 @@ def test_query_user_data__not_authenticated(api_client, settings): @patch_method(SentryLogger.log_message) +@freeze_time("2024-01-01T00:00:00") def test_query_user_data__wrong_scope(api_client, settings): user = UserFactory.create() @@ -458,16 +460,24 @@ def test_query_user_data__wrong_scope(api_client, settings): assert SentryLogger.log_message.call_args.kwargs == { "details": { "request_method": "GET", - "request_api_scopes": ["invalid"], - "request_loa": "high", "allowed_loa": ["substantial", "high"], "required_query_scope": "gdprquery", "required_delete_scope": "gdprdelete", + "auth_claims": { + "aud": "TUNNISTAMO_AUDIENCE", + "authorization": {"permissions": [{"scopes": ["invalid"]}]}, + "exp": 1705276800, + "iat": 1704067200, + "iss": "TUNNISTAMO_ISSUER", + "loa": "high", + "sub": str(user.uuid), + }, } } @patch_method(SentryLogger.log_message) +@freeze_time("2024-01-01T00:00:00") def test_query_user_data__insufficient_loa(api_client, settings): user = UserFactory.create(username="foo") @@ -489,11 +499,18 @@ def test_query_user_data__insufficient_loa(api_client, settings): assert SentryLogger.log_message.call_args.kwargs == { "details": { "request_method": "GET", - "request_api_scopes": ["gdprquery"], - "request_loa": "low", "allowed_loa": ["substantial", "high"], "required_query_scope": "gdprquery", "required_delete_scope": "gdprdelete", + "auth_claims": { + "aud": "TUNNISTAMO_AUDIENCE", + "authorization": {"permissions": [{"scopes": ["gdprquery"]}]}, + "exp": 1705276800, + "iat": 1704067200, + "iss": "TUNNISTAMO_ISSUER", + "loa": "low", + "sub": str(user.uuid), + }, } } @@ -735,6 +752,7 @@ def test_delete_user_data__not_authenticated(api_client, settings): @patch_method(SentryLogger.log_message) +@freeze_time("2024-01-01T00:00:00") def test_delete_user_data__wrong_scope(api_client, settings): user = UserFactory.create(username="foo") @@ -756,16 +774,24 @@ def test_delete_user_data__wrong_scope(api_client, settings): assert SentryLogger.log_message.call_args.kwargs == { "details": { "request_method": "DELETE", - "request_api_scopes": ["invalid"], - "request_loa": "high", "allowed_loa": ["substantial", "high"], "required_query_scope": "gdprquery", "required_delete_scope": "gdprdelete", + "auth_claims": { + "aud": "TUNNISTAMO_AUDIENCE", + "authorization": {"permissions": [{"scopes": ["invalid"]}]}, + "exp": 1705276800, + "iat": 1704067200, + "iss": "TUNNISTAMO_ISSUER", + "loa": "high", + "sub": str(user.uuid), + }, } } @patch_method(SentryLogger.log_message) +@freeze_time("2024-01-01T00:00:00") def test_delete_user_data__insufficient_loa(api_client, settings): user = UserFactory.create(username="foo") @@ -787,11 +813,18 @@ def test_delete_user_data__insufficient_loa(api_client, settings): assert SentryLogger.log_message.call_args.kwargs == { "details": { "request_method": "DELETE", - "request_api_scopes": ["gdprdelete"], - "request_loa": "low", "allowed_loa": ["substantial", "high"], "required_query_scope": "gdprquery", "required_delete_scope": "gdprdelete", + "auth_claims": { + "aud": "TUNNISTAMO_AUDIENCE", + "authorization": {"permissions": [{"scopes": ["gdprdelete"]}]}, + "exp": 1705276800, + "iat": 1704067200, + "iss": "TUNNISTAMO_ISSUER", + "loa": "low", + "sub": str(user.uuid), + }, } } diff --git a/tilavarauspalvelu/settings.py b/tilavarauspalvelu/settings.py index 67441b4aa..2862b1e8d 100644 --- a/tilavarauspalvelu/settings.py +++ b/tilavarauspalvelu/settings.py @@ -344,6 +344,7 @@ def OIDC_AUTH(cls): def OIDC_API_TOKEN_AUTH(cls): # See 'helusers/settings.py' return { + "API_AUTHORIZATION_FIELD": "authorization.permissions.scopes", "AUDIENCE": cls.GDPR_API_AUDIENCE, "ISSUER": cls.GDPR_API_ISSUER, }