web: re-organise frontend and cleanup common code (#3572)

* fix repo in api client

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* web: re-organise files to match their interface

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* core: include version in script tags

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* cleanup maybe broken

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* revert rename

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* web: get rid of Client.ts

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* move more to common

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* more moving

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* format

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* unfuck files that vscode fucked, thanks

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* move more

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* finish moving (maybe)

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* ok more moving

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* fix more stuff that vs code destroyed

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* get rid "web" prefix for virtual package

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* fix locales

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* use custom base element

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* fix css file

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* don't run autoDetectLanguage when importing locale

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* fix circular dependencies

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

* web: fix build

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens L
2022-09-15 00:05:21 +02:00
committed by GitHub
parent 369440652c
commit 4a91a7d2e2
291 changed files with 2062 additions and 1921 deletions

View File

@ -0,0 +1,66 @@
import "@goauthentik/admin/applications/wizard/InitialApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/TypeApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/ldap/TypeLDAPApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/link/TypeLinkApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/oauth/TypeOAuthAPIApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/oauth/TypeOAuthApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/oauth/TypeOAuthCodeApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/oauth/TypeOAuthImplicitApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/proxy/TypeProxyApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/saml/TypeSAMLApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/saml/TypeSAMLConfigApplicationWizardPage";
import "@goauthentik/admin/applications/wizard/saml/TypeSAMLImportApplicationWizardPage";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/wizard/Wizard";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { CSSResult, TemplateResult, html } from "lit";
import { property } from "lit/decorators.js";
import AKGlobal from "@goauthentik/common/styles/authentik.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-application-wizard")
export class ApplicationWizard extends AKElement {
static get styles(): CSSResult[] {
return [PFBase, PFButton, AKGlobal, PFRadio];
}
@property({ type: Boolean })
open = false;
@property()
createText = t`Create`;
@property({ type: Boolean })
showButton = true;
@property({ attribute: false })
finalHandler: () => Promise<void> = () => {
return Promise.resolve();
};
render(): TemplateResult {
return html`
<ak-wizard
.open=${this.open}
.steps=${["ak-application-wizard-initial", "ak-application-wizard-type"]}
header=${t`New application`}
description=${t`Create a new application.`}
.finalHandler=${() => {
return this.finalHandler();
}}
>
${this.showButton
? html`<button slot="trigger" class="pf-c-button pf-m-primary">
${this.createText}
</button>`
: html``}
</ak-wizard>
`;
}
}

View File

