From 70fc4c0d88babc4b95e75e52c0d70f663feac867 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 2 Apr 2021 12:12:14 +0200 Subject: [PATCH] sources/ldap: migrate to web Signed-off-by: Jens Langhammer --- authentik/core/api/sources.py | 4 +- authentik/core/models.py | 5 + .../saml/templates/providers/saml/import.html | 13 - authentik/sources/ldap/forms.py | 60 ----- authentik/sources/ldap/models.py | 7 +- web/src/pages/sources/SourcesListPage.ts | 30 ++- web/src/pages/sources/ldap/LDAPSourceForm.ts | 230 ++++++++++++++++++ 7 files changed, 262 insertions(+), 87 deletions(-) delete mode 100644 authentik/providers/saml/templates/providers/saml/import.html delete mode 100644 authentik/sources/ldap/forms.py create mode 100644 web/src/pages/sources/ldap/LDAPSourceForm.ts diff --git a/authentik/core/api/sources.py b/authentik/core/api/sources.py index 94b31c92b..858e8b5b3 100644 --- a/authentik/core/api/sources.py +++ b/authentik/core/api/sources.py @@ -1,7 +1,6 @@ """Source API Views""" from typing import Iterable -from django.urls import reverse from drf_yasg.utils import swagger_auto_schema from rest_framework import mixins from rest_framework.decorators import action @@ -72,8 +71,7 @@ class SourceViewSet( { "name": verbose_name(subclass), "description": subclass.__doc__, - "link": reverse("authentik_admin:source-create") - + f"?type={subclass.__name__}", + "link": subclass().component, } ) return Response(TypeCreateSerializer(data, many=True).data) diff --git a/authentik/core/models.py b/authentik/core/models.py index 67a66386b..900573364 100644 --- a/authentik/core/models.py +++ b/authentik/core/models.py @@ -275,6 +275,11 @@ class Source(SerializerModel, PolicyBindingModel): objects = InheritanceManager() + @property + def component(self) -> str: + """Return component used to edit this object""" + raise NotImplementedError + @property def form(self) -> Type[ModelForm]: """Return Form class used to edit this object""" diff --git a/authentik/providers/saml/templates/providers/saml/import.html b/authentik/providers/saml/templates/providers/saml/import.html deleted file mode 100644 index d4c72334c..000000000 --- a/authentik/providers/saml/templates/providers/saml/import.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends base_template|default:"generic/form.html" %} - -{% load i18n %} - -{% block above_form %} -

-{% trans 'Import SAML Metadata' %} -

