from unittest import mock import faker import pytest from cachelib import SimpleCache from fansifter_common.adapters.ows_account import VendorLookup from fansifter_common.adapters.ows_pdp import ( AuthEffect, CheckResourceAction, CheckResourceActionResult, CheckResourcesInput, Resource, TenantType, ) from fansifter_common.auth.account import Account, AccountAccess from fansifter_common.auth.authorization import PdpAuthorizationBackend from fansifter_common.auth.exceptions import PermissionDenied from tests.factories import TenantFactory @pytest.fixture def pdp_authorization_backend( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, cache: SimpleCache, ) -> PdpAuthorizationBackend: return PdpAuthorizationBackend( ows_pdp_client=ows_pdp_client_mock, ows_account_client=ows_account_client_mock, cache=cache, cache_timeout=0, ) def test_authorize_account( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: vendor_id = 1000 identity_id = faker.pystr() account_tenant = TenantFactory.build(tenant_id=vendor_id) account = Account(vendor_id=vendor_id, subaccount_id=0) ows_pdp_client_mock.get_allowed_tenants.return_value = [account_tenant] account_access = pdp_authorization_backend.authorize_account( identity_id, resource_type=faker.pystr(), action=faker.pystr(), account=account ) assert account_access == AccountAccess(accounts=[account]) def test_authorize_account_denied( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: identity_id = faker.pystr() account = TenantFactory.build() ows_pdp_client_mock.get_allowed_tenants.return_value = [account] with pytest.raises(PermissionDenied): pdp_authorization_backend.authorize_account( identity_id, resource_type=faker.pystr(), action=faker.pystr(), account=Account( vendor_id=faker.pyint(), subaccount_id=faker.pyint(), ), ) def test_is_allowed_account_resource( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: identity_id = faker.pystr() vendor_uuid = str(faker.uuid4(cast_to=str)) vendor_id = faker.pyint() resource = Resource( resource_id=str(faker.uuid4(cast_to=str)), resource_type="audience", attributes={ "tenant": { "tenant_uuid": vendor_uuid, "tenant_type": TenantType.ACCOUNT, } }, ) ows_pdp_client_mock.check_resources.return_value = [ CheckResourceActionResult( resource=resource, effect=AuthEffect.ALLOW, ) ] ows_account_client_mock.lookup_vendors_by_vendor_ids.return_value = [ VendorLookup(vendor_id=vendor_id, uuid=vendor_uuid) ] assert pdp_authorization_backend.is_allowed_account_resource( identity_id, account=Account(vendor_id=vendor_id, subaccount_id=0), joint_ventures=[], resource_id=resource.resource_id, resource_type="audience", action="view", ) ows_pdp_client_mock.check_resources.assert_called_once_with( "self", resources=CheckResourcesInput( resources=[ CheckResourceAction(resource=resource, action="view"), ] ), ) def test_is_allowed_account_resource_denied( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: identity_id = faker.pystr() vendor_uuid = str(faker.uuid4(cast_to=str)) vendor_id = faker.pyint() resource = Resource( resource_id=str(faker.uuid4(cast_to=str)), resource_type="audience", attributes={ "tenant": { "tenant_uuid": vendor_uuid, "tenant_type": TenantType.ACCOUNT, } }, ) ows_pdp_client_mock.check_resources.return_value = [ CheckResourceActionResult( resource=resource, effect=AuthEffect.DENY, ) ] ows_account_client_mock.lookup_vendors_by_vendor_ids.return_value = [ VendorLookup(vendor_id=vendor_id, uuid=vendor_uuid) ] assert not pdp_authorization_backend.is_allowed_account_resource( identity_id, account=Account(vendor_id=vendor_id, subaccount_id=0), resource_id=resource.resource_id, resource_type="audience", action="view", ) def test_is_allowed_account_resource_empty_check_resources( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: identity_id = faker.pystr() resource_id = str(faker.uuid4(cast_to=str)) vendor_id = faker.pyint() ows_pdp_client_mock.check_resources.return_value = [] ows_account_client_mock.lookup_vendors_by_vendor_ids.return_value = [] assert not pdp_authorization_backend.is_allowed_account_resource( identity_id, account=Account(vendor_id=vendor_id, subaccount_id=0), resource_id=resource_id, resource_type="audience", action="view", ) def test_is_allowed_owned_resource( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: identity_id = faker.pystr() resource = Resource( resource_id=str(faker.uuid4(cast_to=str)), resource_type="ad_account", attributes={ "identity_uuid": identity_id, }, ) ows_pdp_client_mock.check_resources.return_value = [ CheckResourceActionResult( resource=resource, effect=AuthEffect.ALLOW, ) ] assert pdp_authorization_backend.is_allowed_owned_resource( identity_id, resource_identity_id=identity_id, resource_id=resource.resource_id, resource_type="ad_account", action="connect", account=None, ) ows_account_client_mock.lookup_vendors_by_vendor_ids.assert_not_called() ows_pdp_client_mock.check_resources.assert_called_once_with( "self", resources=CheckResourcesInput( resources=[ CheckResourceAction(resource=resource, action="connect"), ] ), ) def test_is_allowed_owned_resource_denied( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: identity_id = faker.pystr() vendor_uuid = str(faker.uuid4(cast_to=str)) vendor_id = faker.pyint() resource = Resource( resource_id=str(faker.uuid4(cast_to=str)), resource_type="ad_account", attributes={ "tenant": { "tenant_uuid": vendor_uuid, "tenant_type": TenantType.ACCOUNT, } }, ) ows_pdp_client_mock.check_resources.return_value = [ CheckResourceActionResult( resource=resource, effect=AuthEffect.DENY, ) ] ows_account_client_mock.lookup_vendors_by_vendor_ids.return_value = [ VendorLookup(vendor_id=vendor_id, uuid=vendor_uuid) ] assert not pdp_authorization_backend.is_allowed_owned_resource( identity_id, resource_identity_id=str(faker.uuid4(cast_to=str)), account=Account(vendor_id=vendor_id, subaccount_id=0), resource_id=resource.resource_id, resource_type="ad_account", action="delete", ) def test_is_allowed_owned_resource_empty_check_resources( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: identity_id = faker.pystr() resource_id = str(faker.uuid4(cast_to=str)) vendor_id = faker.pyint() ows_pdp_client_mock.check_resources.return_value = [] ows_account_client_mock.lookup_vendors_by_vendor_ids.return_value = [] assert not pdp_authorization_backend.is_allowed_owned_resource( identity_id, resource_identity_id=str(faker.uuid4(cast_to=str)), account=Account(vendor_id=vendor_id, subaccount_id=0), resource_id=resource_id, resource_type="ad_account", action="delete", ) def test_authorize_for_permission( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: vendor_id = 1000 identity_id = faker.pystr() resource_type, action = faker.pystr(), faker.pystr() account_tenant = TenantFactory.build(tenant_id=vendor_id) account = Account(vendor_id=vendor_id, subaccount_id=0) ows_pdp_client_mock.get_allowed_tenants.return_value = [account_tenant] account_access = pdp_authorization_backend.authorize_for_resource_type_action( identity_id, resource_type=resource_type, action=action ) assert account_access == AccountAccess( accounts=[ Account(vendor_id=account.vendor_id, subaccount_id=account.subaccount_id) ] ) def test_authorize_for_permission_denied( ows_pdp_client_mock: mock.MagicMock, ows_account_client_mock: mock.MagicMock, pdp_authorization_backend: PdpAuthorizationBackend, faker: faker.Faker, ) -> None: identity_id = faker.pystr() ows_pdp_client_mock.get_allowed_tenants.return_value = [] with pytest.raises(PermissionDenied): pdp_authorization_backend.authorize_for_resource_type_action( identity_id, resource_type=faker.pystr(), action=faker.pystr() )