We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Backchannel LDAP providers missing from outpost configuration page
**Description**
When creating an LDAP Provider, it will appear in the Outpost create/configuration page if it is assigned an application, but not if it's assigned as an application backchannel.

This means we're unable to associate an LDAP backchannel to an outpost.

**To Reproduce**
Steps to reproduce the behavior:

1. Create a demo Application and an LDAP Provider
2. Assign the LDAP Provider as a _backchannel provider_ to the application.
3. Attempt to create an LDAP outpost. Notice the LDAP provider does not appear on the selectable list.

**Expected behavior**
The backchannel should appear the outposts "applications" list, so that it may be added to the outpost.

**Version and Deployment (please complete the following information):**
-   authentik version: 2023.5.2
-   Deployment: docker-compose


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `authentik/providers/ldap/api.py`
Content:
```
1 """LDAPProvider API Views"""
2 from rest_framework.fields import CharField, ListField, SerializerMethodField
3 from rest_framework.serializers import ModelSerializer
4 from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
5 
6 from authentik.core.api.providers import ProviderSerializer
7 from authentik.core.api.used_by import UsedByMixin
8 from authentik.providers.ldap.models import LDAPProvider
9 
10 
11 class LDAPProviderSerializer(ProviderSerializer):
12     """LDAPProvider Serializer"""
13 
14     outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all")
15 
16     class Meta:
17         model = LDAPProvider
18         fields = ProviderSerializer.Meta.fields + [
19             "base_dn",
20             "search_group",
21             "certificate",
22             "tls_server_name",
23             "uid_start_number",
24             "gid_start_number",
25             "outpost_set",
26             "search_mode",
27             "bind_mode",
28         ]
29         extra_kwargs = ProviderSerializer.Meta.extra_kwargs
30 
31 
32 class LDAPProviderViewSet(UsedByMixin, ModelViewSet):
33     """LDAPProvider Viewset"""
34 
35     queryset = LDAPProvider.objects.all()
36     serializer_class = LDAPProviderSerializer
37     filterset_fields = {
38         "application": ["isnull"],
39         "name": ["iexact"],
40         "authorization_flow__slug": ["iexact"],
41         "base_dn": ["iexact"],
42         "search_group__group_uuid": ["iexact"],
43         "search_group__name": ["iexact"],
44         "certificate__kp_uuid": ["iexact"],
45         "certificate__name": ["iexact"],
46         "tls_server_name": ["iexact"],
47         "uid_start_number": ["iexact"],
48         "gid_start_number": ["iexact"],
49     }
50     search_fields = ["name"]
51     ordering = ["name"]
52 
53 
54 class LDAPOutpostConfigSerializer(ModelSerializer):
55     """LDAPProvider Serializer"""
56 
57     application_slug = SerializerMethodField()
58     bind_flow_slug = CharField(source="authorization_flow.slug")
59 
60     def get_application_slug(self, instance: LDAPProvider) -> str:
61         """Prioritise backchannel slug over direct application slug"""
62         if instance.backchannel_application:
63             return instance.backchannel_application.slug
64         return instance.application.slug
65 
66     class Meta:
67         model = LDAPProvider
68         fields = [
69             "pk",
70             "name",
71             "base_dn",
72             "bind_flow_slug",
73             "application_slug",
74             "search_group",
75             "certificate",
76             "tls_server_name",
77             "uid_start_number",
78             "gid_start_number",
79             "search_mode",
80             "bind_mode",
81         ]
82 
83 
84 class LDAPOutpostConfigViewSet(ReadOnlyModelViewSet):
85     """LDAPProvider Viewset"""
86 
87     queryset = LDAPProvider.objects.filter(application__isnull=False)
88     serializer_class = LDAPOutpostConfigSerializer
89     ordering = ["name"]
90     search_fields = ["name"]
91     filterset_fields = ["name"]
92
```

