authentik.enterprise.stages.account_lockdown.tests.test_api
Test Users Account Lockdown API
1"""Test Users Account Lockdown API""" 2 3from json import loads 4from unittest.mock import MagicMock, patch 5from urllib.parse import urlparse 6 7from django.urls import reverse 8from rest_framework.test import APITestCase 9 10from authentik.core.tests.utils import ( 11 create_test_brand, 12 create_test_flow, 13 create_test_user, 14) 15from authentik.enterprise.stages.account_lockdown.models import AccountLockdownStage 16from authentik.flows.models import FlowDesignation, FlowStageBinding 17from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER 18from authentik.flows.views.executor import SESSION_KEY_PLAN 19from authentik.lib.generators import generate_id 20 21# Patch for enterprise license check 22patch_license = patch( 23 "authentik.enterprise.models.LicenseUsageStatus.is_valid", 24 MagicMock(return_value=True), 25) 26 27 28@patch_license 29class AccountLockdownAPITestCase(APITestCase): 30 """Shared helpers for account lockdown API tests.""" 31 32 def setUp(self) -> None: 33 self.lockdown_flow = create_test_flow(FlowDesignation.STAGE_CONFIGURATION) 34 self.lockdown_stage = AccountLockdownStage.objects.create(name=generate_id()) 35 FlowStageBinding.objects.create( 36 target=self.lockdown_flow, 37 stage=self.lockdown_stage, 38 order=0, 39 ) 40 self.brand = create_test_brand() 41 self.brand.flow_lockdown = self.lockdown_flow 42 self.brand.save() 43 44 def create_user_with_email(self): 45 """Create a regular user with a unique email address.""" 46 user = create_test_user() 47 user.email = f"{generate_id()}@test.com" 48 user.save() 49 return user 50 51 def assert_redirect_targets(self, response, user): 52 """Assert that a response contains a pre-planned lockdown flow link for a user.""" 53 self.assertEqual(response.status_code, 200) 54 body = loads(response.content) 55 self.assertIn(self.lockdown_flow.slug, body["link"]) 56 self.assertEqual(urlparse(body["link"]).query, "") 57 plan = self.client.session[SESSION_KEY_PLAN] 58 self.assertEqual(plan.context[PLAN_CONTEXT_PENDING_USER].pk, user.pk) 59 60 def assert_no_flow_configured(self, response): 61 """Assert that the API reports a missing lockdown flow.""" 62 self.assertEqual(response.status_code, 400) 63 body = loads(response.content) 64 self.assertIn("No lockdown flow configured", body["non_field_errors"][0]) 65 66 67@patch_license 68class TestUsersAccountLockdownAPI(AccountLockdownAPITestCase): 69 """Test Users Account Lockdown API""" 70 71 def setUp(self) -> None: 72 super().setUp() 73 self.actor = create_test_user() 74 self.user = self.create_user_with_email() 75 76 def test_account_lockdown_with_change_user_returns_redirect(self): 77 """Test that account lockdown allows users with change_user permission.""" 78 self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.user) 79 self.client.force_login(self.actor) 80 81 response = self.client.post( 82 reverse("authentik_api:user-account-lockdown"), 83 data={"user": self.user.pk}, 84 format="json", 85 ) 86 87 self.assert_redirect_targets(response, self.user) 88 89 def test_account_lockdown_no_flow_configured(self): 90 """Test account lockdown when no flow is configured""" 91 self.brand.flow_lockdown = None 92 self.brand.save() 93 self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.user) 94 self.client.force_login(self.actor) 95 96 response = self.client.post( 97 reverse("authentik_api:user-account-lockdown"), 98 data={"user": self.user.pk}, 99 format="json", 100 ) 101 102 self.assert_no_flow_configured(response) 103 104 def test_account_lockdown_unauthenticated(self): 105 """Test account lockdown requires authentication""" 106 response = self.client.post( 107 reverse("authentik_api:user-account-lockdown"), 108 data={"user": self.user.pk}, 109 format="json", 110 ) 111 112 self.assertEqual(response.status_code, 403) 113 114 def test_account_lockdown_without_change_user_denied(self): 115 """Test account lockdown denies users without change_user permission.""" 116 self.client.force_login(self.actor) 117 118 response = self.client.post( 119 reverse("authentik_api:user-account-lockdown"), 120 data={"user": self.user.pk}, 121 format="json", 122 ) 123 124 self.assertEqual(response.status_code, 403) 125 126 def test_account_lockdown_self_returns_redirect(self): 127 """Test successful self-service account lockdown returns a direct redirect.""" 128 self.client.force_login(self.user) 129 130 response = self.client.post( 131 reverse("authentik_api:user-account-lockdown"), 132 data={}, 133 format="json", 134 ) 135 136 self.assert_redirect_targets(response, self.user) 137 138 def test_account_lockdown_self_target_without_change_user_returns_redirect(self): 139 """Test self-service does not require change_user permission.""" 140 self.client.force_login(self.user) 141 142 response = self.client.post( 143 reverse("authentik_api:user-account-lockdown"), 144 data={"user": self.user.pk}, 145 format="json", 146 ) 147 148 self.assert_redirect_targets(response, self.user)
29@patch_license 30class AccountLockdownAPITestCase(APITestCase): 31 """Shared helpers for account lockdown API tests.""" 32 33 def setUp(self) -> None: 34 self.lockdown_flow = create_test_flow(FlowDesignation.STAGE_CONFIGURATION) 35 self.lockdown_stage = AccountLockdownStage.objects.create(name=generate_id()) 36 FlowStageBinding.objects.create( 37 target=self.lockdown_flow, 38 stage=self.lockdown_stage, 39 order=0, 40 ) 41 self.brand = create_test_brand() 42 self.brand.flow_lockdown = self.lockdown_flow 43 self.brand.save() 44 45 def create_user_with_email(self): 46 """Create a regular user with a unique email address.""" 47 user = create_test_user() 48 user.email = f"{generate_id()}@test.com" 49 user.save() 50 return user 51 52 def assert_redirect_targets(self, response, user): 53 """Assert that a response contains a pre-planned lockdown flow link for a user.""" 54 self.assertEqual(response.status_code, 200) 55 body = loads(response.content) 56 self.assertIn(self.lockdown_flow.slug, body["link"]) 57 self.assertEqual(urlparse(body["link"]).query, "") 58 plan = self.client.session[SESSION_KEY_PLAN] 59 self.assertEqual(plan.context[PLAN_CONTEXT_PENDING_USER].pk, user.pk) 60 61 def assert_no_flow_configured(self, response): 62 """Assert that the API reports a missing lockdown flow.""" 63 self.assertEqual(response.status_code, 400) 64 body = loads(response.content) 65 self.assertIn("No lockdown flow configured", body["non_field_errors"][0])
Shared helpers for account lockdown API tests.
33 def setUp(self) -> None: 34 self.lockdown_flow = create_test_flow(FlowDesignation.STAGE_CONFIGURATION) 35 self.lockdown_stage = AccountLockdownStage.objects.create(name=generate_id()) 36 FlowStageBinding.objects.create( 37 target=self.lockdown_flow, 38 stage=self.lockdown_stage, 39 order=0, 40 ) 41 self.brand = create_test_brand() 42 self.brand.flow_lockdown = self.lockdown_flow 43 self.brand.save()
Hook method for setting up the test fixture before exercising it.
45 def create_user_with_email(self): 46 """Create a regular user with a unique email address.""" 47 user = create_test_user() 48 user.email = f"{generate_id()}@test.com" 49 user.save() 50 return user
Create a regular user with a unique email address.
52 def assert_redirect_targets(self, response, user): 53 """Assert that a response contains a pre-planned lockdown flow link for a user.""" 54 self.assertEqual(response.status_code, 200) 55 body = loads(response.content) 56 self.assertIn(self.lockdown_flow.slug, body["link"]) 57 self.assertEqual(urlparse(body["link"]).query, "") 58 plan = self.client.session[SESSION_KEY_PLAN] 59 self.assertEqual(plan.context[PLAN_CONTEXT_PENDING_USER].pk, user.pk)
Assert that a response contains a pre-planned lockdown flow link for a user.
61 def assert_no_flow_configured(self, response): 62 """Assert that the API reports a missing lockdown flow.""" 63 self.assertEqual(response.status_code, 400) 64 body = loads(response.content) 65 self.assertIn("No lockdown flow configured", body["non_field_errors"][0])
Assert that the API reports a missing lockdown flow.
68@patch_license 69class TestUsersAccountLockdownAPI(AccountLockdownAPITestCase): 70 """Test Users Account Lockdown API""" 71 72 def setUp(self) -> None: 73 super().setUp() 74 self.actor = create_test_user() 75 self.user = self.create_user_with_email() 76 77 def test_account_lockdown_with_change_user_returns_redirect(self): 78 """Test that account lockdown allows users with change_user permission.""" 79 self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.user) 80 self.client.force_login(self.actor) 81 82 response = self.client.post( 83 reverse("authentik_api:user-account-lockdown"), 84 data={"user": self.user.pk}, 85 format="json", 86 ) 87 88 self.assert_redirect_targets(response, self.user) 89 90 def test_account_lockdown_no_flow_configured(self): 91 """Test account lockdown when no flow is configured""" 92 self.brand.flow_lockdown = None 93 self.brand.save() 94 self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.user) 95 self.client.force_login(self.actor) 96 97 response = self.client.post( 98 reverse("authentik_api:user-account-lockdown"), 99 data={"user": self.user.pk}, 100 format="json", 101 ) 102 103 self.assert_no_flow_configured(response) 104 105 def test_account_lockdown_unauthenticated(self): 106 """Test account lockdown requires authentication""" 107 response = self.client.post( 108 reverse("authentik_api:user-account-lockdown"), 109 data={"user": self.user.pk}, 110 format="json", 111 ) 112 113 self.assertEqual(response.status_code, 403) 114 115 def test_account_lockdown_without_change_user_denied(self): 116 """Test account lockdown denies users without change_user permission.""" 117 self.client.force_login(self.actor) 118 119 response = self.client.post( 120 reverse("authentik_api:user-account-lockdown"), 121 data={"user": self.user.pk}, 122 format="json", 123 ) 124 125 self.assertEqual(response.status_code, 403) 126 127 def test_account_lockdown_self_returns_redirect(self): 128 """Test successful self-service account lockdown returns a direct redirect.""" 129 self.client.force_login(self.user) 130 131 response = self.client.post( 132 reverse("authentik_api:user-account-lockdown"), 133 data={}, 134 format="json", 135 ) 136 137 self.assert_redirect_targets(response, self.user) 138 139 def test_account_lockdown_self_target_without_change_user_returns_redirect(self): 140 """Test self-service does not require change_user permission.""" 141 self.client.force_login(self.user) 142 143 response = self.client.post( 144 reverse("authentik_api:user-account-lockdown"), 145 data={"user": self.user.pk}, 146 format="json", 147 ) 148 149 self.assert_redirect_targets(response, self.user)
Test Users Account Lockdown API
72 def setUp(self) -> None: 73 super().setUp() 74 self.actor = create_test_user() 75 self.user = self.create_user_with_email()
Hook method for setting up the test fixture before exercising it.
77 def test_account_lockdown_with_change_user_returns_redirect(self): 78 """Test that account lockdown allows users with change_user permission.""" 79 self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.user) 80 self.client.force_login(self.actor) 81 82 response = self.client.post( 83 reverse("authentik_api:user-account-lockdown"), 84 data={"user": self.user.pk}, 85 format="json", 86 ) 87 88 self.assert_redirect_targets(response, self.user)
Test that account lockdown allows users with change_user permission.
90 def test_account_lockdown_no_flow_configured(self): 91 """Test account lockdown when no flow is configured""" 92 self.brand.flow_lockdown = None 93 self.brand.save() 94 self.actor.assign_perms_to_managed_role("authentik_core.change_user", self.user) 95 self.client.force_login(self.actor) 96 97 response = self.client.post( 98 reverse("authentik_api:user-account-lockdown"), 99 data={"user": self.user.pk}, 100 format="json", 101 ) 102 103 self.assert_no_flow_configured(response)
Test account lockdown when no flow is configured
105 def test_account_lockdown_unauthenticated(self): 106 """Test account lockdown requires authentication""" 107 response = self.client.post( 108 reverse("authentik_api:user-account-lockdown"), 109 data={"user": self.user.pk}, 110 format="json", 111 ) 112 113 self.assertEqual(response.status_code, 403)
Test account lockdown requires authentication
115 def test_account_lockdown_without_change_user_denied(self): 116 """Test account lockdown denies users without change_user permission.""" 117 self.client.force_login(self.actor) 118 119 response = self.client.post( 120 reverse("authentik_api:user-account-lockdown"), 121 data={"user": self.user.pk}, 122 format="json", 123 ) 124 125 self.assertEqual(response.status_code, 403)
Test account lockdown denies users without change_user permission.
127 def test_account_lockdown_self_returns_redirect(self): 128 """Test successful self-service account lockdown returns a direct redirect.""" 129 self.client.force_login(self.user) 130 131 response = self.client.post( 132 reverse("authentik_api:user-account-lockdown"), 133 data={}, 134 format="json", 135 ) 136 137 self.assert_redirect_targets(response, self.user)
Test successful self-service account lockdown returns a direct redirect.
139 def test_account_lockdown_self_target_without_change_user_returns_redirect(self): 140 """Test self-service does not require change_user permission.""" 141 self.client.force_login(self.user) 142 143 response = self.client.post( 144 reverse("authentik_api:user-account-lockdown"), 145 data={"user": self.user.pk}, 146 format="json", 147 ) 148 149 self.assert_redirect_targets(response, self.user)
Test self-service does not require change_user permission.