from typing import Any from uuid import UUID from cerbos.sdk.model import Principal as CerbosPrincipal from ddtrace.trace import tracer from pydantic import UUID4, BaseModel from pdp.constants.constants import UserType from pdp.fastapi.schemas.identity import TenantRoles class Principal(BaseModel): """Object for describing principal / authenticated identity.""" identity_uuid: UUID4 user_type: UserType = UserType.USER_TYPE_HUMAN pdp_tenant_roles: dict[UUID, TenantRoles] ows_permissions_tenant_roles: dict[UUID, TenantRoles] | None = None impersonated_by_identity_uuid: UUID4 | None = None @tracer.wrap() def get_cerbos_principal(self) -> CerbosPrincipal: """Get all data to represent a principal's attributes as a CerbosPrincipal.""" tenants = self.pdp_tenant_roles cerbos_principal_tenants: dict[str, Any] = {} for tenant in tenants.values(): cerbos_principal_tenants[str(tenant.tenant_uuid)] = ( tenant.as_cerbos_principal_tenants_attribute() ) if self.ows_permissions_tenant_roles: for tenant_role in self.ows_permissions_tenant_roles.values(): tenant_uuid = str(tenant_role.tenant_uuid) if tenant_uuid in cerbos_principal_tenants: # Use the roles cerbos_principal_tenants[tenant_uuid]["roles"].update( tenant_role.as_cerbos_principal_tenants_attribute()["roles"] ) else: cerbos_principal_tenants[tenant_uuid] = ( tenant_role.as_cerbos_principal_tenants_attribute() ) attr = { "type": self.user_type.value, "tenants": cerbos_principal_tenants, } if self.impersonated_by_identity_uuid: attr["impersonated_by_identity_uuid"] = str( self.impersonated_by_identity_uuid ) return CerbosPrincipal( id=str(self.identity_uuid), roles={"user"}, attr=attr, )