diff --git a/authentik/tenants/api.py b/authentik/tenants/api.py index a23d0b77a..a18893674 100644 --- a/authentik/tenants/api.py +++ b/authentik/tenants/api.py @@ -1,6 +1,9 @@ """Serializer for tenant models""" +from typing import Any + from drf_spectacular.utils import extend_schema from rest_framework.decorators import action +from rest_framework.exceptions import ValidationError from rest_framework.fields import CharField, ListField from rest_framework.permissions import AllowAny from rest_framework.request import Request @@ -24,6 +27,15 @@ class FooterLinkSerializer(PassiveSerializer): class TenantSerializer(ModelSerializer): """Tenant Serializer""" + def validate(self, attrs: dict[str, Any]) -> dict[str, Any]: + if attrs.get("default", False): + tenants = Tenant.objects.filter(default=True) + if self.instance: + tenants = tenants.exclude(pk=self.instance.pk) + if tenants.exists(): + raise ValidationError("Only a single Tenant can be set as default.") + return super().validate(attrs) + class Meta: model = Tenant diff --git a/authentik/tenants/tests.py b/authentik/tenants/tests.py index ce7098e70..c3c707d71 100644 --- a/authentik/tenants/tests.py +++ b/authentik/tenants/tests.py @@ -1,16 +1,16 @@ """Test tenants""" -from django.test import TestCase from django.test.client import RequestFactory from django.urls import reverse +from rest_framework.test import APITestCase -from authentik.core.tests.utils import create_test_tenant +from authentik.core.tests.utils import create_test_admin_user, create_test_tenant from authentik.events.models import Event, EventAction from authentik.lib.config import CONFIG from authentik.lib.utils.time import timedelta_from_string from authentik.tenants.models import Tenant -class TestTenants(TestCase): +class TestTenants(APITestCase): """Test tenants""" def test_current_tenant(self): @@ -78,3 +78,18 @@ class TestTenants(TestCase): self.assertEqual( event.expires.year, (event.created + timedelta_from_string("weeks=3")).year ) + + def test_create_default_multiple(self): + """Test attempted creation of multiple default tenants""" + Tenant.objects.create( + domain="foo", + default=True, + branding_title="custom", + event_retention="weeks=3", + ) + user = create_test_admin_user() + self.client.force_login(user) + response = self.client.post( + reverse("authentik_api:tenant-list"), data={"domain": "bar", "default": True} + ) + self.assertEqual(response.status_code, 400)