authentik.core.tests.test_applications_api

Test Applications API

  1"""Test Applications API"""
  2
  3from json import loads
  4
  5from django.urls import reverse
  6from rest_framework.test import APITestCase
  7
  8from authentik.core.models import Application
  9from authentik.core.tests.utils import create_test_admin_user, create_test_flow
 10from authentik.lib.generators import generate_id
 11from authentik.policies.dummy.models import DummyPolicy
 12from authentik.policies.models import PolicyBinding
 13from authentik.providers.oauth2.models import OAuth2Provider, RedirectURI, RedirectURIMatchingMode
 14from authentik.providers.proxy.models import ProxyProvider
 15from authentik.providers.saml.models import SAMLProvider
 16
 17
 18class TestApplicationsAPI(APITestCase):
 19    """Test applications API"""
 20
 21    def setUp(self) -> None:
 22        self.user = create_test_admin_user()
 23        self.provider = OAuth2Provider.objects.create(
 24            name="test",
 25            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://some-other-domain")],
 26            authorization_flow=create_test_flow(),
 27        )
 28        self.allowed: Application = Application.objects.create(
 29            name="allowed",
 30            slug="allowed",
 31            meta_launch_url="https://goauthentik.io/%(username)s",
 32            open_in_new_tab=True,
 33            provider=self.provider,
 34        )
 35        self.denied = Application.objects.create(name="denied", slug="denied")
 36        PolicyBinding.objects.create(
 37            target=self.denied,
 38            policy=DummyPolicy.objects.create(name="deny", result=False, wait_min=1, wait_max=2),
 39            order=0,
 40        )
 41
 42    def test_formatted_launch_url(self):
 43        """Test formatted launch URL"""
 44        self.client.force_login(self.user)
 45        self.assertEqual(
 46            self.client.patch(
 47                reverse("authentik_api:application-detail", kwargs={"slug": self.allowed.slug}),
 48                {"meta_launch_url": "https://%(username)s-test.test.goauthentik.io/%(username)s"},
 49            ).status_code,
 50            200,
 51        )
 52        self.allowed.refresh_from_db()
 53        self.assertEqual(
 54            self.allowed.get_launch_url(self.user),
 55            f"https://{self.user.username}-test.test.goauthentik.io/{self.user.username}",
 56        )
 57
 58    def test_check_access(self):
 59        """Test check_access operation"""
 60        self.client.force_login(self.user)
 61        response = self.client.get(
 62            reverse(
 63                "authentik_api:application-check-access",
 64                kwargs={"slug": self.allowed.slug},
 65            )
 66        )
 67        self.assertEqual(response.status_code, 200)
 68        body = loads(response.content.decode())
 69        self.assertEqual(body["passing"], True)
 70        self.assertEqual(body["messages"], [])
 71        self.assertEqual(len(body["log_messages"]), 0)
 72        response = self.client.get(
 73            reverse(
 74                "authentik_api:application-check-access",
 75                kwargs={"slug": self.denied.slug},
 76            )
 77        )
 78        self.assertEqual(response.status_code, 200)
 79        body = loads(response.content.decode())
 80        self.assertEqual(body["passing"], False)
 81        self.assertEqual(body["messages"], ["dummy"])
 82
 83    def test_list(self):
 84        """Test list operation without superuser_full_list"""
 85        self.client.force_login(self.user)
 86        response = self.client.get(reverse("authentik_api:application-list"))
 87        self.assertJSONEqual(
 88            response.content.decode(),
 89            {
 90                "autocomplete": {},
 91                "pagination": {
 92                    "next": 0,
 93                    "previous": 0,
 94                    "count": 2,
 95                    "current": 1,
 96                    "total_pages": 1,
 97                    "start_index": 1,
 98                    "end_index": 2,
 99                },
100                "results": [
101                    {
102                        "pk": str(self.allowed.pk),
103                        "name": "allowed",
104                        "slug": "allowed",
105                        "group": "",
106                        "provider": self.provider.pk,
107                        "provider_obj": {
108                            "assigned_application_name": "allowed",
109                            "assigned_application_slug": "allowed",
110                            "assigned_backchannel_application_name": None,
111                            "assigned_backchannel_application_slug": None,
112                            "authentication_flow": None,
113                            "invalidation_flow": None,
114                            "authorization_flow": str(self.provider.authorization_flow.pk),
115                            "component": "ak-provider-oauth2-form",
116                            "meta_model_name": "authentik_providers_oauth2.oauth2provider",
117                            "name": self.provider.name,
118                            "pk": self.provider.pk,
119                            "property_mappings": [],
120                            "verbose_name": "OAuth2/OpenID Provider",
121                            "verbose_name_plural": "OAuth2/OpenID Providers",
122                        },
123                        "backchannel_providers": [],
124                        "backchannel_providers_obj": [],
125                        "launch_url": f"https://goauthentik.io/{self.user.username}",
126                        "meta_launch_url": "https://goauthentik.io/%(username)s",
127                        "open_in_new_tab": True,
128                        "meta_icon": "",
129                        "meta_icon_url": None,
130                        "meta_icon_themed_urls": None,
131                        "meta_description": "",
132                        "meta_hide": False,
133                        "meta_publisher": "",
134                        "policy_engine_mode": "any",
135                    },
136                ],
137            },
138        )
139
140    def test_list_superuser_full_list(self):
141        """Test list operation with superuser_full_list"""
142        self.client.force_login(self.user)
143        response = self.client.get(
144            reverse("authentik_api:application-list") + "?superuser_full_list=true"
145        )
146        self.assertJSONEqual(
147            response.content.decode(),
148            {
149                "autocomplete": {},
150                "pagination": {
151                    "next": 0,
152                    "previous": 0,
153                    "count": 2,
154                    "current": 1,
155                    "total_pages": 1,
156                    "start_index": 1,
157                    "end_index": 2,
158                },
159                "results": [
160                    {
161                        "pk": str(self.allowed.pk),
162                        "name": "allowed",
163                        "slug": "allowed",
164                        "group": "",
165                        "provider": self.provider.pk,
166                        "provider_obj": {
167                            "assigned_application_name": "allowed",
168                            "assigned_application_slug": "allowed",
169                            "assigned_backchannel_application_name": None,
170                            "assigned_backchannel_application_slug": None,
171                            "authentication_flow": None,
172                            "invalidation_flow": None,
173                            "authorization_flow": str(self.provider.authorization_flow.pk),
174                            "component": "ak-provider-oauth2-form",
175                            "meta_model_name": "authentik_providers_oauth2.oauth2provider",
176                            "name": self.provider.name,
177                            "pk": self.provider.pk,
178                            "property_mappings": [],
179                            "verbose_name": "OAuth2/OpenID Provider",
180                            "verbose_name_plural": "OAuth2/OpenID Providers",
181                        },
182                        "backchannel_providers": [],
183                        "backchannel_providers_obj": [],
184                        "launch_url": f"https://goauthentik.io/{self.user.username}",
185                        "meta_launch_url": "https://goauthentik.io/%(username)s",
186                        "open_in_new_tab": True,
187                        "meta_icon": "",
188                        "meta_icon_url": None,
189                        "meta_icon_themed_urls": None,
190                        "meta_description": "",
191                        "meta_hide": False,
192                        "meta_publisher": "",
193                        "policy_engine_mode": "any",
194                    },
195                    {
196                        "launch_url": None,
197                        "meta_description": "",
198                        "meta_hide": False,
199                        "meta_icon": "",
200                        "meta_icon_url": None,
201                        "meta_icon_themed_urls": None,
202                        "meta_launch_url": "",
203                        "open_in_new_tab": False,
204                        "meta_publisher": "",
205                        "group": "",
206                        "name": "denied",
207                        "pk": str(self.denied.pk),
208                        "policy_engine_mode": "any",
209                        "provider": None,
210                        "provider_obj": None,
211                        "backchannel_providers": [],
212                        "backchannel_providers_obj": [],
213                        "slug": "denied",
214                    },
215                ],
216            },
217        )
218
219    def test_get_provider(self):
220        """Ensure that proxy providers (at the time of writing that is the only provider
221        that inherits from another proxy type (OAuth) instead of inheriting from the root
222        provider class) is correctly looked up and selected from the database"""
223        slug = generate_id()
224        provider = ProxyProvider.objects.create(name=generate_id())
225        Application.objects.create(
226            name=generate_id(),
227            slug=slug,
228            provider=provider,
229        )
230        self.assertEqual(Application.objects.get(slug=slug).get_provider(), provider)
231        self.assertEqual(
232            Application.objects.with_provider().get(slug=slug).get_provider(), provider
233        )
234
235        slug = generate_id()
236        provider = SAMLProvider.objects.create(name=generate_id())
237        Application.objects.create(
238            name=generate_id(),
239            slug=slug,
240            provider=provider,
241        )
242        self.assertEqual(Application.objects.get(slug=slug).get_provider(), provider)
243        self.assertEqual(
244            Application.objects.with_provider().get(slug=slug).get_provider(), provider
245        )
246
247    def test_create_application_with_reserved_slug(self):
248        """Test creating an application with a reserved slug"""
249        self.client.force_login(self.user)
250        response = self.client.post(
251            reverse("authentik_api:application-list"),
252            {
253                "name": "Test Application",
254                "slug": Application.reserved_slugs[0],
255            },
256        )
257        self.assertEqual(response.status_code, 400)
258        self.assertIn("slug", response.data)
259        self.assertIn("reserved", response.data["slug"][0])
260
261    def test_update_application_with_reserved_slug(self):
262        """Test updating an application to use a reserved slug"""
263        self.client.force_login(self.user)
264        app = Application.objects.create(
265            name="Test Application",
266            slug="valid-slug",
267        )
268
269        response = self.client.patch(
270            reverse("authentik_api:application-detail", kwargs={"slug": app.slug}),
271            {
272                "slug": Application.reserved_slugs[0],
273            },
274        )
275        self.assertEqual(response.status_code, 400)
276        self.assertIn("slug", response.data)
277        self.assertIn("reserved", response.data["slug"][0])
class TestApplicationsAPI(rest_framework.test.APITestCase):
 19class TestApplicationsAPI(APITestCase):
 20    """Test applications API"""
 21
 22    def setUp(self) -> None:
 23        self.user = create_test_admin_user()
 24        self.provider = OAuth2Provider.objects.create(
 25            name="test",
 26            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://some-other-domain")],
 27            authorization_flow=create_test_flow(),
 28        )
 29        self.allowed: Application = Application.objects.create(
 30            name="allowed",
 31            slug="allowed",
 32            meta_launch_url="https://goauthentik.io/%(username)s",
 33            open_in_new_tab=True,
 34            provider=self.provider,
 35        )
 36        self.denied = Application.objects.create(name="denied", slug="denied")
 37        PolicyBinding.objects.create(
 38            target=self.denied,
 39            policy=DummyPolicy.objects.create(name="deny", result=False, wait_min=1, wait_max=2),
 40            order=0,
 41        )
 42
 43    def test_formatted_launch_url(self):
 44        """Test formatted launch URL"""
 45        self.client.force_login(self.user)
 46        self.assertEqual(
 47            self.client.patch(
 48                reverse("authentik_api:application-detail", kwargs={"slug": self.allowed.slug}),
 49                {"meta_launch_url": "https://%(username)s-test.test.goauthentik.io/%(username)s"},
 50            ).status_code,
 51            200,
 52        )
 53        self.allowed.refresh_from_db()
 54        self.assertEqual(
 55            self.allowed.get_launch_url(self.user),
 56            f"https://{self.user.username}-test.test.goauthentik.io/{self.user.username}",
 57        )
 58
 59    def test_check_access(self):
 60        """Test check_access operation"""
 61        self.client.force_login(self.user)
 62        response = self.client.get(
 63            reverse(
 64                "authentik_api:application-check-access",
 65                kwargs={"slug": self.allowed.slug},
 66            )
 67        )
 68        self.assertEqual(response.status_code, 200)
 69        body = loads(response.content.decode())
 70        self.assertEqual(body["passing"], True)
 71        self.assertEqual(body["messages"], [])
 72        self.assertEqual(len(body["log_messages"]), 0)
 73        response = self.client.get(
 74            reverse(
 75                "authentik_api:application-check-access",
 76                kwargs={"slug": self.denied.slug},
 77            )
 78        )
 79        self.assertEqual(response.status_code, 200)
 80        body = loads(response.content.decode())
 81        self.assertEqual(body["passing"], False)
 82        self.assertEqual(body["messages"], ["dummy"])
 83
 84    def test_list(self):
 85        """Test list operation without superuser_full_list"""
 86        self.client.force_login(self.user)
 87        response = self.client.get(reverse("authentik_api:application-list"))
 88        self.assertJSONEqual(
 89            response.content.decode(),
 90            {
 91                "autocomplete": {},
 92                "pagination": {
 93                    "next": 0,
 94                    "previous": 0,
 95                    "count": 2,
 96                    "current": 1,
 97                    "total_pages": 1,
 98                    "start_index": 1,
 99                    "end_index": 2,
100                },
101                "results": [
102                    {
103                        "pk": str(self.allowed.pk),
104                        "name": "allowed",
105                        "slug": "allowed",
106                        "group": "",
107                        "provider": self.provider.pk,
108                        "provider_obj": {
109                            "assigned_application_name": "allowed",
110                            "assigned_application_slug": "allowed",
111                            "assigned_backchannel_application_name": None,
112                            "assigned_backchannel_application_slug": None,
113                            "authentication_flow": None,
114                            "invalidation_flow": None,
115                            "authorization_flow": str(self.provider.authorization_flow.pk),
116                            "component": "ak-provider-oauth2-form",
117                            "meta_model_name": "authentik_providers_oauth2.oauth2provider",
118                            "name": self.provider.name,
119                            "pk": self.provider.pk,
120                            "property_mappings": [],
121                            "verbose_name": "OAuth2/OpenID Provider",
122                            "verbose_name_plural": "OAuth2/OpenID Providers",
123                        },
124                        "backchannel_providers": [],
125                        "backchannel_providers_obj": [],
126                        "launch_url": f"https://goauthentik.io/{self.user.username}",
127                        "meta_launch_url": "https://goauthentik.io/%(username)s",
128                        "open_in_new_tab": True,
129                        "meta_icon": "",
130                        "meta_icon_url": None,
131                        "meta_icon_themed_urls": None,
132                        "meta_description": "",
133                        "meta_hide": False,
134                        "meta_publisher": "",
135                        "policy_engine_mode": "any",
136                    },
137                ],
138            },
139        )
140
141    def test_list_superuser_full_list(self):
142        """Test list operation with superuser_full_list"""
143        self.client.force_login(self.user)
144        response = self.client.get(
145            reverse("authentik_api:application-list") + "?superuser_full_list=true"
146        )
147        self.assertJSONEqual(
148            response.content.decode(),
149            {
150                "autocomplete": {},
151                "pagination": {
152                    "next": 0,
153                    "previous": 0,
154                    "count": 2,
155                    "current": 1,
156                    "total_pages": 1,
157                    "start_index": 1,
158                    "end_index": 2,
159                },
160                "results": [
161                    {
162                        "pk": str(self.allowed.pk),
163                        "name": "allowed",
164                        "slug": "allowed",
165                        "group": "",
166                        "provider": self.provider.pk,
167                        "provider_obj": {
168                            "assigned_application_name": "allowed",
169                            "assigned_application_slug": "allowed",
170                            "assigned_backchannel_application_name": None,
171                            "assigned_backchannel_application_slug": None,
172                            "authentication_flow": None,
173                            "invalidation_flow": None,
174                            "authorization_flow": str(self.provider.authorization_flow.pk),
175                            "component": "ak-provider-oauth2-form",
176                            "meta_model_name": "authentik_providers_oauth2.oauth2provider",
177                            "name": self.provider.name,
178                            "pk": self.provider.pk,
179                            "property_mappings": [],
180                            "verbose_name": "OAuth2/OpenID Provider",
181                            "verbose_name_plural": "OAuth2/OpenID Providers",
182                        },
183                        "backchannel_providers": [],
184                        "backchannel_providers_obj": [],
185                        "launch_url": f"https://goauthentik.io/{self.user.username}",
186                        "meta_launch_url": "https://goauthentik.io/%(username)s",
187                        "open_in_new_tab": True,
188                        "meta_icon": "",
189                        "meta_icon_url": None,
190                        "meta_icon_themed_urls": None,
191                        "meta_description": "",
192                        "meta_hide": False,
193                        "meta_publisher": "",
194                        "policy_engine_mode": "any",
195                    },
196                    {
197                        "launch_url": None,
198                        "meta_description": "",
199                        "meta_hide": False,
200                        "meta_icon": "",
201                        "meta_icon_url": None,
202                        "meta_icon_themed_urls": None,
203                        "meta_launch_url": "",
204                        "open_in_new_tab": False,
205                        "meta_publisher": "",
206                        "group": "",
207                        "name": "denied",
208                        "pk": str(self.denied.pk),
209                        "policy_engine_mode": "any",
210                        "provider": None,
211                        "provider_obj": None,
212                        "backchannel_providers": [],
213                        "backchannel_providers_obj": [],
214                        "slug": "denied",
215                    },
216                ],
217            },
218        )
219
220    def test_get_provider(self):
221        """Ensure that proxy providers (at the time of writing that is the only provider
222        that inherits from another proxy type (OAuth) instead of inheriting from the root
223        provider class) is correctly looked up and selected from the database"""
224        slug = generate_id()
225        provider = ProxyProvider.objects.create(name=generate_id())
226        Application.objects.create(
227            name=generate_id(),
228            slug=slug,
229            provider=provider,
230        )
231        self.assertEqual(Application.objects.get(slug=slug).get_provider(), provider)
232        self.assertEqual(
233            Application.objects.with_provider().get(slug=slug).get_provider(), provider
234        )
235
236        slug = generate_id()
237        provider = SAMLProvider.objects.create(name=generate_id())
238        Application.objects.create(
239            name=generate_id(),
240            slug=slug,
241            provider=provider,
242        )
243        self.assertEqual(Application.objects.get(slug=slug).get_provider(), provider)
244        self.assertEqual(
245            Application.objects.with_provider().get(slug=slug).get_provider(), provider
246        )
247
248    def test_create_application_with_reserved_slug(self):
249        """Test creating an application with a reserved slug"""
250        self.client.force_login(self.user)
251        response = self.client.post(
252            reverse("authentik_api:application-list"),
253            {
254                "name": "Test Application",
255                "slug": Application.reserved_slugs[0],
256            },
257        )
258        self.assertEqual(response.status_code, 400)
259        self.assertIn("slug", response.data)
260        self.assertIn("reserved", response.data["slug"][0])
261
262    def test_update_application_with_reserved_slug(self):
263        """Test updating an application to use a reserved slug"""
264        self.client.force_login(self.user)
265        app = Application.objects.create(
266            name="Test Application",
267            slug="valid-slug",
268        )
269
270        response = self.client.patch(
271            reverse("authentik_api:application-detail", kwargs={"slug": app.slug}),
272            {
273                "slug": Application.reserved_slugs[0],
274            },
275        )
276        self.assertEqual(response.status_code, 400)
277        self.assertIn("slug", response.data)
278        self.assertIn("reserved", response.data["slug"][0])

