authentik.enterprise.tests.test_read_only

read only tests

  1"""read only tests"""
  2
  3from datetime import timedelta
  4from unittest.mock import MagicMock, patch
  5
  6from django.urls import reverse
  7from django.utils.timezone import now
  8
  9from authentik.core.tests.utils import create_test_admin_user, create_test_flow, create_test_user
 10from authentik.enterprise.license import LicenseKey
 11from authentik.enterprise.models import (
 12    THRESHOLD_READ_ONLY_WEEKS,
 13    License,
 14    LicenseUsage,
 15    LicenseUsageStatus,
 16)
 17from authentik.enterprise.tests.test_license import expiry_valid
 18from authentik.flows.models import (
 19    FlowDesignation,
 20    FlowStageBinding,
 21)
 22from authentik.flows.tests import FlowTestCase
 23from authentik.lib.generators import generate_id
 24from authentik.stages.identification.models import IdentificationStage, UserFields
 25from authentik.stages.password import BACKEND_INBUILT
 26from authentik.stages.password.models import PasswordStage
 27from authentik.stages.user_login.models import UserLoginStage
 28
 29
 30class TestReadOnly(FlowTestCase):
 31    """Test read_only"""
 32
 33    @patch(
 34        "authentik.enterprise.license.LicenseKey.validate",
 35        MagicMock(
 36            return_value=LicenseKey(
 37                aud="",
 38                exp=expiry_valid,
 39                name=generate_id(),
 40                internal_users=100,
 41                external_users=100,
 42            )
 43        ),
 44    )
 45    @patch(
 46        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
 47        MagicMock(return_value=1000),
 48    )
 49    @patch(
 50        "authentik.enterprise.license.LicenseKey.get_external_user_count",
 51        MagicMock(return_value=1000),
 52    )
 53    @patch(
 54        "authentik.enterprise.license.LicenseKey.record_usage",
 55        MagicMock(),
 56    )
 57    def test_login(self):
 58        """Test flow, ensure login is still possible with read only mode"""
 59        License.objects.create(key=generate_id())
 60        usage = LicenseUsage.objects.create(
 61            internal_user_count=100,
 62            external_user_count=100,
 63            status=LicenseUsageStatus.VALID,
 64        )
 65        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
 66        usage.save(update_fields=["record_date"])
 67
 68        flow = create_test_flow(
 69            FlowDesignation.AUTHENTICATION,
 70        )
 71
 72        ident_stage = IdentificationStage.objects.create(
 73            name=generate_id(),
 74            user_fields=[UserFields.E_MAIL],
 75            pretend_user_exists=False,
 76        )
 77        FlowStageBinding.objects.create(
 78            target=flow,
 79            stage=ident_stage,
 80            order=0,
 81        )
 82        password_stage = PasswordStage.objects.create(
 83            name=generate_id(), backends=[BACKEND_INBUILT]
 84        )
 85        FlowStageBinding.objects.create(
 86            target=flow,
 87            stage=password_stage,
 88            order=1,
 89        )
 90        login_stage = UserLoginStage.objects.create(
 91            name=generate_id(),
 92        )
 93        FlowStageBinding.objects.create(
 94            target=flow,
 95            stage=login_stage,
 96            order=2,
 97        )
 98
 99        user = create_test_user()