@ -0,0 +1,73 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { convertToSlug } from "@goauthentik/common/utils";
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { TemplateResult, html } from "lit";
import { ApplicationRequest, CoreApi, Provider } from "@goauthentik/api";
@customElement("ak-application-wizard-initial")
export class InitialApplicationWizardPage extends WizardFormPage {
sidebarLabel = () => t`Application details`;
nextDataCallback = async (data: KeyUnknown): Promise<boolean> => {
const name = data.name as string;
let slug = convertToSlug(name || "");
// Check if an application with the generated slug already exists
const apps = await new CoreApi(DEFAULT_CONFIG).coreApplicationsList({
search: slug,
});
if (apps.results.filter((app) => app.slug == slug)) {
slug += "-1";
}
this.host.state["slug"] = slug;
this.host.state["name"] = name;
this.host.addActionBefore(t`Create application`, async (): Promise<boolean> => {
const req: ApplicationRequest = {
name: name || "",
slug: slug,
metaPublisher: data.metaPublisher as string,
metaDescription: data.metaDescription as string,
};
if ("provider" in this.host.state) {
req.provider = (this.host.state["provider"] as Provider).pk;
}
if ("link" in this.host.state) {
req.metaLaunchUrl = this.host.state["link"] as string;
}
this.host.state["app"] = await new CoreApi(DEFAULT_CONFIG).coreApplicationsCreate({
applicationRequest: req,
});
return true;
});
return true;
};
renderForm(): TemplateResult {
return html`
<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
<input type="text" value="" class="pf-c-form-control" required />
<p class="pf-c-form__helper-text">${t`Application's display Name.`}</p>
</ak-form-element-horizontal>
<ak-form-group ?expanded=${true}>
<span slot="header"> ${t`Additional UI settings`} </span>
<div slot="body" class="pf-c-form">
<ak-form-element-horizontal label=${t`Description`} name="metaDescription">
<textarea class="pf-c-form-control"></textarea>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${t`Publisher`} name="metaPublisher">
<input type="text" value="" class="pf-c-form-control" />
</ak-form-element-horizontal>
</div>
</ak-form-group>
</form>
`;
}
}

View File

@ -0,0 +1,81 @@
import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { CSSResult, TemplateResult, html } from "lit";
import AKGlobal from "@goauthentik/common/styles/authentik.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { TypeCreate } from "@goauthentik/api";
@customElement("ak-application-wizard-type")
export class TypeApplicationWizardPage extends WizardPage {
applicationTypes: TypeCreate[] = [
{
component: "ak-application-wizard-type-oauth",
name: t`OAuth2/OIDC`,
description: t`Modern applications, APIs and Single-page applications.`,
modelName: "",
},
{
component: "ak-application-wizard-type-saml",
name: t`SAML`,
description: t`XML-based SSO standard. Use this if your application only supports SAML.`,
modelName: "",
},
{
component: "ak-application-wizard-type-proxy",
name: t`Proxy`,
description: t`Legacy applications which don't natively support SSO.`,
modelName: "",
},
{
component: "ak-application-wizard-type-ldap",
name: t`LDAP`,
description: t`Provide an LDAP interface for applications and users to authenticate against.`,
modelName: "",
},
{
component: "ak-application-wizard-type-link",
name: t`Link`,
description: t`Provide an LDAP interface for applications and users to authenticate against.`,
modelName: "",
},
];
sidebarLabel = () => t`Authentication method`;
static get styles(): CSSResult[] {
return [PFBase, PFButton, PFForm, PFRadio, AKGlobal];
}
render(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
${this.applicationTypes.map((type) => {
return html`<div class="pf-c-radio">
<input
class="pf-c-radio__input"
type="radio"
name="type"
id=${type.component}
@change=${() => {
this.host.steps = [
"ak-application-wizard-initial",
"ak-application-wizard-type",
type.component,
];
this.host.isValid = true;
}}
/>
<label class="pf-c-radio__label" for=${type.component}>${type.name}</label>
<span class="pf-c-radio__description">${type.description}</span>
</div>`;
})}
</form>`;
}
}

View File

@ -0,0 +1,74 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { TemplateResult, html } from "lit";
import {
CoreApi,
FlowDesignationEnum,
FlowsApi,
LDAPProviderRequest,
ProvidersApi,
UserServiceAccountResponse,
} from "@goauthentik/api";
@customElement("ak-application-wizard-type-ldap")
export class TypeLDAPApplicationWizardPage extends WizardFormPage {
sidebarLabel = () => t`LDAP details`;
nextDataCallback = async (data: KeyUnknown): Promise<boolean> => {
let name = this.host.state["name"] as string;
// Check if a provider with the name already exists
const providers = await new ProvidersApi(DEFAULT_CONFIG).providersAllList({
search: name,
});
if (providers.results.filter((provider) => provider.name == name)) {
name += "-1";
}
this.host.addActionBefore(t`Create service account`, async (): Promise<boolean> => {
const serviceAccount = await new CoreApi(DEFAULT_CONFIG).coreUsersServiceAccountCreate({
userServiceAccountRequest: {
name: name,
createGroup: true,
},
});
this.host.state["serviceAccount"] = serviceAccount;
return true;
});
this.host.addActionBefore(t`Create provider`, async (): Promise<boolean> => {
// Get all flows and default to the implicit authorization
const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
designation: FlowDesignationEnum.Authorization,
ordering: "slug",
});
const serviceAccount = this.host.state["serviceAccount"] as UserServiceAccountResponse;
const req: LDAPProviderRequest = {
name: name,
authorizationFlow: flows.results[0].pk,
baseDn: data.baseDN as string,
searchGroup: serviceAccount.groupPk,
};
const provider = await new ProvidersApi(DEFAULT_CONFIG).providersLdapCreate({
lDAPProviderRequest: req,
});
this.host.state["provider"] = provider;
return true;
});
return true;
};
renderForm(): TemplateResult {
const domainParts = window.location.hostname.split(".");
const defaultBaseDN = domainParts.map((part) => `dc=${part}`).join(",");
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Base DN`} name="baseDN" ?required=${true}>
<input type="text" value="${defaultBaseDN}" class="pf-c-form-control" required />
</ak-form-element-horizontal>
</form> `;
}
}

View File

@ -0,0 +1,31 @@
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { TemplateResult, html } from "lit";
@customElement("ak-application-wizard-type-link")
export class TypeLinkApplicationWizardPage extends WizardFormPage {
sidebarLabel = () => t`Application Link`;
nextDataCallback = async (data: KeyUnknown): Promise<boolean> => {
this.host.state["link"] = data.link;
return true;
};
renderForm(): TemplateResult {
return html`
<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Link`} ?required=${true} name="link">
<input type="text" value="" class="pf-c-form-control" required />
<p class="pf-c-form__helper-text">
${t`URL which will be opened when a user clicks on the application.`}
</p>
</ak-form-element-horizontal>
</form>
`;
}
}