Test applications API

def setUp(self) -> None:
22    def setUp(self) -> None:
23        self.user = create_test_admin_user()
24        self.provider = OAuth2Provider.objects.create(
25            name="test",
26            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://some-other-domain")],
27            authorization_flow=create_test_flow(),
28        )
29        self.allowed: Application = Application.objects.create(
30            name="allowed",
31            slug="allowed",
32            meta_launch_url="https://goauthentik.io/%(username)s",
33            open_in_new_tab=True,
34            provider=self.provider,
35        )
36        self.denied = Application.objects.create(name="denied", slug="denied")
37        PolicyBinding.objects.create(
38            target=self.denied,
39            policy=DummyPolicy.objects.create(name="deny", result=False, wait_min=1, wait_max=2),
40            order=0,
41        )

Hook method for setting up the test fixture before exercising it.

def test_formatted_launch_url(self):
43    def test_formatted_launch_url(self):
44        """Test formatted launch URL"""
45        self.client.force_login(self.user)
46        self.assertEqual(
47            self.client.patch(
48                reverse("authentik_api:application-detail", kwargs={"slug": self.allowed.slug}),
49                {"meta_launch_url": "https://%(username)s-test.test.goauthentik.io/%(username)s"},
50            ).status_code,
51            200,
52        )
53        self.allowed.refresh_from_db()
54        self.assertEqual(
55            self.allowed.get_launch_url(self.user),
56            f"https://{self.user.username}-test.test.goauthentik.io/{self.user.username}",
57        )

