diff --git a/horizon/enforcer/api.py b/horizon/enforcer/api.py index cb77cc6f..31b217bd 100644 --- a/horizon/enforcer/api.py +++ b/horizon/enforcer/api.py @@ -475,23 +475,24 @@ async def user_permissions( query: UserPermissionsQuery, x_permit_sdk_language: Optional[str] = Depends(notify_seen_sdk), ): - response = await _is_allowed(query, request, USER_PERMISSIONS_POLICY_PACKAGE) - log_query_result(query, response) - try: - raw_result = json.loads(response.body).get("result", {}) - processed_query = ( - get_v1_processed_query(raw_result) - or get_v2_processed_query(raw_result) - or {} - ) + def parse_func(result: dict) -> dict | list: + return result.get("permissions", {}) - result = parse_obj_as( - UserPermissionsResult, raw_result.get("permissions", {}) - ) - except: + response = await conditional_is_allowed( + query, + request, + policy_package=USER_PERMISSIONS_POLICY_PACKAGE, + external_data_manager_path=f"/user-permissions", + external_data_manager_params=query.get_filters(), + legacy_parse_func=parse_func, + ) + try: + result = parse_obj_as(UserPermissionsResult, response) + except Exception as e: result = parse_obj_as(UserPermissionsResult, {}) logger.warning( - "is allowed (fallback response)", reason="cannot decode opa response" + "user permissions (fallback response)", + reason="cannot decode opa response", ) return result diff --git a/horizon/enforcer/schemas.py b/horizon/enforcer/schemas.py index 04819718..de150fcb 100644 --- a/horizon/enforcer/schemas.py +++ b/horizon/enforcer/schemas.py @@ -74,6 +74,16 @@ class UserPermissionsQuery(BaseSchema): resource_types: Optional[list[str]] = None context: Optional[dict[str, Any]] = {} + def get_filters(self) -> dict: + filters = {} + if self.tenants: + filters["tenants"] = self.tenants + if self.resources: + filters["resource_instances"] = self.resources + if self.resource_types: + filters["resource_types"] = self.resource_types + return filters + class AuthorizationResult(BaseSchema): allow: bool = False diff --git a/horizon/tests/test_enforcer_api.py b/horizon/tests/test_enforcer_api.py index 6d01f7a0..d1d23df5 100644 --- a/horizon/tests/test_enforcer_api.py +++ b/horizon/tests/test_enforcer_api.py @@ -256,6 +256,38 @@ async def pdp_api_client() -> TestClient: [{"key": "default-2", "attributes": {}}, {"key": "default", "attributes": {}}], [{"key": "default-2", "attributes": {}}, {"key": "default", "attributes": {}}], ), + ( + "/user-permissions", + "/user-permissions", + UserPermissionsQuery( + user=User(key="user1"), + ), + None, + { + "user1": { + "resource": { + "key": "resource_x", + "attributes": {}, + "type": "resource1", + }, + "tenant": {"key": "default", "attributes": {}}, + "permissions": ["read:read"], + "roles": ["admin"], + } + }, + { + "user1": { + "resource": { + "key": "resource_x", + "attributes": {}, + "type": "resource1", + }, + "tenant": {"key": "default", "attributes": {}}, + "permissions": ["read:read"], + "roles": ["admin"], + } + }, + ), ] @@ -513,9 +545,14 @@ def post_endpoint(): assert response.json() == expected_response elif isinstance(expected_response, dict): for k, v in expected_response.items(): - assert ( - response.json()[k] == v - ), f"Expected {k} to be {v} but got {response.json()[k]}" + try: + assert ( + response.json()[k] == v + ), f"Expected {k} to be {v} but got {response.json()[k]}" + except KeyError: + pytest.fail( + f"response missing key {k} from expected response:\n,{response.json()}" + ) else: raise TypeError( f"Unexpected expected response type, expected one of list, dict and got {type(expected_response)}"