View File

@ -0,0 +1,33 @@
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { CSSResult, TemplateResult, html } from "lit";
import AKGlobal from "@goauthentik/common/styles/authentik.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
@customElement("ak-application-wizard-type-oauth-api")
export class TypeOAuthAPIApplicationWizardPage extends WizardPage {
static get styles(): CSSResult[] {
return [PFBase, PFButton, PFForm, PFRadio, AKGlobal];
}
sidebarLabel = () => t`Method details`;
render(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<p>
${t`This configuration can be used to authenticate to authentik with other APIs other otherwise programmatically.`}
</p>
<p>
${t`By default, all service accounts can authenticate as this application, as long as they have a valid token of the type app-password.`}
</p>
</form> `;
}
}

View File

@ -0,0 +1,78 @@
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { CSSResult, TemplateResult, html } from "lit";
import AKGlobal from "@goauthentik/common/styles/authentik.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { TypeCreate } from "@goauthentik/api";
@customElement("ak-application-wizard-type-oauth")
export class TypeOAuthApplicationWizardPage extends WizardPage {
applicationTypes: TypeCreate[] = [
{
component: "ak-application-wizard-type-oauth-code",
name: t`Web application`,
description: t`Applications which handle the authentication server-side (for example, Python, Go, Rust, Java, PHP)`,
modelName: "",
},
{
component: "ak-application-wizard-type-oauth-implicit",
name: t`Single-page applications`,
description: t`Single-page applications which handle authentication in the browser (for example, Javascript, Angular, React, Vue)`,
modelName: "",
},
{
component: "ak-application-wizard-type-oauth-implicit",
name: t`Native application`,
description: t`Applications which redirect users to a non-web callback (for example, Android, iOS)`,
modelName: "",
},
{
component: "ak-application-wizard-type-oauth-api",
name: t`API`,
description: t`Authentication without user interaction, or machine-to-machine authentication.`,
modelName: "",
},
];
static get styles(): CSSResult[] {
return [PFBase, PFButton, PFForm, PFRadio, AKGlobal];
}
sidebarLabel = () => t`Application type`;
render(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
${this.applicationTypes.map((type) => {
return html`<div class="pf-c-radio">
<input
class="pf-c-radio__input"
type="radio"
name="type"
id=${type.component}
@change=${() => {
this.host.steps = [
"ak-application-wizard-initial",
"ak-application-wizard-type",
"ak-application-wizard-type-oauth",
type.component,
];
this.host.state["oauth-type"] = type.component;
this.host.isValid = true;
}}
/>
<label class="pf-c-radio__label" for=${type.component}>${type.name}</label>
<span class="pf-c-radio__description">${type.description}</span>
</div>`;
})}
</form> `;
}
}

View File