100
101        exec_url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug})
102        response = self.client.get(exec_url)
103        self.assertStageResponse(
104            response,
105            flow,
106            component="ak-stage-identification",
107            password_fields=False,
108            primary_action="Log in",
109            sources=[],
110            show_source_labels=False,
111            user_fields=[UserFields.E_MAIL],
112        )
113        response = self.client.post(exec_url, {"uid_field": user.email}, follow=True)
114        self.assertStageResponse(response, flow, component="ak-stage-password")
115        response = self.client.post(exec_url, {"password": user.username}, follow=True)
116        self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
117
118    @patch(
119        "authentik.enterprise.license.LicenseKey.validate",
120        MagicMock(
121            return_value=LicenseKey(
122                aud="",
123                exp=expiry_valid,
124                name=generate_id(),
125                internal_users=100,
126                external_users=100,
127            )
128        ),
129    )
130    @patch(
131        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
132        MagicMock(return_value=1000),
133    )
134    @patch(
135        "authentik.enterprise.license.LicenseKey.get_external_user_count",
136        MagicMock(return_value=1000),
137    )
138    @patch(
139        "authentik.enterprise.license.LicenseKey.record_usage",
140        MagicMock(),
141    )
142    def test_manage_licenses(self):
143        """Test that managing licenses is still possible"""
144        license = License.objects.create(key=generate_id())
145        usage = LicenseUsage.objects.create(
146            internal_user_count=100,
147            external_user_count=100,
148            status=LicenseUsageStatus.VALID,
149        )
150        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
151        usage.save(update_fields=["record_date"])
152
153        admin = create_test_admin_user()
154        self.client.force_login(admin)
155
156        # Reading is always allowed
157        response = self.client.get(reverse("authentik_api:license-list"))
158        self.assertEqual(response.status_code, 200)
159
160        # Writing should also be allowed
161        response = self.client.patch(
162            reverse("authentik_api:license-detail", kwargs={"pk": license.pk})
163        )
164        self.assertEqual(response.status_code, 200)
165
166    @patch(
167        "authentik.enterprise.license.LicenseKey.validate",
168        MagicMock(
169            return_value=LicenseKey(
170                aud="",
171                exp=expiry_valid,
172                name=generate_id(),
173                internal_users=100,
174                external_users=100,
175            )
176        ),
177    )
178    @patch(
179        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
180        MagicMock(return_value=1000),
181    )
182    @patch(
183        "authentik.enterprise.license.LicenseKey.get_external_user_count",
184        MagicMock(return_value=1000),
185    )
186    @patch(
187        "authentik.enterprise.license.LicenseKey.record_usage",
188        MagicMock(),
189    )
190    def test_manage_flows(self):
191        """Test flow"""
192        License.objects.create(key=generate_id())
193        usage = LicenseUsage.objects.create(
194            internal_user_count=100,
195            external_user_count=100,
196            status=LicenseUsageStatus.VALID,
197        )
198        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
199        usage.save(update_fields=["record_date"])
200
201        admin = create_test_admin_user()
202        self.client.force_login(admin)
203
204        # Read only is still allowed
205        response = self.client.get(reverse("authentik_api:flow-list"))
206        self.assertEqual(response.status_code, 200)
207
208        flow = create_test_flow()
209        # Writing is not
210        response = self.client.patch(
211            reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug})
212        )
213        self.assertJSONEqual(
214            response.content,
215            {"detail": "Request denied due to expired/invalid license.", "code": "denied_license"},
216        )
217        self.assertEqual(response.status_code, 400)
218
219    @patch(
220        "authentik.enterprise.license.LicenseKey.validate",
221        MagicMock(
222            return_value=LicenseKey(
223                aud="",
224                exp=expiry_valid,
225                name=generate_id(),
226                internal_users=100,
227                external_users=100,
228            )
229        ),
230    )
231    @patch(
232        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
233        MagicMock(return_value=1000),
234    )
235    @patch(
236        "authentik.enterprise.license.LicenseKey.get_external_user_count",
237        MagicMock(return_value=1000),
238    )
239    @patch(
240        "authentik.enterprise.license.LicenseKey.record_usage",
241        MagicMock(),
242    )
243    def test_manage_users(self):
244        """Test that managing users is still possible"""
245        License.objects.create(key=generate_id())
246        usage = LicenseUsage.objects.create(
247            internal_user_count=100,
248            external_user_count=100,
249            status=LicenseUsageStatus.VALID,
250        )
251        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
252        usage.save(update_fields=["record_date"])
253
254        admin = create_test_admin_user()
255        self.client.force_login(admin)
256
257        # Reading is always allowed
258        response = self.client.get(reverse("authentik_api:user-list"))
259        self.assertEqual(response.status_code, 200)
260
261        # Writing should also be allowed
262        response = self.client.patch(reverse("authentik_api:user-detail", kwargs={"pk": admin.pk}))
263        self.assertEqual(response.status_code, 200)
class TestReadOnly(authentik.flows.tests.FlowTestCase):
 31class TestReadOnly(FlowTestCase):
 32    """Test read_only"""
 33
 34    @patch(
 35        "authentik.enterprise.license.LicenseKey.validate",
 36        MagicMock(
 37            return_value=LicenseKey(
 38                aud="",
 39                exp=expiry_valid,
 40                name=generate_id(),
 41                internal_users=100,
 42                external_users=100,
 43            )
 44        ),
 45    )
 46    @patch(
 47        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
 48        MagicMock(return_value=1000),
 49    )
 50    @patch(
 51        "authentik.enterprise.license.LicenseKey.get_external_user_count",
 52        MagicMock(return_value=1000),
 53    )
 54    @patch(
 55        "authentik.enterprise.license.LicenseKey.record_usage",
 56        MagicMock(),
 57    )
 58    def test_login(self):
 59        """Test flow, ensure login is still possible with read only mode"""
 60        License.objects.create(key=generate_id())
 61        usage = LicenseUsage.objects.create(
 62            internal_user_count=100,
 63            external_user_count=100,
 64            status=LicenseUsageStatus.VALID,
 65        )
 66        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
 67        usage.save(update_fields=["record_date"])
 68
 69        flow = create_test_flow(
 70            FlowDesignation.AUTHENTICATION,
 71        )
 72
 73        ident_stage = IdentificationStage.objects.create(
 74            name=generate_id(),
 75            user_fields=[UserFields.E_MAIL],
 76            pretend_user_exists=False,
 77        )
 78        FlowStageBinding.objects.create(
 79            target=flow,
 80            stage=ident_stage,
 81            order=0,
 82        )
 83        password_stage = PasswordStage.objects.create(
 84            name=generate_id(), backends=[BACKEND_INBUILT]
 85        )
 86        FlowStageBinding.objects.create(
 87            target=flow,
 88            stage=password_stage,
 89            order=1,
 90        )
 91        login_stage = UserLoginStage.objects.create(
 92            name=generate_id(),
 93        )
 94        FlowStageBinding.objects.create(
 95            target=flow,
 96            stage=login_stage,
 97            order=2,
 98        )
 99
