diff --git a/fed_mng/auth.py b/fed_mng/auth.py index edb009d..8bf8fff 100644 --- a/fed_mng/auth.py +++ b/fed_mng/auth.py @@ -8,6 +8,7 @@ from flaat.fastapi import Flaat from flaat.requirements import AllOf, HasSubIss, IsTrue from flaat.user_infos import UserInfos +from requests.exceptions import ConnectionError, Timeout from sqlmodel import Session, select from fed_mng.config import get_settings @@ -115,9 +116,17 @@ def get_user_roles(token: str) -> list[str]: """ settings = get_settings() data = {"input": {"authorization": f"Bearer {token}"}} - resp = requests.post( - os.path.join(settings.OPA_URL, settings.ROLES_ENDPOINT), json=data - ) - if resp.status_code == status.HTTP_200_OK: - return resp.json().get("result", []) - raise resp.raise_for_status() + try: + resp = requests.post( + os.path.join(settings.OPA_URL, settings.ROLES_ENDPOINT), json=data + ) + if resp.status_code == status.HTTP_200_OK: + return resp.json().get("result", []) + elif resp.status_code == status.HTTP_400_BAD_REQUEST: + print("Bad request sent to OPA server.") + elif resp.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR: + print("OPA server internal error.") + return [] + except (Timeout, ConnectionError): + print("OPA server is not reachable.") + return [] diff --git a/tests/test_auth.py b/tests/test_auth.py index 5bac1f8..67547e3 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,7 +1,12 @@ +from unittest.mock import MagicMock, patch + +from fastapi import status from flaat import UserInfos +from pytest_cases import parametrize_with_cases from sqlmodel import Session, select from fed_mng.auth import ( + get_user_roles, is_admin, is_site_admin, is_site_tester, @@ -122,3 +127,38 @@ def test_is_not_user_group_manager() -> None: introspection_info=None, ) assert not is_user_group_manager(user_info) + + +@patch("fed_mng.auth.requests") +@parametrize_with_cases("opa_resp", has_tag="valid") +def test_opa_auth(mock_requests: MagicMock, opa_resp: list[str]) -> None: + mock_resp = MagicMock() + mock_resp.status_code = status.HTTP_200_OK + mock_resp.json.return_value = opa_resp + mock_requests.post.return_value = mock_resp + user_roles = get_user_roles("fake_token") + assert user_roles is not None + assert isinstance(user_roles, list) + assert len(user_roles) == len(opa_resp.get("result", [])) + + +@patch("fed_mng.auth.requests") +@parametrize_with_cases("status_code", has_tag="http_exc") +def test_opa_auth_http_exc(mock_requests: MagicMock, status_code: int) -> None: + mock_resp = MagicMock() + mock_resp.status_code = status_code + mock_requests.post.return_value = mock_resp + user_roles = get_user_roles("fake_token") + assert user_roles is not None + assert isinstance(user_roles, list) + assert len(user_roles) == 0 + + +@patch("fed_mng.auth.requests") +@parametrize_with_cases("err", has_tag="conn_err") +def test_opa_auth_conn_err(mock_requests: MagicMock, err) -> None: + mock_requests.post.side_effect = err() + user_roles = get_user_roles("fake_token") + assert user_roles is not None + assert isinstance(user_roles, list) + assert len(user_roles) == 0 diff --git a/tests/test_auth_cases.py b/tests/test_auth_cases.py new file mode 100644 index 0000000..3ca0840 --- /dev/null +++ b/tests/test_auth_cases.py @@ -0,0 +1,33 @@ +from fastapi import status +from pytest_cases import case +from requests.exceptions import ConnectionError, Timeout + + +class CaseRoles: + @case(tags="valid") + def case_no_roles(self) -> dict: + return {} + + @case(tags="valid") + def case_single_role(self) -> dict[str, list[str]]: + return {"result": ["role1"]} + + @case(tags="valid") + def case_multi_roles(self) -> dict[str, list[str]]: + return {"result": ["role1", "role2"]} + + @case(tags="http_exc") + def case_bad_req(self) -> int: + return status.HTTP_400_BAD_REQUEST + + @case(tags="http_exc") + def case_server_err(self) -> int: + return status.HTTP_500_INTERNAL_SERVER_ERROR + + @case(tags="conn_err") + def case_timeout(self) -> type[Timeout]: + return Timeout + + @case(tags="conn_err") + def case_conn_err(self) -> type[ConnectionError]: + return ConnectionError