@ -0,0 +1,72 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import "@goauthentik/elements/wizard/WizardFormPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { TemplateResult, html } from "lit";
import { ifDefined } from "lit/directives/if-defined.js";
import { until } from "lit/directives/until.js";
import {
ClientTypeEnum,
FlowsApi,
FlowsInstancesListDesignationEnum,
OAuth2ProviderRequest,
ProvidersApi,
} from "@goauthentik/api";
@customElement("ak-application-wizard-type-oauth-code")
export class TypeOAuthCodeApplicationWizardPage extends WizardFormPage {
sidebarLabel = () => t`Method details`;
nextDataCallback = async (data: KeyUnknown): Promise<boolean> => {
this.host.addActionBefore(t`Create provider`, async (): Promise<boolean> => {
const req: OAuth2ProviderRequest = {
name: this.host.state["name"] as string,
clientType: ClientTypeEnum.Confidential,
authorizationFlow: data.authorizationFlow as string,
};
const provider = await new ProvidersApi(DEFAULT_CONFIG).providersOauth2Create({
oAuth2ProviderRequest: req,
});
this.host.state["provider"] = provider;
return true;
});
return true;
};
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal
label=${t`Authorization flow`}
?required=${true}
name="authorizationFlow"
>
<select class="pf-c-form-control">
${until(
new FlowsApi(DEFAULT_CONFIG)
.flowsInstancesList({
ordering: "slug",
designation: FlowsInstancesListDesignationEnum.Authorization,
})
.then((flows) => {
return flows.results.map((flow) => {
return html`<option value=${ifDefined(flow.pk)}>
${flow.name} (${flow.slug})
</option>`;
});
}),
html`<option>${t`Loading...`}</option>`,
)}
</select>
<p class="pf-c-form__helper-text">
${t`Flow used when users access this application.`}
</p>
</ak-form-element-horizontal>
</form>`;
}
}

View File

@ -0,0 +1,16 @@
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { TemplateResult, html } from "lit";
@customElement("ak-application-wizard-type-oauth-implicit")
export class TypeOAuthImplicitApplicationWizardPage extends WizardFormPage {
sidebarLabel = () => t`Method details`;
render(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">some stuff idk</form> `;
}
}

View File

@ -0,0 +1,65 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { TemplateResult, html } from "lit";
import {
FlowDesignationEnum,
FlowsApi,
ProvidersApi,
ProxyProviderRequest,
} from "@goauthentik/api";
@customElement("ak-application-wizard-type-proxy")
export class TypeProxyApplicationWizardPage extends WizardFormPage {
sidebarLabel = () => t`Proxy details`;
nextDataCallback = async (data: KeyUnknown): Promise<boolean> => {
let name = this.host.state["name"] as string;
// Check if a provider with the name already exists
const providers = await new ProvidersApi(DEFAULT_CONFIG).providersAllList({
search: name,
});
if (providers.results.filter((provider) => provider.name == name)) {
name += "-1";
}
this.host.addActionBefore(t`Create provider`, async (): Promise<boolean> => {
// Get all flows and default to the implicit authorization
const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
designation: FlowDesignationEnum.Authorization,
ordering: "slug",
});
const req: ProxyProviderRequest = {
name: name,
authorizationFlow: flows.results[0].pk,
externalHost: data.externalHost as string,
};
const provider = await new ProvidersApi(DEFAULT_CONFIG).providersProxyCreate({
proxyProviderRequest: req,
});
this.host.state["provider"] = provider;
return true;
});
return true;
};
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal
label=${t`External domain`}
name="externalHost"
?required=${true}
>
<input type="text" value="" class="pf-c-form-control" required />
<p class="pf-c-form__helper-text">
${t`External domain you will be accessing the domain from.`}
</p>
</ak-form-element-horizontal>
</form> `;
}
}

View File

@ -0,0 +1,66 @@
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardPage } from "@goauthentik/elements/wizard/WizardPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { CSSResult, TemplateResult, html } from "lit";
import AKGlobal from "@goauthentik/common/styles/authentik.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFRadio from "@patternfly/patternfly/components/Radio/radio.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import { TypeCreate } from "@goauthentik/api";
@customElement("ak-application-wizard-type-saml")
export class TypeOAuthApplicationWizardPage extends WizardPage {
applicationTypes: TypeCreate[] = [
{
component: "ak-application-wizard-type-saml-import",
name: t`Import SAML Metadata`,
description: t`Import the metadata document of the applicaation you want to configure.`,
modelName: "",
},
{
component: "ak-application-wizard-type-saml-config",
name: t`Manual configuration`,
description: t`Manually configure SAML`,
modelName: "",
},
];
static get styles(): CSSResult[] {
return [PFBase, PFButton, PFForm, PFRadio, AKGlobal];
}
sidebarLabel = () => t`Application type`;
render(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
${this.applicationTypes.map((type) => {
return html`<div class="pf-c-radio">
<input
class="pf-c-radio__input"
type="radio"
name="type"
id=${type.component}
@change=${() => {
this.host.steps = [
"ak-application-wizard-initial",
"ak-application-wizard-type",
"ak-application-wizard-type-saml",
type.component,
];
this.host.state["saml-type"] = type.component;
this.host.isValid = true;
}}
/>
<label class="pf-c-radio__label" for=${type.component}>${type.name}</label>
<span class="pf-c-radio__description">${type.description}</span>
</div>`;
})}
</form> `;
}
}