100        user = create_test_user()
101
102        exec_url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug})
103        response = self.client.get(exec_url)
104        self.assertStageResponse(
105            response,
106            flow,
107            component="ak-stage-identification",
108            password_fields=False,
109            primary_action="Log in",
110            sources=[],
111            show_source_labels=False,
112            user_fields=[UserFields.E_MAIL],
113        )
114        response = self.client.post(exec_url, {"uid_field": user.email}, follow=True)
115        self.assertStageResponse(response, flow, component="ak-stage-password")
116        response = self.client.post(exec_url, {"password": user.username}, follow=True)
117        self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))
118
119    @patch(
120        "authentik.enterprise.license.LicenseKey.validate",
121        MagicMock(
122            return_value=LicenseKey(
123                aud="",
124                exp=expiry_valid,
125                name=generate_id(),
126                internal_users=100,
127                external_users=100,
128            )
129        ),
130    )
131    @patch(
132        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
133        MagicMock(return_value=1000),
134    )
135    @patch(
136        "authentik.enterprise.license.LicenseKey.get_external_user_count",
137        MagicMock(return_value=1000),
138    )
139    @patch(
140        "authentik.enterprise.license.LicenseKey.record_usage",
141        MagicMock(),
142    )
143    def test_manage_licenses(self):
144        """Test that managing licenses is still possible"""
145        license = License.objects.create(key=generate_id())
146        usage = LicenseUsage.objects.create(
147            internal_user_count=100,
148            external_user_count=100,
149            status=LicenseUsageStatus.VALID,
150        )
151        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
152        usage.save(update_fields=["record_date"])
153
154        admin = create_test_admin_user()
155        self.client.force_login(admin)
156
157        # Reading is always allowed
158        response = self.client.get(reverse("authentik_api:license-list"))
159        self.assertEqual(response.status_code, 200)
160
161        # Writing should also be allowed
162        response = self.client.patch(
163            reverse("authentik_api:license-detail", kwargs={"pk": license.pk})
164        )
165        self.assertEqual(response.status_code, 200)
166
167    @patch(
168        "authentik.enterprise.license.LicenseKey.validate",
169        MagicMock(
170            return_value=LicenseKey(
171                aud="",
172                exp=expiry_valid,
173                name=generate_id(),
174                internal_users=100,
175                external_users=100,
176            )
177        ),
178    )
179    @patch(
180        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
181        MagicMock(return_value=1000),
182    )
183    @patch(
184        "authentik.enterprise.license.LicenseKey.get_external_user_count",
185        MagicMock(return_value=1000),
186    )
187    @patch(
188        "authentik.enterprise.license.LicenseKey.record_usage",
189        MagicMock(),
190    )
191    def test_manage_flows(self):
192        """Test flow"""
193        License.objects.create(key=generate_id())
194        usage = LicenseUsage.objects.create(
195            internal_user_count=100,
196            external_user_count=100,
197            status=LicenseUsageStatus.VALID,
198        )
199        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
200        usage.save(update_fields=["record_date"])
201
202        admin = create_test_admin_user()
203        self.client.force_login(admin)
204
205        # Read only is still allowed
206        response = self.client.get(reverse("authentik_api:flow-list"))
207        self.assertEqual(response.status_code, 200)
208
209        flow = create_test_flow()
210        # Writing is not
211        response = self.client.patch(
212            reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug})
213        )
214        self.assertJSONEqual(
215            response.content,
216            {"detail": "Request denied due to expired/invalid license.", "code": "denied_license"},
217        )
218        self.assertEqual(response.status_code, 400)
219
220    @patch(
221        "authentik.enterprise.license.LicenseKey.validate",
222        MagicMock(
223            return_value=LicenseKey(
224                aud="",
225                exp=expiry_valid,
226                name=generate_id(),
227                internal_users=100,
228                external_users=100,
229            )
230        ),
231    )
232    @patch(
233        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
234        MagicMock(return_value=1000),
235    )
236    @patch(
237        "authentik.enterprise.license.LicenseKey.get_external_user_count",
238        MagicMock(return_value=1000),
239    )
240    @patch(
241        "authentik.enterprise.license.LicenseKey.record_usage",
242        MagicMock(),
243    )
244    def test_manage_users(self):
245        """Test that managing users is still possible"""
246        License.objects.create(key=generate_id())
247        usage = LicenseUsage.objects.create(
248            internal_user_count=100,
249            external_user_count=100,
250            status=LicenseUsageStatus.VALID,
251        )
252        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
253        usage.save(update_fields=["record_date"])
254
255        admin = create_test_admin_user()
256        self.client.force_login(admin)
257
258        # Reading is always allowed
259        response = self.client.get(reverse("authentik_api:user-list"))
260        self.assertEqual(response.status_code, 200)
261
262        # Writing should also be allowed
263        response = self.client.patch(reverse("authentik_api:user-detail", kwargs={"pk": admin.pk}))
264        self.assertEqual(response.status_code, 200)