Path: `authentik/core/api/providers.py`
Content:
```
1 """Provider API Views"""
2 from django.utils.translation import gettext_lazy as _
3 from django_filters.filters import BooleanFilter
4 from django_filters.filterset import FilterSet
5 from drf_spectacular.utils import extend_schema
6 from rest_framework import mixins
7 from rest_framework.decorators import action
8 from rest_framework.fields import ReadOnlyField
9 from rest_framework.request import Request
10 from rest_framework.response import Response
11 from rest_framework.serializers import ModelSerializer, SerializerMethodField
12 from rest_framework.viewsets import GenericViewSet
13 
14 from authentik.core.api.used_by import UsedByMixin
15 from authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer
16 from authentik.core.models import Provider
17 from authentik.lib.utils.reflection import all_subclasses
18 
19 
20 class ProviderSerializer(ModelSerializer, MetaNameSerializer):
21     """Provider Serializer"""
22 
23     assigned_application_slug = ReadOnlyField(source="application.slug")
24     assigned_application_name = ReadOnlyField(source="application.name")
25     assigned_backchannel_application_slug = ReadOnlyField(source="backchannel_application.slug")
26     assigned_backchannel_application_name = ReadOnlyField(source="backchannel_application.name")
27 
28     component = SerializerMethodField()
29 
30     def get_component(self, obj: Provider) -> str:  # pragma: no cover
31         """Get object component so that we know how to edit the object"""
32         if obj.__class__ == Provider:
33             return ""
34         return obj.component
35 
36     class Meta:
37         model = Provider
38         fields = [
39             "pk",
40             "name",
41             "authentication_flow",
42             "authorization_flow",
43             "property_mappings",
44             "component",
45             "assigned_application_slug",
46             "assigned_application_name",
47             "assigned_backchannel_application_slug",
48             "assigned_backchannel_application_name",
49             "verbose_name",
50             "verbose_name_plural",
51             "meta_model_name",
52         ]
53         extra_kwargs = {
54             "authorization_flow": {"required": True, "allow_null": False},
55         }
56 
57 
58 class ProviderFilter(FilterSet):
59     """Filter for groups"""
60 
61     application__isnull = BooleanFilter(
62         field_name="application",
63         lookup_expr="isnull",
64     )
65     backchannel_only = BooleanFilter(
66         method="filter_backchannel_only",
67     )
68 
69     def filter_backchannel_only(self, queryset, name, value):
70         """Only return backchannel providers"""
71         return queryset.filter(is_backchannel=value)
72 
73 
74 class ProviderViewSet(
75     mixins.RetrieveModelMixin,
76     mixins.DestroyModelMixin,
77     UsedByMixin,
78     mixins.ListModelMixin,
79     GenericViewSet,
80 ):
81     """Provider Viewset"""
82 
83     queryset = Provider.objects.none()
84     serializer_class = ProviderSerializer
85     filterset_class = ProviderFilter
86     search_fields = [
87         "name",
88         "application__name",
89     ]
90 
91     def get_queryset(self):  # pragma: no cover
92         return Provider.objects.select_subclasses()
93 
94     @extend_schema(responses={200: TypeCreateSerializer(many=True)})
95     @action(detail=False, pagination_class=None, filter_backends=[])
96     def types(self, request: Request) -> Response:
97         """Get all creatable provider types"""
98         data = []
99         for subclass in all_subclasses(self.queryset.model):
100             subclass: Provider
101             if subclass._meta.abstract:
102                 continue
103             data.append(
104                 {
105                     "name": subclass._meta.verbose_name,
106                     "description": subclass.__doc__,
107                     "component": subclass().component,
108                     "model_name": subclass._meta.model_name,
109                 }
110             )
111         data.append(
112             {
113                 "name": _("SAML Provider from Metadata"),
114                 "description": _("Create a SAML Provider by importing its Metadata."),
115                 "component": "ak-provider-saml-import-form",
116                 "model_name": "",
117             }
118         )
119         return Response(TypeCreateSerializer(data, many=True).data)
120
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/authentik/core/api/providers.py b/authentik/core/api/providers.py
--- a/authentik/core/api/providers.py
+++ b/authentik/core/api/providers.py
@@ -1,4 +1,6 @@
 """Provider API Views"""
+from django.db.models import QuerySet
+from django.db.models.query import Q
 from django.utils.translation import gettext_lazy as _
 from django_filters.filters import BooleanFilter
 from django_filters.filterset import FilterSet
@@ -56,17 +58,22 @@
 
 
 class ProviderFilter(FilterSet):
-    """Filter for groups"""
+    """Filter for providers"""
 
-    application__isnull = BooleanFilter(
-        field_name="application",
-        lookup_expr="isnull",
-    )
+    application__isnull = BooleanFilter(method="filter_application__isnull")
     backchannel_only = BooleanFilter(
         method="filter_backchannel_only",
     )
 
-    def filter_backchannel_only(self, queryset, name, value):
+    def filter_application__isnull(self, queryset: QuerySet, name, value):
+        """Only return providers that are neither assigned to application,
+        both as provider or application provider"""
+        return queryset.filter(
+            Q(backchannel_application__isnull=value, is_backchannel=True)
+            | Q(application__isnull=value)
+        )
+
+    def filter_backchannel_only(self, queryset: QuerySet, name, value):
         """Only return backchannel providers"""
         return queryset.filter(is_backchannel=value)
 
diff --git a/authentik/providers/ldap/api.py b/authentik/providers/ldap/api.py
--- a/authentik/providers/ldap/api.py
+++ b/authentik/providers/ldap/api.py
@@ -1,4 +1,8 @@
 """LDAPProvider API Views"""
+from django.db.models import QuerySet
+from django.db.models.query import Q
+from django_filters.filters import BooleanFilter
+from django_filters.filterset import FilterSet
 from rest_framework.fields import CharField, ListField, SerializerMethodField
 from rest_framework.serializers import ModelSerializer
 from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
@@ -29,24 +33,41 @@
         extra_kwargs = ProviderSerializer.Meta.extra_kwargs
 
 
+class LDAPProviderFilter(FilterSet):
+    """LDAP Provider filters"""
+
+    application__isnull = BooleanFilter(method="filter_application__isnull")
+
+    def filter_application__isnull(self, queryset: QuerySet, name, value):
+        """Only return providers that are neither assigned to application,
+        both as provider or application provider"""
+        return queryset.filter(
+            Q(backchannel_application__isnull=value) | Q(application__isnull=value)
+        )
+
+    class Meta:
+        model = LDAPProvider
+        fields = {
+            "application": ["isnull"],
+            "name": ["iexact"],
+            "authorization_flow__slug": ["iexact"],
+            "base_dn": ["iexact"],
+            "search_group__group_uuid": ["iexact"],
+            "search_group__name": ["iexact"],
+            "certificate__kp_uuid": ["iexact"],
+            "certificate__name": ["iexact"],
+            "tls_server_name": ["iexact"],
+            "uid_start_number": ["iexact"],
+            "gid_start_number": ["iexact"],
+        }
+
+
 class LDAPProviderViewSet(UsedByMixin, ModelViewSet):
     """LDAPProvider Viewset"""
 
     queryset = LDAPProvider.objects.all()
     serializer_class = LDAPProviderSerializer
-    filterset_fields = {
-        "application": ["isnull"],
-        "name": ["iexact"],
-        "authorization_flow__slug": ["iexact"],
-        "base_dn": ["iexact"],
-        "search_group__group_uuid": ["iexact"],
-        "search_group__name": ["iexact"],
-        "certificate__kp_uuid": ["iexact"],
-        "certificate__name": ["iexact"],
-        "tls_server_name": ["iexact"],
-        "uid_start_number": ["iexact"],
-        "gid_start_number": ["iexact"],
-    }
+    filterset_class = LDAPProviderFilter
     search_fields = ["name"]
     ordering = ["name"]

{"golden_diff": "diff --git a/authentik/core/api/providers.py b/authentik/core/api/providers.py\n--- a/authentik/core/api/providers.py\n+++ b/authentik/core/api/providers.py\n@@ -1,4 +1,6 @@\n \"\"\"Provider API Views\"\"\"\n+from django.db.models import QuerySet\n+from django.db.models.query import Q\n from django.utils.translation import gettext_lazy as _\n from django_filters.filters import BooleanFilter\n from django_filters.filterset import FilterSet\n@@ -56,17 +58,22 @@\n \n \n class ProviderFilter(FilterSet):\n-    \"\"\"Filter for groups\"\"\"\n+    \"\"\"Filter for providers\"\"\"\n \n-    application__isnull = BooleanFilter(\n-        field_name=\"application\",\n-        lookup_expr=\"isnull\",\n-    )\n+    application__isnull = BooleanFilter(method=\"filter_application__isnull\")\n     backchannel_only = BooleanFilter(\n         method=\"filter_backchannel_only\",\n     )\n \n-    def filter_backchannel_only(self, queryset, name, value):\n+    def filter_application__isnull(self, queryset: QuerySet, name, value):\n+        \"\"\"Only return providers that are neither assigned to application,\n+        both as provider or application provider\"\"\"\n+        return queryset.filter(\n+            Q(backchannel_application__isnull=value, is_backchannel=True)\n+            | Q(application__isnull=value)\n+        )\n+\n+    def filter_backchannel_only(self, queryset: QuerySet, name, value):\n         \"\"\"Only return backchannel providers\"\"\"\n         return queryset.filter(is_backchannel=value)\n \ndiff --git a/authentik/providers/ldap/api.py b/authentik/providers/ldap/api.py\n--- a/authentik/providers/ldap/api.py\n+++ b/authentik/providers/ldap/api.py\n@@ -1,4 +1,8 @@\n \"\"\"LDAPProvider API Views\"\"\"\n+from django.db.models import QuerySet\n+from django.db.models.query import Q\n+from django_filters.filters import BooleanFilter\n+from django_filters.filterset import FilterSet\n from rest_framework.fields import CharField, ListField, SerializerMethodField\n from rest_framework.serializers import ModelSerializer\n from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet\n@@ -29,24 +33,41 @@\n         extra_kwargs = ProviderSerializer.Meta.extra_kwargs\n \n \n+class LDAPProviderFilter(FilterSet):\n+    \"\"\"LDAP Provider filters\"\"\"\n+\n+    application__isnull = BooleanFilter(method=\"filter_application__isnull\")\n+\n+    def filter_application__isnull(self, queryset: QuerySet, name, value):\n+        \"\"\"Only return providers that are neither assigned to application,\n+        both as provider or application provider\"\"\"\n+        return queryset.filter(\n+            Q(backchannel_application__isnull=value) | Q(application__isnull=value)\n+        )\n+\n+    class Meta:\n+        model = LDAPProvider\n+        fields = {\n+            \"application\": [\"isnull\"],\n+            \"name\": [\"iexact\"],\n+            \"authorization_flow__slug\": [\"iexact\"],\n+            \"base_dn\": [\"iexact\"],\n+            \"search_group__group_uuid\": [\"iexact\"],\n+            \"search_group__name\": [\"iexact\"],\n+            \"certificate__kp_uuid\": [\"iexact\"],\n+            \"certificate__name\": [\"iexact\"],\n+            \"tls_server_name\": [\"iexact\"],\n+            \"uid_start_number\": [\"iexact\"],\n+            \"gid_start_number\": [\"iexact\"],\n+        }\n+\n+\n class LDAPProviderViewSet(UsedByMixin, ModelViewSet):\n     \"\"\"LDAPProvider Viewset\"\"\"\n \n     queryset = LDAPProvider.objects.all()\n     serializer_class = LDAPProviderSerializer\n-    filterset_fields = {\n-        \"application\": [\"isnull\"],\n-        \"name\": [\"iexact\"],\n-        \"authorization_flow__slug\": [\"iexact\"],\n-        \"base_dn\": [\"iexact\"],\n-        \"search_group__group_uuid\": [\"iexact\"],\n-        \"search_group__name\": [\"iexact\"],\n-        \"certificate__kp_uuid\": [\"iexact\"],\n-        \"certificate__name\": [\"iexact\"],\n-        \"tls_server_name\": [\"iexact\"],\n-        \"uid_start_number\": [\"iexact\"],\n-        \"gid_start_number\": [\"iexact\"],\n-    }\n+    filterset_class = LDAPProviderFilter\n     search_fields = [\"name\"]\n     ordering = [\"name\"]\n", "issue": "Backchannel LDAP providers missing from outpost configuration page\n**Description**\r\nWhen creating an LDAP Provider, it will appear in the Outpost create/configuration page if it is assigned an application, but not if it's assigned as an application backchannel.\r\n\r\nThis means we're unable to associate an LDAP backchannel to an outpost.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n\r\n1. Create a demo Application and an LDAP Provider\r\n2. Assign the LDAP Provider as a _backchannel provider_ to the application.\r\n3. Attempt to create an LDAP outpost. Notice the LDAP provider does not appear on the selectable list.\r\n\r\n**Expected behavior**\r\nThe backchannel should appear the outposts \"applications\" list, so that it may be added to the outpost.\r\n\r\n**Version and Deployment (please complete the following information):**\r\n-   authentik version: 2023.5.2\r\n-   Deployment: docker-compose\r\n\n", "before_files": [{"content": "\"\"\"LDAPProvider API Views\"\"\"\nfrom rest_framework.fields import CharField, ListField, SerializerMethodField\nfrom rest_framework.serializers import ModelSerializer\nfrom rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet\n\nfrom authentik.core.api.providers import ProviderSerializer\nfrom authentik.core.api.used_by import UsedByMixin\nfrom authentik.providers.ldap.models import LDAPProvider\n\n\nclass LDAPProviderSerializer(ProviderSerializer):\n    \"\"\"LDAPProvider Serializer\"\"\"\n\n    outpost_set = ListField(child=CharField(), read_only=True, source=\"outpost_set.all\")\n\n    class Meta:\n        model = LDAPProvider\n        fields = ProviderSerializer.Meta.fields + [\n            \"base_dn\",\n            \"search_group\",\n            \"certificate\",\n            \"tls_server_name\",\n            \"uid_start_number\",\n            \"gid_start_number\",\n            \"outpost_set\",\n            \"search_mode\",\n            \"bind_mode\",\n        ]\n        extra_kwargs = ProviderSerializer.Meta.extra_kwargs\n\n\nclass LDAPProviderViewSet(UsedByMixin, ModelViewSet):\n    \"\"\"LDAPProvider Viewset\"\"\"\n\n    queryset = LDAPProvider.objects.all()\n    serializer_class = LDAPProviderSerializer\n    filterset_fields = {\n        \"application\": [\"isnull\"],\n        \"name\": [\"iexact\"],\n        \"authorization_flow__slug\": [\"iexact\"],\n        \"base_dn\": [\"iexact\"],\n        \"search_group__group_uuid\": [\"iexact\"],\n        \"search_group__name\": [\"iexact\"],\n        \"certificate__kp_uuid\": [\"iexact\"],\n        \"certificate__name\": [\"iexact\"],\n        \"tls_server_name\": [\"iexact\"],\n        \"uid_start_number\": [\"iexact\"],\n        \"gid_start_number\": [\"iexact\"],\n    }\n    search_fields = [\"name\"]\n    ordering = [\"name\"]\n\n\nclass LDAPOutpostConfigSerializer(ModelSerializer):\n    \"\"\"LDAPProvider Serializer\"\"\"\n\n    application_slug = SerializerMethodField()\n    bind_flow_slug = CharField(source=\"authorization_flow.slug\")\n\n    def get_application_slug(self, instance: LDAPProvider) -> str:\n        \"\"\"Prioritise backchannel slug over direct application slug\"\"\"\n        if instance.backchannel_application:\n            return instance.backchannel_application.slug\n        return instance.application.slug\n\n    class Meta:\n        model = LDAPProvider\n        fields = [\n            \"pk\",\n            \"name\",\n            \"base_dn\",\n            \"bind_flow_slug\",\n            \"application_slug\",\n            \"search_group\",\n            \"certificate\",\n            \"tls_server_name\",\n            \"uid_start_number\",\n            \"gid_start_number\",\n            \"search_mode\",\n            \"bind_mode\",\n        ]\n\n\nclass LDAPOutpostConfigViewSet(ReadOnlyModelViewSet):\n    \"\"\"LDAPProvider Viewset\"\"\"\n\n    queryset = LDAPProvider.objects.filter(application__isnull=False)\n    serializer_class = LDAPOutpostConfigSerializer\n    ordering = [\"name\"]\n    search_fields = [\"name\"]\n    filterset_fields = [\"name\"]\n", "path": "authentik/providers/ldap/api.py"}, {"content": "\"\"\"Provider API Views\"\"\"\nfrom django.utils.translation import gettext_lazy as _\nfrom django_filters.filters import BooleanFilter\nfrom django_filters.filterset import FilterSet\nfrom drf_spectacular.utils import extend_schema\nfrom rest_framework import mixins\nfrom rest_framework.decorators import action\nfrom rest_framework.fields import ReadOnlyField\nfrom rest_framework.request import Request\nfrom rest_framework.response import Response\nfrom rest_framework.serializers import ModelSerializer, SerializerMethodField\nfrom rest_framework.viewsets import GenericViewSet\n\nfrom authentik.core.api.used_by import UsedByMixin\nfrom authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer\nfrom authentik.core.models import Provider\nfrom authentik.lib.utils.reflection import all_subclasses\n\n\nclass ProviderSerializer(ModelSerializer, MetaNameSerializer):\n    \"\"\"Provider Serializer\"\"\"\n\n    assigned_application_slug = ReadOnlyField(source=\"application.slug\")\n    assigned_application_name = ReadOnlyField(source=\"application.name\")\n    assigned_backchannel_application_slug = ReadOnlyField(source=\"backchannel_application.slug\")\n    assigned_backchannel_application_name = ReadOnlyField(source=\"backchannel_application.name\")\n\n    component = SerializerMethodField()\n\n    def get_component(self, obj: Provider) -> str:  # pragma: no cover\n        \"\"\"Get object component so that we know how to edit the object\"\"\"\n        if obj.__class__ == Provider:\n            return \"\"\n        return obj.component\n\n    class Meta:\n        model = Provider\n        fields = [\n            \"pk\",\n            \"name\",\n            \"authentication_flow\",\n            \"authorization_flow\",\n            \"property_mappings\",\n            \"component\",\n            \"assigned_application_slug\",\n            \"assigned_application_name\",\n            \"assigned_backchannel_application_slug\",\n            \"assigned_backchannel_application_name\",\n            \"verbose_name\",\n            \"verbose_name_plural\",\n            \"meta_model_name\",\n        ]\n        extra_kwargs = {\n            \"authorization_flow\": {\"required\": True, \"allow_null\": False},\n        }\n\n\nclass ProviderFilter(FilterSet):\n    \"\"\"Filter for groups\"\"\"\n\n    application__isnull = BooleanFilter(\n        field_name=\"application\",\n        lookup_expr=\"isnull\",\n    )\n    backchannel_only = BooleanFilter(\n        method=\"filter_backchannel_only\",\n    )\n\n    def filter_backchannel_only(self, queryset, name, value):\n        \"\"\"Only return backchannel providers\"\"\"\n        return queryset.filter(is_backchannel=value)\n\n\nclass ProviderViewSet(\n    mixins.RetrieveModelMixin,\n    mixins.DestroyModelMixin,\n    UsedByMixin,\n    mixins.ListModelMixin,\n    GenericViewSet,\n):\n    \"\"\"Provider Viewset\"\"\"\n\n    queryset = Provider.objects.none()\n    serializer_class = ProviderSerializer\n    filterset_class = ProviderFilter\n    search_fields = [\n        \"name\",\n        \"application__name\",\n    ]\n\n    def get_queryset(self):  # pragma: no cover\n        return Provider.objects.select_subclasses()\n\n    @extend_schema(responses={200: TypeCreateSerializer(many=True)})\n    @action(detail=False, pagination_class=None, filter_backends=[])\n    def types(self, request: Request) -> Response:\n        \"\"\"Get all creatable provider types\"\"\"\n        data = []\n        for subclass in all_subclasses(self.queryset.model):\n            subclass: Provider\n            if subclass._meta.abstract:\n                continue\n            data.append(\n                {\n                    \"name\": subclass._meta.verbose_name,\n                    \"description\": subclass.__doc__,\n                    \"component\": subclass().component,\n                    \"model_name\": subclass._meta.model_name,\n                }\n            )\n        data.append(\n            {\n                \"name\": _(\"SAML Provider from Metadata\"),\n                \"description\": _(\"Create a SAML Provider by importing its Metadata.\"),\n                \"component\": \"ak-provider-saml-import-form\",\n                \"model_name\": \"\",\n            }\n        )\n        return Response(TypeCreateSerializer(data, many=True).data)\n", "path": "authentik/core/api/providers.py"}], "after_files": [{"content": "\"\"\"LDAPProvider API Views\"\"\"\nfrom django.db.models import QuerySet\nfrom django.db.models.query import Q\nfrom django_filters.filters import BooleanFilter\nfrom django_filters.filterset import FilterSet\nfrom rest_framework.fields import CharField, ListField, SerializerMethodField\nfrom rest_framework.serializers import ModelSerializer\nfrom rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet\n\nfrom authentik.core.api.providers import ProviderSerializer\nfrom authentik.core.api.used_by import UsedByMixin\nfrom authentik.providers.ldap.models import LDAPProvider\n\n\nclass LDAPProviderSerializer(ProviderSerializer):\n    \"\"\"LDAPProvider Serializer\"\"\"\n\n    outpost_set = ListField(child=CharField(), read_only=True, source=\"outpost_set.all\")\n\n    class Meta:\n        model = LDAPProvider\n        fields = ProviderSerializer.Meta.fields + [\n            \"base_dn\",\n            \"search_group\",\n            \"certificate\",\n            \"tls_server_name\",\n            \"uid_start_number\",\n            \"gid_start_number\",\n            \"outpost_set\",\n            \"search_mode\",\n            \"bind_mode\",\n        ]\n        extra_kwargs = ProviderSerializer.Meta.extra_kwargs\n\n\nclass LDAPProviderFilter(FilterSet):\n    \"\"\"LDAP Provider filters\"\"\"\n\n    application__isnull = BooleanFilter(method=\"filter_application__isnull\")\n\n    def filter_application__isnull(self, queryset: QuerySet, name, value):\n        \"\"\"Only return providers that are neither assigned to application,\n        both as provider or application provider\"\"\"\n        return queryset.filter(\n            Q(backchannel_application__isnull=value) | Q(application__isnull=value)\n        )\n\n    class Meta:\n        model = LDAPProvider\n        fields = {\n            \"application\": [\"isnull\"],\n            \"name\": [\"iexact\"],\n            \"authorization_flow__slug\": [\"iexact\"],\n            \"base_dn\": [\"iexact\"],\n            \"search_group__group_uuid\": [\"iexact\"],\n            \"search_group__name\": [\"iexact\"],\n            \"certificate__kp_uuid\": [\"iexact\"],\n            \"certificate__name\": [\"iexact\"],\n            \"tls_server_name\": [\"iexact\"],\n            \"uid_start_number\": [\"iexact\"],\n            \"gid_start_number\": [\"iexact\"],\n        }\n\n\nclass LDAPProviderViewSet(UsedByMixin, ModelViewSet):\n    \"\"\"LDAPProvider Viewset\"\"\"\n\n    queryset = LDAPProvider.objects.all()\n    serializer_class = LDAPProviderSerializer\n    filterset_class = LDAPProviderFilter\n    search_fields = [\"name\"]\n    ordering = [\"name\"]\n\n\nclass LDAPOutpostConfigSerializer(ModelSerializer):\n    \"\"\"LDAPProvider Serializer\"\"\"\n\n    application_slug = SerializerMethodField()\n    bind_flow_slug = CharField(source=\"authorization_flow.slug\")\n\n    def get_application_slug(self, instance: LDAPProvider) -> str:\n        \"\"\"Prioritise backchannel slug over direct application slug\"\"\"\n        if instance.backchannel_application:\n            return instance.backchannel_application.slug\n        return instance.application.slug\n\n    class Meta:\n        model = LDAPProvider\n        fields = [\n            \"pk\",\n            \"name\",\n            \"base_dn\",\n            \"bind_flow_slug\",\n            \"application_slug\",\n            \"search_group\",\n            \"certificate\",\n            \"tls_server_name\",\n            \"uid_start_number\",\n            \"gid_start_number\",\n            \"search_mode\",\n            \"bind_mode\",\n        ]\n\n\nclass LDAPOutpostConfigViewSet(ReadOnlyModelViewSet):\n    \"\"\"LDAPProvider Viewset\"\"\"\n\n    queryset = LDAPProvider.objects.filter(application__isnull=False)\n    serializer_class = LDAPOutpostConfigSerializer\n    ordering = [\"name\"]\n    search_fields = [\"name\"]\n    filterset_fields = [\"name\"]\n", "path": "authentik/providers/ldap/api.py"}, {"content": "\"\"\"Provider API Views\"\"\"\nfrom django.db.models import QuerySet\nfrom django.db.models.query import Q\nfrom django.utils.translation import gettext_lazy as _\nfrom django_filters.filters import BooleanFilter\nfrom django_filters.filterset import FilterSet\nfrom drf_spectacular.utils import extend_schema\nfrom rest_framework import mixins\nfrom rest_framework.decorators import action\nfrom rest_framework.fields import ReadOnlyField\nfrom rest_framework.request import Request\nfrom rest_framework.response import Response\nfrom rest_framework.serializers import ModelSerializer, SerializerMethodField\nfrom rest_framework.viewsets import GenericViewSet\n\nfrom authentik.core.api.used_by import UsedByMixin\nfrom authentik.core.api.utils import MetaNameSerializer, TypeCreateSerializer\nfrom authentik.core.models import Provider\nfrom authentik.lib.utils.reflection import all_subclasses\n\n\nclass ProviderSerializer(ModelSerializer, MetaNameSerializer):\n    \"\"\"Provider Serializer\"\"\"\n\n    assigned_application_slug = ReadOnlyField(source=\"application.slug\")\n    assigned_application_name = ReadOnlyField(source=\"application.name\")\n    assigned_backchannel_application_slug = ReadOnlyField(source=\"backchannel_application.slug\")\n    assigned_backchannel_application_name = ReadOnlyField(source=\"backchannel_application.name\")\n\n    component = SerializerMethodField()\n\n    def get_component(self, obj: Provider) -> str:  # pragma: no cover\n        \"\"\"Get object component so that we know how to edit the object\"\"\"\n        if obj.__class__ == Provider:\n            return \"\"\n        return obj.component\n\n    class Meta:\n        model = Provider\n        fields = [\n            \"pk\",\n            \"name\",\n            \"authentication_flow\",\n            \"authorization_flow\",\n            \"property_mappings\",\n            \"component\",\n            \"assigned_application_slug\",\n            \"assigned_application_name\",\n            \"assigned_backchannel_application_slug\",\n            \"assigned_backchannel_application_name\",\n            \"verbose_name\",\n            \"verbose_name_plural\",\n            \"meta_model_name\",\n        ]\n        extra_kwargs = {\n            \"authorization_flow\": {\"required\": True, \"allow_null\": False},\n        }\n\n\nclass ProviderFilter(FilterSet):\n    \"\"\"Filter for providers\"\"\"\n\n    application__isnull = BooleanFilter(method=\"filter_application__isnull\")\n    backchannel_only = BooleanFilter(\n        method=\"filter_backchannel_only\",\n    )\n\n    def filter_application__isnull(self, queryset: QuerySet, name, value):\n        \"\"\"Only return providers that are neither assigned to application,\n        both as provider or application provider\"\"\"\n        return queryset.filter(\n            Q(backchannel_application__isnull=value, is_backchannel=True)\n            | Q(application__isnull=value)\n        )\n\n    def filter_backchannel_only(self, queryset: QuerySet, name, value):\n        \"\"\"Only return backchannel providers\"\"\"\n        return queryset.filter(is_backchannel=value)\n\n\nclass ProviderViewSet(\n    mixins.RetrieveModelMixin,\n    mixins.DestroyModelMixin,\n    UsedByMixin,\n    mixins.ListModelMixin,\n    GenericViewSet,\n):\n    \"\"\"Provider Viewset\"\"\"\n\n    queryset = Provider.objects.none()\n    serializer_class = ProviderSerializer\n    filterset_class = ProviderFilter\n    search_fields = [\n        \"name\",\n        \"application__name\",\n    ]\n\n    def get_queryset(self):  # pragma: no cover\n        return Provider.objects.select_subclasses()\n\n    @extend_schema(responses={200: TypeCreateSerializer(many=True)})\n    @action(detail=False, pagination_class=None, filter_backends=[])\n    def types(self, request: Request) -> Response:\n        \"\"\"Get all creatable provider types\"\"\"\n        data = []\n        for subclass in all_subclasses(self.queryset.model):\n            subclass: Provider\n            if subclass._meta.abstract:\n                continue\n            data.append(\n                {\n                    \"name\": subclass._meta.verbose_name,\n                    \"description\": subclass.__doc__,\n                    \"component\": subclass().component,\n                    \"model_name\": subclass._meta.model_name,\n                }\n            )\n        data.append(\n            {\n                \"name\": _(\"SAML Provider from Metadata\"),\n                \"description\": _(\"Create a SAML Provider by importing its Metadata.\"),\n                \"component\": \"ak-provider-saml-import-form\",\n                \"model_name\": \"\",\n            }\n        )\n        return Response(TypeCreateSerializer(data, many=True).data)\n", "path": "authentik/core/api/providers.py"}]}