From 07702afe6831928cbf00ec41d23382fb4c47c2b9 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Fri, 2 Apr 2021 13:12:31 +0200 Subject: [PATCH] sources/saml: migrate to web Signed-off-by: Jens Langhammer --- authentik/sources/saml/forms.py | 63 ----- authentik/sources/saml/models.py | 7 +- web/src/pages/sources/SourcesListPage.ts | 21 +- web/src/pages/sources/saml/SAMLSourceForm.ts | 283 +++++++++++++++++++ 4 files changed, 301 insertions(+), 73 deletions(-) delete mode 100644 authentik/sources/saml/forms.py create mode 100644 web/src/pages/sources/saml/SAMLSourceForm.ts diff --git a/authentik/sources/saml/forms.py b/authentik/sources/saml/forms.py deleted file mode 100644 index 0a4773b3a..000000000 --- a/authentik/sources/saml/forms.py +++ /dev/null @@ -1,63 +0,0 @@ -"""authentik SAML SP Forms""" - -from django import forms -from django.utils.translation import gettext_lazy as _ - -from authentik.crypto.models import CertificateKeyPair -from authentik.flows.models import Flow, FlowDesignation -from authentik.sources.saml.models import SAMLSource - - -class SAMLSourceForm(forms.ModelForm): - """SAML Provider form""" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - self.fields["pre_authentication_flow"].queryset = Flow.objects.filter( - designation=FlowDesignation.STAGE_CONFIGURATION - ) - self.fields["authentication_flow"].queryset = Flow.objects.filter( - designation=FlowDesignation.AUTHENTICATION - ) - self.fields["enrollment_flow"].queryset = Flow.objects.filter( - designation=FlowDesignation.ENROLLMENT - ) - self.fields["signing_kp"].queryset = CertificateKeyPair.objects.filter( - certificate_data__isnull=False, - key_data__isnull=False, - ) - - class Meta: - - model = SAMLSource - fields = [ - "name", - "slug", - "enabled", - "policy_engine_mode", - "pre_authentication_flow", - "authentication_flow", - "enrollment_flow", - "issuer", - "sso_url", - "slo_url", - "binding_type", - "name_id_policy", - "allow_idp_initiated", - "signing_kp", - "digest_algorithm", - "signature_algorithm", - "temporary_user_delete_after", - ] - widgets = { - "name": forms.TextInput(), - "issuer": forms.TextInput(), - "sso_url": forms.TextInput(), - "slo_url": forms.TextInput(), - "temporary_user_delete_after": forms.TextInput(), - } - labels = { - "name_id_policy": _("Name ID Policy"), - "allow_idp_initiated": _("Allow IDP-initiated logins"), - } diff --git a/authentik/sources/saml/models.py b/authentik/sources/saml/models.py index 64f2b3f63..d35685aac 100644 --- a/authentik/sources/saml/models.py +++ b/authentik/sources/saml/models.py @@ -2,7 +2,6 @@ from typing import Type from django.db import models -from django.forms import ModelForm from django.http import HttpRequest from django.urls import reverse from django.utils.translation import gettext_lazy as _ @@ -146,10 +145,8 @@ class SAMLSource(Source): ) @property - def form(self) -> Type[ModelForm]: - from authentik.sources.saml.forms import SAMLSourceForm - - return SAMLSourceForm + def component(self) -> str: + return "ak-source-saml-form" @property def serializer(self) -> Type[Serializer]: diff --git a/web/src/pages/sources/SourcesListPage.ts b/web/src/pages/sources/SourcesListPage.ts index 74a5a098c..e4f019893 100644 --- a/web/src/pages/sources/SourcesListPage.ts +++ b/web/src/pages/sources/SourcesListPage.ts @@ -4,7 +4,6 @@ import { AKResponse } from "../../api/Client"; import { TableColumn } from "../../elements/table/Table"; import { TablePage } from "../../elements/table/TablePage"; -import "../../elements/buttons/ModalButton"; import "../../elements/buttons/SpinnerButton"; import "../../elements/buttons/Dropdown"; import "../../elements/forms/DeleteForm"; @@ -16,6 +15,7 @@ import { Source, SourcesApi } from "authentik-api"; import { DEFAULT_CONFIG } from "../../api/Config"; import { ifDefined } from "lit-html/directives/if-defined"; import "./ldap/LDAPSourceForm"; +import "./saml/SAMLSourceForm"; @customElement("ak-source-list") export class SourceListPage extends TablePage { @@ -75,6 +75,7 @@ export class SourceListPage extends TablePage { type=${ifDefined(item.objectType)} .typeMap=${{ "ldap": "ak-source-ldap-form", + "saml": "ak-source-saml-form", }}> -
- + `; }); }), html``)} diff --git a/web/src/pages/sources/saml/SAMLSourceForm.ts b/web/src/pages/sources/saml/SAMLSourceForm.ts new file mode 100644 index 000000000..997dd094e --- /dev/null +++ b/web/src/pages/sources/saml/SAMLSourceForm.ts @@ -0,0 +1,283 @@ +import { SAMLSource, SourcesApi, SAMLSourceBindingTypeEnum, SAMLSourceNameIdPolicyEnum, CryptoApi, SAMLSourceDigestAlgorithmEnum, SAMLSourceSignatureAlgorithmEnum, FlowsApi, FlowDesignationEnum } from "authentik-api"; +import { gettext } from "django"; +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 "../../../elements/forms/FormGroup"; +import "../../../elements/forms/HorizontalFormElement"; +import { ifDefined } from "lit-html/directives/if-defined"; +import { until } from "lit-html/directives/until"; + +@customElement("ak-source-saml-form") +export class SAMLSourceForm extends Form { + + set sourceSlug(value: string) { + new SourcesApi(DEFAULT_CONFIG).sourcesSamlRead({ + slug: value, + }).then(source => { + this.source = source; + }); + } + + @property({attribute: false}) + source?: SAMLSource; + + getSuccessMessage(): string { + if (this.source) { + return gettext("Successfully updated source."); + } else { + return gettext("Successfully created source."); + } + } + + send = (data: SAMLSource): Promise => { + if (this.source) { + return new SourcesApi(DEFAULT_CONFIG).sourcesSamlUpdate({ + slug: this.source.slug, + data: data + }); + } else { + return new SourcesApi(DEFAULT_CONFIG).sourcesSamlCreate({ + data: data + }); + } + }; + + renderForm(): TemplateResult { + return html`
+ + + + + + + +
+ + +
+
+ + + + ${gettext("Protocol settings")} + +
+ + +

${gettext("URL that the initial Login request is sent to.")}

+
+ + +

${gettext("Optional URL if the IDP supports Single-Logout.")}

+
+ + +

${gettext("Also known as Entity ID. Defaults the Metadata URL.")}

+
+ + + + + +

${gettext("Keypair which is used to sign outgoing requests. Leave empty to disable signing.")}

+
+
+
+ + + ${gettext("Advanced protocol settings")} + +
+ +
+ + +
+

${gettext("Allows authentication flows initiated by the IdP. This can be a security risk, as no validation of the request ID is done.")}

+
+ + + + + +

${gettext("Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. (Format: hours=1;minutes=2;seconds=3).")}

+
+ + + + + + +
+
+ + + ${gettext("Flow settings")} + +
+ + +

${gettext("Flow used before authentication.")}

+
+ + +

${gettext("Flow to use when authenticating existing users.")}

+
+ + +

${gettext("Flow to use when enrolling new users.")}

+
+
+
+
`; + } + +}