Test read_only

@patch('authentik.enterprise.license.LicenseKey.validate', MagicMock(return_value=LicenseKey(aud='', exp=expiry_valid, name=generate_id(), internal_users=100, external_users=100)))
@patch('authentik.enterprise.license.LicenseKey.get_internal_user_count', MagicMock(return_value=1000))
@patch('authentik.enterprise.license.LicenseKey.get_external_user_count', MagicMock(return_value=1000))
@patch('authentik.enterprise.license.LicenseKey.record_usage', MagicMock())
def test_login(self):
 34    @patch(
 35        "authentik.enterprise.license.LicenseKey.validate",
 36        MagicMock(
 37            return_value=LicenseKey(
 38                aud="",
 39                exp=expiry_valid,
 40                name=generate_id(),
 41                internal_users=100,
 42                external_users=100,
 43            )
 44        ),
 45    )
 46    @patch(
 47        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
 48        MagicMock(return_value=1000),
 49    )
 50    @patch(
 51        "authentik.enterprise.license.LicenseKey.get_external_user_count",
 52        MagicMock(return_value=1000),
 53    )
 54    @patch(
 55        "authentik.enterprise.license.LicenseKey.record_usage",
 56        MagicMock(),
 57    )
 58    def test_login(self):
 59        """Test flow, ensure login is still possible with read only mode"""
 60        License.objects.create(key=generate_id())
 61        usage = LicenseUsage.objects.create(
 62            internal_user_count=100,
 63            external_user_count=100,
 64            status=LicenseUsageStatus.VALID,
 65        )
 66        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
 67        usage.save(update_fields=["record_date"])
 68
 69        flow = create_test_flow(
 70            FlowDesignation.AUTHENTICATION,
 71        )
 72
 73        ident_stage = IdentificationStage.objects.create(
 74            name=generate_id(),
 75            user_fields=[UserFields.E_MAIL],
 76            pretend_user_exists=False,
 77        )
 78        FlowStageBinding.objects.create(
 79            target=flow,
 80            stage=ident_stage,
 81            order=0,
 82        )
 83        password_stage = PasswordStage.objects.create(
 84            name=generate_id(), backends=[BACKEND_INBUILT]
 85        )
 86        FlowStageBinding.objects.create(
 87            target=flow,
 88            stage=password_stage,
 89            order=1,
 90        )
 91        login_stage = UserLoginStage.objects.create(
 92            name=generate_id(),
 93        )
 94        FlowStageBinding.objects.create(
 95            target=flow,
 96            stage=login_stage,
 97            order=2,
 98        )
 99