-{% endblock %} - -{% block action %} -{% trans 'Import Metadata' %} -{% endblock %} diff --git a/authentik/sources/ldap/forms.py b/authentik/sources/ldap/forms.py deleted file mode 100644 index 37c812730..000000000 --- a/authentik/sources/ldap/forms.py +++ /dev/null @@ -1,60 +0,0 @@ -"""authentik LDAP Forms""" - -from django import forms -from django.utils.translation import gettext_lazy as _ - -from authentik.sources.ldap.models import LDAPPropertyMapping, LDAPSource - - -class LDAPSourceForm(forms.ModelForm): - """LDAPSource Form""" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.fields["property_mappings"].queryset = LDAPPropertyMapping.objects.all() - self.fields[ - "property_mappings_group" - ].queryset = LDAPPropertyMapping.objects.all() - - class Meta: - - model = LDAPSource - fields = [ - # we don't use all common fields, as we don't use flows for this - "name", - "slug", - "enabled", - "policy_engine_mode", - # -- start of our custom fields - "server_uri", - "start_tls", - "bind_cn", - "bind_password", - "base_dn", - "sync_users", - "sync_users_password", - "sync_groups", - "property_mappings", - "property_mappings_group", - "additional_user_dn", - "additional_group_dn", - "user_object_filter", - "group_object_filter", - "group_membership_field", - "object_uniqueness_field", - "sync_parent_group", - ] - labels = {"property_mappings_group": _("Group property mappings")} - widgets = { - "name": forms.TextInput(), - "server_uri": forms.TextInput(), - "bind_cn": forms.TextInput(), - "bind_password": forms.TextInput(), - "base_dn": forms.TextInput(), - "additional_user_dn": forms.TextInput(), - "additional_group_dn": forms.TextInput(), - "user_object_filter": forms.TextInput(), - "group_object_filter": forms.TextInput(), - "group_membership_field": forms.TextInput(), - "object_uniqueness_field": forms.TextInput(), - } diff --git a/authentik/sources/ldap/models.py b/authentik/sources/ldap/models.py index bdf163bf9..bdea6abf0 100644 --- a/authentik/sources/ldap/models.py +++ b/authentik/sources/ldap/models.py @@ -2,7 +2,6 @@ from typing import Optional, Type from django.db import models -from django.forms import ModelForm from django.utils.translation import gettext_lazy as _ from ldap3 import ALL, Connection, Server from rest_framework.serializers import Serializer @@ -73,10 +72,8 @@ class LDAPSource(Source): ) @property - def form(self) -> Type[ModelForm]: - from authentik.sources.ldap.forms import LDAPSourceForm - - return LDAPSourceForm + def component(self) -> str: + return "ak-source-ldap-form" @property def serializer(self) -> Type[Serializer]: diff --git a/web/src/pages/sources/SourcesListPage.ts b/web/src/pages/sources/SourcesListPage.ts index 0f048133e..74a5a098c 100644 --- a/web/src/pages/sources/SourcesListPage.ts +++ b/web/src/pages/sources/SourcesListPage.ts @@ -8,11 +8,14 @@ import "../../elements/buttons/ModalButton"; import "../../elements/buttons/SpinnerButton"; import "../../elements/buttons/Dropdown"; import "../../elements/forms/DeleteForm"; +import "../../elements/forms/ModalForm"; +import "../../elements/forms/ProxyForm"; import { until } from "lit-html/directives/until"; import { PAGE_SIZE } from "../../constants"; import { Source, SourcesApi } from "authentik-api"; import { DEFAULT_CONFIG } from "../../api/Config"; -import { AdminURLManager } from "../../api/legacy"; +import { ifDefined } from "lit-html/directives/if-defined"; +import "./ldap/LDAPSourceForm"; @customElement("ak-source-list") export class SourceListPage extends TablePage { @@ -57,12 +60,27 @@ export class SourceListPage extends TablePage { `, html`${item.verboseName}`, html` - - + + + ${gettext("Update")} + + + ${gettext(`Update ${item.verboseName}`)} + + + + + { + + set sourceSlug(value: string) { + new SourcesApi(DEFAULT_CONFIG).sourcesLdapRead({ + slug: value, + }).then(source => { + this.source = source; + }); + } + + @property({attribute: false}) + source?: LDAPSource; + + getSuccessMessage(): string { + if (this.source) { + return gettext("Successfully updated source."); + } else { + return gettext("Successfully created source."); + } + } + + send = (data: LDAPSource): Promise => { + if (this.source) { + return new SourcesApi(DEFAULT_CONFIG).sourcesLdapUpdate({ + slug: this.source.slug, + data: data + }); + } else { + return new SourcesApi(DEFAULT_CONFIG).sourcesLdapCreate({ + data: data + }); + } + }; + + renderForm(): TemplateResult { + return html`
+ + + + + + + +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ + + ${gettext("Connection settings")} + +
+ + + + +
+ + +
+
+ + + + + + + + + +
+
+ + + ${gettext("Advanced settings")} + +
+ + +

${gettext("Property mappings used to user creation.")}

+

${gettext("Hold control/command to select multiple items.")}

+
+ + +

${gettext("Property mappings used to group creation.")}

+

${gettext("Hold control/command to select multiple items.")}

+
+ + +

${gettext("Additional user DN, prepended to the Base DN.")}

+
+ + +

${gettext("Additional group DN, prepended to the Base DN.")}

+
+ + +

${gettext("Consider Objects matching this filter to be Users.")}

+
+ + +

${gettext("Consider Objects matching this filter to be Groups.")}

+
+ + +

${gettext("Field which contains members of a group.")}

+
+ + +

${gettext("Field which contains a unique Identifier.")}

+
+
+
+
`; + } + +}