Test formatted launch URL

def test_check_access(self):
59    def test_check_access(self):
60        """Test check_access operation"""
61        self.client.force_login(self.user)
62        response = self.client.get(
63            reverse(
64                "authentik_api:application-check-access",
65                kwargs={"slug": self.allowed.slug},
66            )
67        )
68        self.assertEqual(response.status_code, 200)
69        body = loads(response.content.decode())
70        self.assertEqual(body["passing"], True)
71        self.assertEqual(body["messages"], [])
72        self.assertEqual(len(body["log_messages"]), 0)
73        response = self.client.get(
74            reverse(
75                "authentik_api:application-check-access",
76                kwargs={"slug": self.denied.slug},
77            )
78        )
79        self.assertEqual(response.status_code, 200)
80        body = loads(response.content.decode())
81        self.assertEqual(body["passing"], False)
82        self.assertEqual(body["messages"], ["dummy"])

Test check_access operation

def test_list(self):
 84    def test_list(self):
 85        """Test list operation without superuser_full_list"""
 86        self.client.force_login(self.user)
 87        response = self.client.get(reverse("authentik_api:application-list"))
 88        self.assertJSONEqual(
 89            response.content.decode(),
 90            {
 91                "autocomplete": {},
 92                "pagination": {
 93                    "next": 0,
 94                    "previous": 0,
 95                    "count": 2,
 96                    "current": 1,
 97                    "total_pages": 1,
 98                    "start_index": 1,
 99                    "end_index": 2,
100                },
101                "results": [
102                    {
103                        "pk": str(self.allowed.pk),
104                        "name": "allowed",
105                        "slug": "allowed",
106                        "group": "",
107                        "provider": self.provider.pk,
108                        "provider_obj": {
109                            "assigned_application_name": "allowed",
110                            "assigned_application_slug": "allowed",
111                            "assigned_backchannel_application_name": None,
112                            "assigned_backchannel_application_slug": None,
113                            "authentication_flow": None,
114                            "invalidation_flow": None,
115                            "authorization_flow": str(self.provider.authorization_flow.pk),
116                            "component": "ak-provider-oauth2-form",
117                            "meta_model_name": "authentik_providers_oauth2.oauth2provider",
118                            "name": self.provider.name,
119                            "pk": self.provider.pk,
120                            "property_mappings": [],
121                            "verbose_name": "OAuth2/OpenID Provider",
122                            "verbose_name_plural": "OAuth2/OpenID Providers",
123                        },
124                        "backchannel_providers": [],
125                        "backchannel_providers_obj": [],
126                        "launch_url": f"https://goauthentik.io/{self.user.username}",
127                        "meta_launch_url": "https://goauthentik.io/%(username)s",
128                        "open_in_new_tab": True,
129                        "meta_icon": "",
130                        "meta_icon_url": None,
131                        "meta_icon_themed_urls": None,
132                        "meta_description": "",
133                        "meta_hide": False,
134                        "meta_publisher": "",
135                        "policy_engine_mode": "any",
136                    },
137                ],
138            },
139        )

