import uuid from typing import Any import pytest from pdp.constants.constants import TenantType, UserType from pdp.fastapi.schemas.identity import Role, RolesResponse, TenantRoles from pdp.fastapi.schemas.principal import Principal @pytest.fixture() def mock_pdp_tenant_roles() -> dict[uuid.UUID, TenantRoles]: """Test fixture representing tenant roles assigned to a principal.""" return RolesResponse.model_validate( { "tenants": { "04b48f72-5b47-425f-8b49-21f1ebc3f0cd": { "tenant_type": "account", "tenant_uuid": "04b48f72-5b47-425f-8b49-21f1ebc3f0cd", "roles": [{"role": "dog_whisperer"}], } }, "cursor": {"cursor": None}, } ).tenants @pytest.mark.parametrize( "payload, expect_exception, expected", [ pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, }, False, { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "user_type": "human", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": None, "impersonated_by_identity_uuid": None, }, id="minimum needed is identity uuid with no tenant roles", ), pytest.param( {}, True, {}, id="identity uuid and pdp_tenant_roles required", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, "user_type": "dancer", }, True, {}, id="dancer is not a user type", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, "user_type": "machine", }, False, { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "user_type": "machine", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": None, "impersonated_by_identity_uuid": None, }, id="machine is a user type", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, "user_type": "machine", "impersonated_by_identity_uuid": "086f48bc-4e62-4ca4-bcd2-6518ecec11da", }, False, { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "user_type": "machine", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": None, "impersonated_by_identity_uuid": "086f48bc-4e62-4ca4-bcd2-6518ecec11da", }, id="Classic impersonated M2M JWT", ), pytest.param( { "identity_uuid": "6592faaa-b36c-11f0-930d-224337b051bc", "pdp_tenant_roles": {}, "user_type": "machine", "impersonated_by_identity_uuid": "086f48bc-4e62-4ca4-bcd2-6518ecec11da", }, True, {}, id="identity uuid can't be uuid1", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, "user_type": "machine", "impersonated_by_identity_uuid": "6592faaa-b36c-11f0-930d-224337b051bc", }, True, {}, id="impersonated_by_identity_uuid cannot be uuid1", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, "user_type": "machine", "impersonated_by_identity_uuid": "", }, True, {}, id="impersonated_by_identity_uuid cannot be empty string", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": {}, }, False, { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "user_type": "human", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": {}, "impersonated_by_identity_uuid": None, }, id="ows_permissions_tenant_roles can be empty dict", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": {}, }, False, { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "user_type": "human", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": {}, "impersonated_by_identity_uuid": None, }, id="ows_permissions_tenant_roles can be empty dict", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": { uuid.UUID("04b48f72-5b47-425f-8b49-21f1ebc3f0cd"): TenantRoles( roles=[Role(role="dog_whisperer")], tenant_uuid="04b48f72-5b47-425f-8b49-21f1ebc3f0cd", tenant_type=TenantType.TENANT_TYPE_SUBACCOUNT, ) }, "ows_permissions_tenant_roles": {}, }, False, { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "user_type": "human", "pdp_tenant_roles": { "04b48f72-5b47-425f-8b49-21f1ebc3f0cd": { "roles": [{"role": "dog_whisperer"}], "tenant_uuid": "04b48f72-5b47-425f-8b49-21f1ebc3f0cd", "tenant_type": "subaccount", } }, "ows_permissions_tenant_roles": {}, "impersonated_by_identity_uuid": None, }, id="pdp_tenant_roles is a dict of uuid key/TenantRoles values", ), pytest.param( { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": { uuid.UUID("04b48f72-5b47-425f-8b49-21f1ebc3f0cd"): TenantRoles( roles=[Role(role="dog_whisperer")], tenant_uuid="04b48f72-5b47-425f-8b49-21f1ebc3f0cd", tenant_type=TenantType.TENANT_TYPE_SUBACCOUNT, ) }, }, False, { "identity_uuid": "b1720cec-0391-498e-b294-039e9f0b3c08", "user_type": "human", "pdp_tenant_roles": {}, "ows_permissions_tenant_roles": { "04b48f72-5b47-425f-8b49-21f1ebc3f0cd": { "roles": [{"role": "dog_whisperer"}], "tenant_uuid": "04b48f72-5b47-425f-8b49-21f1ebc3f0cd", "tenant_type": "subaccount", } }, "impersonated_by_identity_uuid": None, }, id="ows_permissions_tenant_roles is be a dict of uuid key/TenantRoles values", # noqa: E501 ), ], ) def test_principal_model_validate( payload: Any, expect_exception: bool, expected: dict[str, Any], ) -> None: """Parametrized testing of Principal schema.""" if expect_exception: with pytest.raises(Exception): Principal.model_validate(payload) else: actual = Principal.model_validate(payload) assert actual == Principal(**expected) def test_principal_get_cerbos_principal( mock_pdp_tenant_roles: dict[uuid.UUID, TenantRoles], identity_uuid_as_uuid: uuid.UUID, ) -> None: """Test Principal.get_cerbos_principal.""" principal = Principal( identity_uuid=identity_uuid_as_uuid, pdp_tenant_roles=mock_pdp_tenant_roles, ) result = principal.get_cerbos_principal() assert result.id == str(identity_uuid_as_uuid) assert result.roles == {"user"} assert result.attr == { "type": "human", "tenants": { "04b48f72-5b47-425f-8b49-21f1ebc3f0cd": { "tenant_type": "account", "tenant_uuid": "04b48f72-5b47-425f-8b49-21f1ebc3f0cd", "roles": {"dog_whisperer": {"role": "dog_whisperer"}}, }, }, } def test_principal_get_cerbos_principal_adds_in_ows_permissions_tenant_roles( mock_pdp_tenant_roles: dict[uuid.UUID, TenantRoles], mock_my_adminable_tenant_roles: dict[uuid.UUID, TenantRoles], identity_uuid_as_uuid: uuid.UUID, ) -> None: """Test Principal.get_cerbos_principal adds in new tenants from ows-permissions tenant roles. """ principal = Principal( identity_uuid=identity_uuid_as_uuid, pdp_tenant_roles=mock_pdp_tenant_roles, ows_permissions_tenant_roles=mock_my_adminable_tenant_roles, ) result = principal.get_cerbos_principal() assert result.id == str(identity_uuid_as_uuid) assert result.roles == {"user"} assert result.attr == { "type": "human", "tenants": { "04b48f72-5b47-425f-8b49-21f1ebc3f0cd": { "tenant_type": "account", "tenant_uuid": "04b48f72-5b47-425f-8b49-21f1ebc3f0cd", "roles": {"dog_whisperer": {"role": "dog_whisperer"}}, }, "573d0372-7f2f-48a6-8deb-c9a6558f9549": { "tenant_type": "account", "tenant_uuid": "573d0372-7f2f-48a6-8deb-c9a6558f9549", "roles": { "ows_permissions_rap_admin": {"role": "ows_permissions_rap_admin"} }, }, }, } def test_principal_get_cerbos_principal_merges_in_ows_permissions_tenant_roles( mock_my_adminable_tenant_roles: dict[uuid.UUID, TenantRoles], identity_uuid_as_uuid: uuid.UUID, ) -> None: """Test Principal.get_cerbos_principal merges in roles from ows-permissions tenant roles. """ mock_pdp_tenant_roles = RolesResponse.model_validate( { "tenants": { "573d0372-7f2f-48a6-8deb-c9a6558f9549": { "tenant_type": "account", "tenant_uuid": "573d0372-7f2f-48a6-8deb-c9a6558f9549", "roles": [{"role": "dog_whisperer"}], } }, "cursor": {"cursor": None}, } ).tenants principal = Principal( identity_uuid=identity_uuid_as_uuid, pdp_tenant_roles=mock_pdp_tenant_roles, ows_permissions_tenant_roles=mock_my_adminable_tenant_roles, ) result = principal.get_cerbos_principal() assert result.id == str(identity_uuid_as_uuid) assert result.roles == {"user"} assert result.attr == { "type": "human", "tenants": { "573d0372-7f2f-48a6-8deb-c9a6558f9549": { "tenant_type": "account", "tenant_uuid": "573d0372-7f2f-48a6-8deb-c9a6558f9549", "roles": { "dog_whisperer": {"role": "dog_whisperer"}, "ows_permissions_rap_admin": {"role": "ows_permissions_rap_admin"}, }, } }, } def test_principal_get_cerbos_principal_uses_user_type( mock_pdp_tenant_roles: dict[uuid.UUID, TenantRoles], identity_uuid_as_uuid: uuid.UUID, ) -> None: """Test Principal.get_cerbos_principal uses user type.""" principal = Principal( identity_uuid=identity_uuid_as_uuid, pdp_tenant_roles=mock_pdp_tenant_roles, ows_permissions_tenant_roles=None, user_type="machine", ) result = principal.get_cerbos_principal() assert result.id == str(identity_uuid_as_uuid) assert result.roles == {"user"} assert result.attr == { "type": "machine", "tenants": { "04b48f72-5b47-425f-8b49-21f1ebc3f0cd": { "tenant_type": "account", "tenant_uuid": "04b48f72-5b47-425f-8b49-21f1ebc3f0cd", "roles": {"dog_whisperer": {"role": "dog_whisperer"}}, }, }, } def test_principal_get_cerbos_principal_uses_impersonated_by_identity_uuid( mock_pdp_tenant_roles: dict[uuid.UUID, TenantRoles], identity_uuid_as_uuid: uuid.UUID, ) -> None: """Test Principal.get_cerbos_principal uses impersonated_by_identity_uuid. """ impersonated_by_identity_uuid = uuid.uuid4() principal = Principal( identity_uuid=identity_uuid_as_uuid, pdp_tenant_roles=mock_pdp_tenant_roles, ows_permissions_tenant_roles=None, user_type=UserType.USER_TYPE_MACHINE, impersonated_by_identity_uuid=impersonated_by_identity_uuid, ) result = principal.get_cerbos_principal() assert result.id == str(identity_uuid_as_uuid) assert result.roles == {"user"} assert result.attr == { "type": "machine", "tenants": { "04b48f72-5b47-425f-8b49-21f1ebc3f0cd": { "tenant_type": "account", "tenant_uuid": "04b48f72-5b47-425f-8b49-21f1ebc3f0cd", "roles": {"dog_whisperer": {"role": "dog_whisperer"}}, }, }, "impersonated_by_identity_uuid": str(impersonated_by_identity_uuid), } def test_build_principal_disregards_null_impersonated_by_identity_uuid( mock_pdp_tenant_roles: dict[uuid.UUID, TenantRoles], identity_uuid_as_uuid: uuid.UUID, ) -> None: """Test _build_principal disregards empty impersonated_by_identity_uuid.""" principal = Principal( identity_uuid=identity_uuid_as_uuid, pdp_tenant_roles=mock_pdp_tenant_roles, ows_permissions_tenant_roles=None, impersonated_by_identity_uuid=None, ) result = principal.get_cerbos_principal() assert result.id == str(identity_uuid_as_uuid) assert result.roles == {"user"} assert result.attr == { "type": "human", "tenants": { "04b48f72-5b47-425f-8b49-21f1ebc3f0cd": { "tenant_type": "account", "tenant_uuid": "04b48f72-5b47-425f-8b49-21f1ebc3f0cd", "roles": {"dog_whisperer": {"role": "dog_whisperer"}}, }, }, }