100        user = create_test_user()
101
102        exec_url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": flow.slug})
103        response = self.client.get(exec_url)
104        self.assertStageResponse(
105            response,
106            flow,
107            component="ak-stage-identification",
108            password_fields=False,
109            primary_action="Log in",
110            sources=[],
111            show_source_labels=False,
112            user_fields=[UserFields.E_MAIL],
113        )
114        response = self.client.post(exec_url, {"uid_field": user.email}, follow=True)
115        self.assertStageResponse(response, flow, component="ak-stage-password")
116        response = self.client.post(exec_url, {"password": user.username}, follow=True)
117        self.assertStageRedirects(response, reverse("authentik_core:root-redirect"))

Test flow, ensure login is still possible with read only mode

@patch('authentik.enterprise.license.LicenseKey.validate', MagicMock(return_value=LicenseKey(aud='', exp=expiry_valid, name=generate_id(), internal_users=100, external_users=100)))
@patch('authentik.enterprise.license.LicenseKey.get_internal_user_count', MagicMock(return_value=1000))
@patch('authentik.enterprise.license.LicenseKey.get_external_user_count', MagicMock(return_value=1000))
@patch('authentik.enterprise.license.LicenseKey.record_usage', MagicMock())
def test_manage_licenses(self):
119    @patch(
120        "authentik.enterprise.license.LicenseKey.validate",
121        MagicMock(
122            return_value=LicenseKey(
123                aud="",
124                exp=expiry_valid,
125                name=generate_id(),
126                internal_users=100,
127                external_users=100,
128            )
129        ),
130    )
131    @patch(
132        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
133        MagicMock(return_value=1000),
134    )
135    @patch(
136        "authentik.enterprise.license.LicenseKey.get_external_user_count",
137        MagicMock(return_value=1000),
138    )
139    @patch(
140        "authentik.enterprise.license.LicenseKey.record_usage",
141        MagicMock(),
142    )
143    def test_manage_licenses(self):
144        """Test that managing licenses is still possible"""
145        license = License.objects.create(key=generate_id())
146        usage = LicenseUsage.objects.create(
147            internal_user_count=100,
148            external_user_count=100,
149            status=LicenseUsageStatus.VALID,
150        )
151        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
152        usage.save(update_fields=["record_date"])
153
154        admin = create_test_admin_user()
155        self.client.force_login(admin)
156
157        # Reading is always allowed
158        response = self.client.get(reverse("authentik_api:license-list"))
159        self.assertEqual(response.status_code, 200)
160
161        # Writing should also be allowed
162        response = self.client.patch(
163            reverse("authentik_api:license-detail", kwargs={"pk": license.pk})
164        )
165        self.assertEqual(response.status_code, 200)

Test that managing licenses is still possible