Test list operation without superuser_full_list

def test_list_superuser_full_list(self):
141    def test_list_superuser_full_list(self):
142        """Test list operation with superuser_full_list"""
143        self.client.force_login(self.user)
144        response = self.client.get(
145            reverse("authentik_api:application-list") + "?superuser_full_list=true"
146        )
147        self.assertJSONEqual(
148            response.content.decode(),
149            {
150                "autocomplete": {},
151                "pagination": {
152                    "next": 0,
153                    "previous": 0,
154                    "count": 2,
155                    "current": 1,
156                    "total_pages": 1,
157                    "start_index": 1,
158                    "end_index": 2,
159                },
160                "results": [
161                    {
162                        "pk": str(self.allowed.pk),
163                        "name": "allowed",
164                        "slug": "allowed",
165                        "group": "",
166                        "provider": self.provider.pk,
167                        "provider_obj": {
168                            "assigned_application_name": "allowed",
169                            "assigned_application_slug": "allowed",
170                            "assigned_backchannel_application_name": None,
171                            "assigned_backchannel_application_slug": None,
172                            "authentication_flow": None,
173                            "invalidation_flow": None,
174                            "authorization_flow": str(self.provider.authorization_flow.pk),
175                            "component": "ak-provider-oauth2-form",
176                            "meta_model_name": "authentik_providers_oauth2.oauth2provider",
177                            "name": self.provider.name,
178                            "pk": self.provider.pk,
179                            "property_mappings": [],
180                            "verbose_name": "OAuth2/OpenID Provider",
181                            "verbose_name_plural": "OAuth2/OpenID Providers",
182                        },
183                        "backchannel_providers": [],
184                        "backchannel_providers_obj": [],
185                        "launch_url": f"https://goauthentik.io/{self.user.username}",
186                        "meta_launch_url": "https://goauthentik.io/%(username)s",
187                        "open_in_new_tab": True,
188                        "meta_icon": "",
189                        "meta_icon_url": None,
190                        "meta_icon_themed_urls": None,
191                        "meta_description": "",
192                        "meta_hide": False,
193                        "meta_publisher": "",
194                        "policy_engine_mode": "any",
195                    },
196                    {
197                        "launch_url": None,
198                        "meta_description": "",
199                        "meta_hide": False,
200                        "meta_icon": "",
201                        "meta_icon_url": None,
202                        "meta_icon_themed_urls": None,
203                        "meta_launch_url": "",
204                        "open_in_new_tab": False,
205                        "meta_publisher": "",
206                        "group": "",
207                        "name": "denied",
208                        "pk": str(self.denied.pk),
209                        "policy_engine_mode": "any",
210                        "provider": None,
211                        "provider_obj": None,
212                        "backchannel_providers": [],
213                        "backchannel_providers_obj": [],
214                        "slug": "denied",
215                    },
216                ],
217            },
218        )

