From d741ed430a9ea27dc6b01018948ba64072b3d3fb Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 26 Apr 2021 12:03:44 +0200 Subject: [PATCH] web/admin: add UI for LDAP Provider Signed-off-by: Jens Langhammer --- authentik/providers/ldap/models.py | 10 +- web/src/pages/providers/ProviderListPage.ts | 1 + .../pages/providers/ldap/LDAPProviderForm.ts | 90 ++++++++++++ .../providers/ldap/LDAPProviderViewPage.ts | 129 ++++++++++++++++++ 4 files changed, 227 insertions(+), 3 deletions(-) create mode 100644 web/src/pages/providers/ldap/LDAPProviderForm.ts create mode 100644 web/src/pages/providers/ldap/LDAPProviderViewPage.ts diff --git a/authentik/providers/ldap/models.py b/authentik/providers/ldap/models.py index 594bd020e..8b94ad254 100644 --- a/authentik/providers/ldap/models.py +++ b/authentik/providers/ldap/models.py @@ -1,5 +1,5 @@ """LDAP Provider""" -from typing import Optional, Type +from typing import Iterable, Optional, Type from django.db import models from django.utils.translation import gettext_lazy as _ @@ -7,10 +7,11 @@ from rest_framework.serializers import Serializer from authentik.core.models import Provider from authentik.flows.models import Flow +from authentik.outposts.models import OutpostModel -class LDAPProvider(Provider): - """LDAP Provider""" +class LDAPProvider(OutpostModel, Provider): + """Allow applications to authenticate against authentik's users using LDAP.""" base_dn = models.TextField( default="DC=ldap,DC=goauthentik,DC=io", @@ -45,6 +46,9 @@ class LDAPProvider(Provider): def __str__(self): return f"LDAP Provider {self.name}" + def get_required_objects(self) -> Iterable[models.Model]: + return [self] + class Meta: verbose_name = _("LDAP Provider") diff --git a/web/src/pages/providers/ProviderListPage.ts b/web/src/pages/providers/ProviderListPage.ts index 000cfe211..c92011e21 100644 --- a/web/src/pages/providers/ProviderListPage.ts +++ b/web/src/pages/providers/ProviderListPage.ts @@ -8,6 +8,7 @@ import "../../elements/buttons/Dropdown"; import "../../elements/forms/DeleteForm"; import "../../elements/forms/ModalForm"; import "../../elements/forms/ProxyForm"; +import "./ldap/LDAPProviderForm"; import "./oauth2/OAuth2ProviderForm"; import "./proxy/ProxyProviderForm"; import "./saml/SAMLProviderForm"; diff --git a/web/src/pages/providers/ldap/LDAPProviderForm.ts b/web/src/pages/providers/ldap/LDAPProviderForm.ts new file mode 100644 index 000000000..e9d815ec5 --- /dev/null +++ b/web/src/pages/providers/ldap/LDAPProviderForm.ts @@ -0,0 +1,90 @@ +import { CryptoApi, FlowDesignationEnum, FlowsApi, ProvidersApi, LDAPProvider } from "authentik-api"; +import { t } from "@lingui/macro"; +import { customElement, property } from "lit-element"; +import { html, TemplateResult } from "lit-html"; +import { DEFAULT_CONFIG } from "../../../api/Config"; +import { Form } from "../../../elements/forms/Form"; +import { until } from "lit-html/directives/until"; +import { ifDefined } from "lit-html/directives/if-defined"; +import "../../../elements/forms/HorizontalFormElement"; +import "../../../elements/forms/FormGroup"; +import { first } from "../../../utils"; + +@customElement("ak-provider-ldap-form") +export class LDAPProviderFormPage extends Form { + + set providerUUID(value: number) { + new ProvidersApi(DEFAULT_CONFIG).providersLdapRead({ + id: value, + }).then(provider => { + this.provider = provider; + }); + } + + @property({attribute: false}) + provider?: LDAPProvider; + + getSuccessMessage(): string { + if (this.provider) { + return t`Successfully updated provider.`; + } else { + return t`Successfully created provider.`; + } + } + + send = (data: LDAPProvider): Promise => { + if (this.provider) { + return new ProvidersApi(DEFAULT_CONFIG).providersLdapUpdate({ + id: this.provider.pk || 0, + data: data + }); + } else { + return new ProvidersApi(DEFAULT_CONFIG).providersLdapCreate({ + data: data + }); + } + }; + + renderForm(): TemplateResult { + return html`
+ + + + + +

${t`Flow used for users to authenticate. Currently only identification and password stages are supported.`}

+
+ + + + ${t`Protocol settings`} + +
+ + +

${t`LDAP DN under which bind requests and search requests can be made.`}

+
+
+
+
`; + } + +} diff --git a/web/src/pages/providers/ldap/LDAPProviderViewPage.ts b/web/src/pages/providers/ldap/LDAPProviderViewPage.ts new file mode 100644 index 000000000..e8bc97667 --- /dev/null +++ b/web/src/pages/providers/ldap/LDAPProviderViewPage.ts @@ -0,0 +1,129 @@ +import { t } from "@lingui/macro"; +import { CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element"; +import PFButton from "@patternfly/patternfly/components/Button/button.css"; +import PFPage from "@patternfly/patternfly/components/Page/page.css"; +import PFContent from "@patternfly/patternfly/components/Content/content.css"; +import PFGallery from "@patternfly/patternfly/layouts/Gallery/gallery.css"; +import PFCard from "@patternfly/patternfly/components/Card/card.css"; +import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; +import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; +import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; +import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css"; +import PFBase from "@patternfly/patternfly/patternfly-base.css"; +import AKGlobal from "../../../authentik.css"; + +import "../../../elements/buttons/ModalButton"; +import "../../../elements/buttons/SpinnerButton"; +import "../../../elements/CodeMirror"; +import "../../../elements/Tabs"; +import "../../../elements/events/ObjectChangelog"; +import "../RelatedApplicationButton"; +import "./LDAPProviderForm"; +import { ProvidersApi, LDAPProvider } from "authentik-api"; +import { DEFAULT_CONFIG } from "../../../api/Config"; +import { EVENT_REFRESH } from "../../../constants"; + +@customElement("ak-provider-ldap-view") +export class LDAPProviderViewPage extends LitElement { + + @property() + set args(value: { [key: string]: number }) { + this.providerID = value.id; + } + + @property({type: Number}) + set providerID(value: number) { + new ProvidersApi(DEFAULT_CONFIG).providersLdapRead({ + id: value, + }).then((prov) => (this.provider = prov)); + } + + @property({ attribute: false }) + provider?: LDAPProvider; + + static get styles(): CSSResult[] { + return [PFBase, PFButton, PFPage, PFFlex, PFDisplay, PFGallery, PFContent, PFCard, PFDescriptionList, PFSizing, AKGlobal]; + } + + constructor() { + super(); + this.addEventListener(EVENT_REFRESH, () => { + if (!this.provider?.pk) return; + this.providerID = this.provider?.pk; + }); + } + + render(): TemplateResult { + if (!this.provider) { + return html``; + } + return html` +
+
+
+
+
+
+
+
+ ${t`Name`} +
+
+
${this.provider.name}
+
+
+
+
+ ${t`Assigned to application`} +
+
+
+ +
+
+
+
+
+ ${t`Base DN`} +
+
+
${this.provider.baseDn}
+
+
+
+
+ +
+
+
+
+
+
+
+ + +
+
+
+
`; + } +}