@patch('authentik.enterprise.license.LicenseKey.validate', MagicMock(return_value=LicenseKey(aud='', exp=expiry_valid, name=generate_id(), internal_users=100, external_users=100)))
@patch('authentik.enterprise.license.LicenseKey.get_internal_user_count', MagicMock(return_value=1000))
@patch('authentik.enterprise.license.LicenseKey.get_external_user_count', MagicMock(return_value=1000))
@patch('authentik.enterprise.license.LicenseKey.record_usage', MagicMock())
def test_manage_flows(self):
167    @patch(
168        "authentik.enterprise.license.LicenseKey.validate",
169        MagicMock(
170            return_value=LicenseKey(
171                aud="",
172                exp=expiry_valid,
173                name=generate_id(),
174                internal_users=100,
175                external_users=100,
176            )
177        ),
178    )
179    @patch(
180        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
181        MagicMock(return_value=1000),
182    )
183    @patch(
184        "authentik.enterprise.license.LicenseKey.get_external_user_count",
185        MagicMock(return_value=1000),
186    )
187    @patch(
188        "authentik.enterprise.license.LicenseKey.record_usage",
189        MagicMock(),
190    )
191    def test_manage_flows(self):
192        """Test flow"""
193        License.objects.create(key=generate_id())
194        usage = LicenseUsage.objects.create(
195            internal_user_count=100,
196            external_user_count=100,
197            status=LicenseUsageStatus.VALID,
198        )
199        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
200        usage.save(update_fields=["record_date"])
201
202        admin = create_test_admin_user()
203        self.client.force_login(admin)
204
205        # Read only is still allowed
206        response = self.client.get(reverse("authentik_api:flow-list"))
207        self.assertEqual(response.status_code, 200)
208
209        flow = create_test_flow()
210        # Writing is not
211        response = self.client.patch(
212            reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug})
213        )
214        self.assertJSONEqual(
215            response.content,
216            {"detail": "Request denied due to expired/invalid license.", "code": "denied_license"},
217        )
218        self.assertEqual(response.status_code, 400)

Test flow

@patch('authentik.enterprise.license.LicenseKey.validate', MagicMock(return_value=LicenseKey(aud='', exp=expiry_valid, name=generate_id(), internal_users=100, external_users=100)))
@patch('authentik.enterprise.license.LicenseKey.get_internal_user_count', MagicMock(return_value=1000))
@patch('authentik.enterprise.license.LicenseKey.get_external_user_count', MagicMock(return_value=1000))
@patch('authentik.enterprise.license.LicenseKey.record_usage', MagicMock())
def test_manage_users(self):
220    @patch(
221        "authentik.enterprise.license.LicenseKey.validate",
222        MagicMock(
223            return_value=LicenseKey(
224                aud="",
225                exp=expiry_valid,
226                name=generate_id(),
227                internal_users=100,
228                external_users=100,
229            )
230        ),
231    )
232    @patch(
233        "authentik.enterprise.license.LicenseKey.get_internal_user_count",
234        MagicMock(return_value=1000),
235    )
236    @patch(
237        "authentik.enterprise.license.LicenseKey.get_external_user_count",
238        MagicMock(return_value=1000),
239    )
240    @patch(
241        "authentik.enterprise.license.LicenseKey.record_usage",
242        MagicMock(),
243    )
244    def test_manage_users(self):
245        """Test that managing users is still possible"""
246        License.objects.create(key=generate_id())
247        usage = LicenseUsage.objects.create(
248            internal_user_count=100,
249            external_user_count=100,
250            status=LicenseUsageStatus.VALID,
251        )
252        usage.record_date = now() - timedelta(weeks=THRESHOLD_READ_ONLY_WEEKS + 1)
253        usage.save(update_fields=["record_date"])
254
255        admin = create_test_admin_user()
256        self.client.force_login(admin)
257
258        # Reading is always allowed
259        response = self.client.get(reverse("authentik_api:user-list"))
260        self.assertEqual(response.status_code, 200)
261
262        # Writing should also be allowed
263        response = self.client.patch(reverse("authentik_api:user-detail", kwargs={"pk": admin.pk}))
264        self.assertEqual(response.status_code, 200)

Test that managing users is still possible