diff --git a/swh/auth/keycloak.py b/swh/auth/keycloak.py --- a/swh/auth/keycloak.py +++ b/swh/auth/keycloak.py @@ -3,6 +3,7 @@ # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information +import json from typing import Any, Dict, Optional from urllib.parse import urlencode @@ -210,3 +211,15 @@ config = dict(load_from_envvar()).get("keycloak", {}) config.update({k: v for k, v in kwargs.items() if v is not None}) return cls.from_config(keycloak=config) + + +def keycloak_error_message(keycloak_error: KeycloakError) -> str: + """Transform a keycloak exception into an error message. + + """ + msg_dict = json.loads(keycloak_error.error_message.decode()) + error_msg = msg_dict["error"] + error_desc = msg_dict.get("error_description") + if error_desc: + error_msg = f"{error_msg}: {error_desc}" + return error_msg diff --git a/swh/auth/tests/test_keycloak.py b/swh/auth/tests/test_keycloak.py --- a/swh/auth/tests/test_keycloak.py +++ b/swh/auth/tests/test_keycloak.py @@ -4,6 +4,7 @@ # See top-level LICENSE file for more information from copy import copy +import json import os from urllib.parse import parse_qs, urlparse @@ -11,7 +12,7 @@ import pytest import yaml -from swh.auth.keycloak import KeycloakOpenIDConnect +from swh.auth.keycloak import KeycloakOpenIDConnect, keycloak_error_message from swh.auth.tests.sample_data import CLIENT_ID, DECODED_TOKEN, OIDC_PROFILE, USER_INFO from swh.core.config import read @@ -152,3 +153,23 @@ assert client.server_url == auth_config["keycloak"]["server_url"] assert client.realm_name == auth_config["keycloak"]["realm_name"] assert client.client_id == "foobar" + + +@pytest.mark.parametrize( + "error_dict, expected_result", + [ + ({"error": "unknown_error"}, "unknown_error"), + ( + {"error": "invalid_grant", "error_description": "Invalid credentials"}, + "invalid_grant: Invalid credentials", + ), + ], +) +def test_auth_keycloak_error_message(error_dict, expected_result): + """Conversion from KeycloakError to error message should work with detail or not""" + error_message = json.dumps(error_dict).encode() + exception = KeycloakError(error_message=error_message, response_code=401) + + actual_result = keycloak_error_message(exception) + + assert actual_result == expected_result