"""Integration tests for DELETE /identity/{identity_uuid}/deactivate/.""" import uuid from typing import Any, Dict, List, Set import pytest import requests from mypy_boto3_dynamodb import DynamoDBClient from pdp.config import DYNAMODB_TABLE_IDENTITY, IDENTITY_HASH_KEY from tests.integration import config, utils from tests.integration.conftest import seed_test_pp_identity def test_deactivate_all_no_attached_tenants( bearer_token_pdptest_user: str, default_boto_client: DynamoDBClient, ) -> None: """DELETE /identity/{identity_uuid}/deactivate/ when there are no attached tenants. The Authenticated Principal is allowed to deactivate. However, for the identity being operated on, there are no attached tenants. ows-pdp treats this as a no-op. """ identity_uuid = uuid.uuid4() assert bearer_token_pdptest_user url = f"{config.QA_BASE_URL}/identity/{identity_uuid}/deactivate/" response = requests.delete( url, headers={"Authorization": f"Bearer {bearer_token_pdptest_user}"} ) assert response.status_code == 200, f"Response: {response.text}" assert response.json() == { "summary": { "deleted": 0, "remaining": 0, }, } # Verify tombstone records tombstone_records = utils.fetch_tombstone_records(default_boto_client) assert len(tombstone_records) == 0 def test_deactivate_all_no_allowed_tenants( bearer_token_pdptest_rap_admin_user: str, bearer_token_pdptest_rap_admin_user_identity_uuid: str, default_boto_client: DynamoDBClient, ) -> None: """DELETE /identity/{identity_uuid}/deactivate/ when there are no allowed tenants. In this case, the Authenticated Principal is allowed to generally deactivate. However, for the identity being operated on, the Authenticated Principal has no allowed tenants for which to deactivate. """ identity_uuid = uuid.uuid4() seed_test_pp_identity( default_boto_client, str(identity_uuid), "8dfd0f5b-3818-40f2-826f-8e822e61bca1", "not visible to rap_admin", tenant_type="account", ) assert bearer_token_pdptest_rap_admin_user url = f"{config.QA_BASE_URL}/identity/{identity_uuid}/deactivate/" response = requests.delete( url, headers={"Authorization": f"Bearer {bearer_token_pdptest_rap_admin_user}"} ) assert response.status_code == 403, f"Response: {response.text}" assert response.json() == { "code": "bad_request", "message": f"Principal {bearer_token_pdptest_rap_admin_user_identity_uuid} not authorized to deactivate all tenants from {identity_uuid}.", # noqa: E501 } # Verify tombstone records tombstone_records = utils.fetch_tombstone_records(default_boto_client) assert len(tombstone_records) == 0 @pytest.mark.parametrize( "user_bearer_token, expected_deleted_tenants, expected_deleted_count, expected_global_remaining", # noqa: E501 [ pytest.param( "bearer_token_pdptest_rap_admin_user", {"573d0372-7f2f-48a6-8deb-c9a6558f9549"}, 1, [ { "identity_uuid": { "S": "4d5f24f5-83f9-4989-9f82-0924a5feaf88", }, "roles": { "L": [ { "M": { "role": { "S": "visible to RAP Admin D3 user", # noqa: E501 }, }, }, ], }, "tenant_type": { "S": "subaccount", }, "tenant_uuid": { "S": "17d7fefd-9b90-4451-856d-6d391b44259b", }, "version": { "S": "1", }, }, { "identity_uuid": { "S": "4d5f24f5-83f9-4989-9f82-0924a5feaf88", }, "roles": { "L": [ { "M": { "role": { "S": "visible to RAP Admin D3 user", # noqa: E501 }, }, }, ], }, "tenant_type": { "S": "subaccount", }, "tenant_uuid": { "S": "8a13da78-eb31-42aa-aa30-75124d23b287", }, "version": { "S": "1", }, }, { "identity_uuid": { "S": "4d5f24f5-83f9-4989-9f82-0924a5feaf88", }, "roles": { "L": [ { "M": { "role": { "S": "visible to neither RAP_ADMIN", }, }, }, ], }, "tenant_type": { "S": "account", }, "tenant_uuid": { "S": "8dfd0f5b-3818-40f2-826f-8e822e61bca1", }, "version": { "S": "1", }, }, ], ), pytest.param( "bearer_token_pdptest_d3_rap_admin_user", { "17d7fefd-9b90-4451-856d-6d391b44259b", "8a13da78-eb31-42aa-aa30-75124d23b287", }, 2, [ { "identity_uuid": { "S": "4d5f24f5-83f9-4989-9f82-0924a5feaf88", }, "roles": { "L": [ { "M": { "role": { "S": "visible to RAP Admin user", }, }, }, ], }, "tenant_type": { "S": "account", }, "tenant_uuid": { "S": "573d0372-7f2f-48a6-8deb-c9a6558f9549", }, "version": { "S": "1", }, }, { "identity_uuid": { "S": "4d5f24f5-83f9-4989-9f82-0924a5feaf88", }, "roles": { "L": [ { "M": { "role": { "S": "visible to neither RAP_ADMIN", }, }, }, ], }, "tenant_type": { "S": "account", }, "tenant_uuid": { "S": "8dfd0f5b-3818-40f2-826f-8e822e61bca1", }, "version": { "S": "1", }, }, ], ), ], ) def test_deactivate_all_rap_admins( user_bearer_token: str, expected_deleted_tenants: Set[str], expected_deleted_count: int, expected_global_remaining: List[Dict[str, Any]], default_boto_client: DynamoDBClient, request: pytest.FixtureRequest, ) -> None: """Deactivate all authorizes any RAP Admins.""" bearer_token = request.getfixturevalue(user_bearer_token) seed_test_pp_identity( default_boto_client, utils.PDP_TEST_USER_UUID, "573d0372-7f2f-48a6-8deb-c9a6558f9549", "visible to RAP Admin user", tenant_type="account", ) seed_test_pp_identity( default_boto_client, utils.PDP_TEST_USER_UUID, "17d7fefd-9b90-4451-856d-6d391b44259b", "visible to RAP Admin D3 user", tenant_type="subaccount", ) seed_test_pp_identity( default_boto_client, utils.PDP_TEST_USER_UUID, "8a13da78-eb31-42aa-aa30-75124d23b287", "visible to RAP Admin D3 user", tenant_type="subaccount", ) seed_test_pp_identity( default_boto_client, utils.PDP_TEST_USER_UUID, "8dfd0f5b-3818-40f2-826f-8e822e61bca1", "visible to neither RAP_ADMIN", tenant_type="account", ) # Fetch pdp_test_user_uuid's seeded tenants # Note this isn't based on the Authenticated Principal's view, # but what DynamoDB was just seeded with for pdp_test_user_uuid. seeded_global_tenants = default_boto_client.query( TableName=DYNAMODB_TABLE_IDENTITY, ExpressionAttributeValues={":hash_key": {"S": utils.PDP_TEST_USER_UUID}}, KeyConditionExpression=f"{IDENTITY_HASH_KEY} = :hash_key", ) seeded_tenants = set( [ seeded_tenant["tenant_uuid"]["S"] for seeded_tenant in seeded_global_tenants.get("Items", []) ] ) overlap = seeded_tenants.intersection(expected_deleted_tenants) assert overlap == expected_deleted_tenants, ( "Confirm that the tenants that will be deleted are fixtured" ) url = f"{config.QA_BASE_URL}/identity/{utils.PDP_TEST_USER_UUID}/deactivate/" response = requests.delete( url, headers={"Authorization": f"Bearer {bearer_token}"}, ) assert response.status_code == 200, f"Response: {response.text}" assert response.json() == { "summary": { "deleted": expected_deleted_count, "remaining": 0, } } # Fetch pdp_test_user_uuid's remaining tenants # Note this isn't based on the Authenticated Principal's view, # but what DynamoDB still has stored for pdp_test_user_uuid. # This allows us to assert that an Authenticated Principal # has not deactivated beyond the Tenants she is authorized to deactivate. actual_global_remaining = default_boto_client.query( TableName=DYNAMODB_TABLE_IDENTITY, ExpressionAttributeValues={":hash_key": {"S": utils.PDP_TEST_USER_UUID}}, KeyConditionExpression=f"{IDENTITY_HASH_KEY} = :hash_key", ) assert actual_global_remaining.get("Items", []) == expected_global_remaining remaining_tenants = set( [ remaining_tenant["tenant_uuid"]["S"] for remaining_tenant in actual_global_remaining.get("Items", []) ] ) overlap = remaining_tenants.intersection(expected_deleted_tenants) assert overlap == set(), "Confirm that previously fixtured tenants were deleted" # Verify tombstone records tombstone_records = utils.fetch_tombstone_records(default_boto_client) assert len(tombstone_records) == expected_deleted_count assert set(tombstone_records.keys()) == expected_deleted_tenants assert all( [ r.get("identity_uuid") .get("S", "") .startswith(f"TOMBSTONE:{utils.PDP_TEST_USER_UUID}") ] for r in tombstone_records.values() ) def test_deactivate_all_no_authorization( default_boto_client: DynamoDBClient, bearer_token_pdptest_not_rap_admin_user: str, ) -> None: """Deactivate All does not authorize a non-RAP Admin.""" bearer_token_identity_uuid = utils.get_bearer_token_identity_uuid( bearer_token_pdptest_not_rap_admin_user ) url = f"{config.QA_BASE_URL}/identity/{utils.PDP_TEST_USER_UUID}/deactivate/" response = requests.delete( url, headers={"Authorization": f"Bearer {bearer_token_pdptest_not_rap_admin_user}"}, ) assert response.status_code == 403, f"Response: {response.text}" assert response.json() == { "code": "bad_request", "message": f"Principal {bearer_token_identity_uuid} not authorized to deactivate_all on identity {utils.PDP_TEST_USER_UUID}", # noqa: E501 }, "NOT RAP Admin user shouldn't be authorized to deactivate_all." # Verify tombstone records tombstone_records = utils.fetch_tombstone_records(default_boto_client) assert len(tombstone_records) == 0