View File

@ -0,0 +1,56 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { TemplateResult, html } from "lit";
import { FlowDesignationEnum, FlowsApi, ProvidersApi, SAMLProviderRequest } from "@goauthentik/api";
@customElement("ak-application-wizard-type-saml-config")
export class TypeSAMLApplicationWizardPage extends WizardFormPage {
sidebarLabel = () => t`SAML details`;
nextDataCallback = async (data: KeyUnknown): Promise<boolean> => {
let name = this.host.state["name"] as string;
// Check if a provider with the name already exists
const providers = await new ProvidersApi(DEFAULT_CONFIG).providersAllList({
search: name,
});
if (providers.results.filter((provider) => provider.name == name)) {
name += "-1";
}
this.host.addActionBefore(t`Create provider`, async (): Promise<boolean> => {
// Get all flows and default to the implicit authorization
const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
designation: FlowDesignationEnum.Authorization,
ordering: "slug",
});
const req: SAMLProviderRequest = {
name: name,
authorizationFlow: flows.results[0].pk,
acsUrl: data.acsUrl as string,
};
const provider = await new ProvidersApi(DEFAULT_CONFIG).providersSamlCreate({
sAMLProviderRequest: req,
});
this.host.state["provider"] = provider;
return true;
});
return true;
};
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`ACS URL`} name="acsUrl" ?required=${true}>
<input type="text" value="" class="pf-c-form-control" required />
<p class="pf-c-form__helper-text">
${t`URL that authentik will redirect back to after successful authentication.`}
</p>
</ak-form-element-horizontal>
</form> `;
}
}

View File

@ -0,0 +1,58 @@
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { KeyUnknown } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { WizardFormPage } from "@goauthentik/elements/wizard/WizardFormPage";
import { t } from "@lingui/macro";
import { customElement } from "@lit/reactive-element/decorators/custom-element.js";
import { TemplateResult, html } from "lit";
import {
FlowDesignationEnum,
FlowsApi,
ProvidersApi,
ProvidersSamlImportMetadataCreateRequest,
} from "@goauthentik/api";
@customElement("ak-application-wizard-type-saml-import")
export class TypeSAMLImportApplicationWizardPage extends WizardFormPage {
sidebarLabel = () => t`Import SAML metadata`;
nextDataCallback = async (data: KeyUnknown): Promise<boolean> => {
let name = this.host.state["name"] as string;
// Check if a provider with the name already exists
const providers = await new ProvidersApi(DEFAULT_CONFIG).providersAllList({
search: name,
});
if (providers.results.filter((provider) => provider.name == name)) {
name += "-1";
}
this.host.addActionBefore(t`Create provider`, async (): Promise<boolean> => {
// Get all flows and default to the implicit authorization
const flows = await new FlowsApi(DEFAULT_CONFIG).flowsInstancesList({
designation: FlowDesignationEnum.Authorization,
ordering: "slug",
});
const req: ProvidersSamlImportMetadataCreateRequest = {
name: name,
authorizationFlow: flows.results[0].slug,
file: data["metadata"] as Blob,
};
const provider = await new ProvidersApi(
DEFAULT_CONFIG,
).providersSamlImportMetadataCreate(req);
this.host.state["provider"] = provider;
return true;
});
return true;
};
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${t`Metadata`} name="metadata">
<input type="file" value="" class="pf-c-form-control" />
</ak-form-element-horizontal>
</form> `;
}
}