Test list operation with superuser_full_list

def test_get_provider(self):
220    def test_get_provider(self):
221        """Ensure that proxy providers (at the time of writing that is the only provider
222        that inherits from another proxy type (OAuth) instead of inheriting from the root
223        provider class) is correctly looked up and selected from the database"""
224        slug = generate_id()
225        provider = ProxyProvider.objects.create(name=generate_id())
226        Application.objects.create(
227            name=generate_id(),
228            slug=slug,
229            provider=provider,
230        )
231        self.assertEqual(Application.objects.get(slug=slug).get_provider(), provider)
232        self.assertEqual(
233            Application.objects.with_provider().get(slug=slug).get_provider(), provider
234        )
235
236        slug = generate_id()
237        provider = SAMLProvider.objects.create(name=generate_id())
238        Application.objects.create(
239            name=generate_id(),
240            slug=slug,
241            provider=provider,
242        )
243        self.assertEqual(Application.objects.get(slug=slug).get_provider(), provider)
244        self.assertEqual(
245            Application.objects.with_provider().get(slug=slug).get_provider(), provider
246        )

Ensure that proxy providers (at the time of writing that is the only provider that inherits from another proxy type (OAuth) instead of inheriting from the root provider class) is correctly looked up and selected from the database

def test_create_application_with_reserved_slug(self):
248    def test_create_application_with_reserved_slug(self):
249        """Test creating an application with a reserved slug"""
250        self.client.force_login(self.user)
251        response = self.client.post(
252            reverse("authentik_api:application-list"),
253            {
254                "name": "Test Application",
255                "slug": Application.reserved_slugs[0],
256            },
257        )
258        self.assertEqual(response.status_code, 400)
259        self.assertIn("slug", response.data)
260        self.assertIn("reserved", response.data["slug"][0])

Test creating an application with a reserved slug

def test_update_application_with_reserved_slug(self):
262    def test_update_application_with_reserved_slug(self):
263        """Test updating an application to use a reserved slug"""
264        self.client.force_login(self.user)
265        app = Application.objects.create(
266            name="Test Application",
267            slug="valid-slug",
268        )
269
270        response = self.client.patch(
271            reverse("authentik_api:application-detail", kwargs={"slug": app.slug}),
272            {
273                "slug": Application.reserved_slugs[0],
274            },
275        )
276        self.assertEqual(response.status_code, 400)
277        self.assertIn("slug", response.data)
278        self.assertIn("reserved", response.data["slug"][0])

Test updating an application to use a reserved slug