From fe17f116ed294f7b3ab0b24bf9270f32126ecb8e Mon Sep 17 00:00:00 2001 From: Ken Sternberg Date: Mon, 7 Aug 2023 15:56:12 -0700 Subject: [PATCH] web: Tactical change. Put all the variants on the second page; it's a longer list, but it's also easier to manage than all those required sub-options. --- ...rd-authentication-method-choice.choices.ts | 35 +++++ ...ion-wizard-authentication-method-choice.ts | 41 +---- ...-proxy.ts => AuthenticationByProxyPage.ts} | 143 +++--------------- ...wizard-authentication-for-reverse-proxy.ts | 49 ++++++ ...authentication-for-single-forward-proxy.ts | 36 +++++ .../stories/ak-application-wizard.stories.ts | 25 ++- 6 files changed, 163 insertions(+), 166 deletions(-) create mode 100644 web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.choices.ts rename web/src/admin/applications/wizard/proxy/{ak-application-wizard-authentication-by-proxy.ts => AuthenticationByProxyPage.ts} (66%) create mode 100644 web/src/admin/applications/wizard/proxy/ak-application-wizard-authentication-for-reverse-proxy.ts create mode 100644 web/src/admin/applications/wizard/proxy/ak-application-wizard-authentication-for-single-forward-proxy.ts diff --git a/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.choices.ts b/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.choices.ts new file mode 100644 index 000000000..46e33aab8 --- /dev/null +++ b/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.choices.ts @@ -0,0 +1,35 @@ +import { msg } from "@lit/localize"; + +import type { TypeCreate } from "@goauthentik/api"; + +type ProviderType = [string, string, string] | [string, string, string, ProviderType[]]; + +type ProviderOption = TypeCreate & { + children?: TypeCreate[]; +}; + +// prettier-ignore +const _providerTypesTable: ProviderType[] = [ + ["oauth2provider", msg("OAuth2/OpenID"), msg("Modern applications, APIs and Single-page applications.")], + ["ldapprovider", msg("LDAP"), msg("Provide an LDAP interface for applications and users to authenticate against.")], + ["proxyprovider-proxy", msg("Transparent Reverse Proxy"), msg("For transparent reverse proxies with required authentication")], + ["proxyprovider-forwardsingle", msg("Forward Single Proxy"), msg("For nginx's auth_request or traefix's forwardAuth")], + ["radiusprovider", msg("Radius"), msg("Allow applications to authenticate against authentik's users using Radius.")], + ["samlprovider-manual", msg("SAML Manual configuration"), msg("Configure SAML provider manually")], + ["samlprovider-import", msg("SAML Import Configuration"), msg("Create a SAML provider by importing its metadata")], + ["scimprovider", msg("SCIM Provider"), msg("SCIM 2.0 provider to create users and groups in external applications")] +]; + +function mapProviders([modelName, name, description, children]: ProviderType): ProviderOption { + return { + modelName, + name, + description, + component: "", + ...(children ? { children: children.map(mapProviders) } : {}), + }; +} + +export const providerTypesList = _providerTypesTable.map(mapProviders); + +export default providerTypesList; diff --git a/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.ts b/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.ts index 481fdb5cd..82ec4ecfb 100644 --- a/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.ts +++ b/web/src/admin/applications/wizard/ak-application-wizard-authentication-method-choice.ts @@ -1,4 +1,3 @@ -import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import "@goauthentik/components/ak-radio-input"; import "@goauthentik/components/ak-switch-input"; import "@goauthentik/components/ak-text-input"; @@ -9,73 +8,45 @@ import "@goauthentik/elements/forms/HorizontalFormElement"; import { msg } from "@lit/localize"; import { customElement } from "@lit/reactive-element/decorators/custom-element.js"; import { html } from "lit"; -import { state } from "lit/decorators.js"; import { map } from "lit/directives/map.js"; -import { ProvidersApi } from "@goauthentik/api"; import type { TypeCreate } from "@goauthentik/api"; import ApplicationWizardPageBase from "./ApplicationWizardPageBase"; - -// The provider description that comes from the server is fairly specific and not internationalized. -// We provide alternative descriptions that use the phrase 'authentication method' instead, and make -// it available to i18n. -// -// prettier-ignore -const alternativeDescription = new Map([ - ["oauth2provider", msg("Modern applications, APIs and Single-page applications.")], - ["samlprovider", msg("XML-based SSO standard. Use this if your application only supports SAML.")], - ["proxyprovider", msg("Legacy applications which don't natively support SSO.")], - ["ldapprovider", msg("Provide an LDAP interface for applications and users to authenticate against.")] -]); +import providerTypesList from "./ak-application-wizard-authentication-method-choice.choices"; @customElement("ak-application-wizard-authentication-method-choice") export class ApplicationWizardAuthenticationMethodChoice extends ApplicationWizardPageBase { - @state() - providerTypes: TypeCreate[] = []; - constructor() { super(); this.handleChoice = this.handleChoice.bind(this); this.renderProvider = this.renderProvider.bind(this); - // If the provider doesn't supply a model to which to send our initialization, the user will - // have to use the older provider path. - new ProvidersApi(DEFAULT_CONFIG).providersAllTypesList().then((types) => { - this.providerTypes = types.filter(({ modelName }) => modelName.trim() !== ""); - }); } handleChoice(ev: InputEvent) { const target = ev.target as HTMLInputElement; - this.dispatchWizardUpdate({ providerType: target.value }); } renderProvider(type: TypeCreate) { - const description = alternativeDescription.has(type.modelName) - ? alternativeDescription.get(type.modelName) - : type.description; - - const label = type.name.replace(/\s+Provider/, ""); - return html`
- - ${description} + + ${type.description}
`; } render() { - return this.providerTypes.length > 0 + return providerTypesList.length > 0 ? html`
- ${map(this.providerTypes, this.renderProvider)} + ${map(providerTypesList, this.renderProvider)}
` : html``; } diff --git a/web/src/admin/applications/wizard/proxy/ak-application-wizard-authentication-by-proxy.ts b/web/src/admin/applications/wizard/proxy/AuthenticationByProxyPage.ts similarity index 66% rename from web/src/admin/applications/wizard/proxy/ak-application-wizard-authentication-by-proxy.ts rename to web/src/admin/applications/wizard/proxy/AuthenticationByProxyPage.ts index ea7df221e..00d82b25a 100644 --- a/web/src/admin/applications/wizard/proxy/ak-application-wizard-authentication-by-proxy.ts +++ b/web/src/admin/applications/wizard/proxy/AuthenticationByProxyPage.ts @@ -1,16 +1,15 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; -import "@goauthentik/elements/forms/HorizontalFormElement"; - -import { msg } from "@lit/localize"; -import { customElement, state } from "@lit/reactive-element/decorators.js"; -import { TemplateResult, html } from "lit"; -import { ifDefined } from "lit/directives/if-defined.js"; - import "@goauthentik/components/ak-switch-input"; import "@goauthentik/components/ak-text-input"; import "@goauthentik/components/ak-textarea-input"; import "@goauthentik/components/ak-toggle-group"; +import "@goauthentik/elements/forms/HorizontalFormElement"; + +import { msg } from "@lit/localize"; +import { state } from "@lit/reactive-element/decorators.js"; +import { TemplateResult, html, nothing } from "lit"; +import { ifDefined } from "lit/directives/if-defined.js"; import { FlowsInstancesListDesignationEnum, @@ -24,7 +23,8 @@ import { import ApplicationWizardPageBase from "../ApplicationWizardPageBase"; -@customElement("ak-application-wizard-authentication-by-proxy") +type MaybeTemplateResult = TemplateResult | typeof nothing; + export class AkTypeProxyApplicationWizardPage extends ApplicationWizardPageBase { constructor() { super(); @@ -72,6 +72,14 @@ export class AkTypeProxyApplicationWizardPage extends ApplicationWizardPageBase return this.wizard.provider as ProxyProvider; } + renderModeDescription(): MaybeTemplateResult { + return nothing; + } + + renderProxyMode() { + return html`

This space intentionally left blank

`; + } + renderHttpBasic(): TemplateResult { return html``; } - renderModeSelector(): TemplateResult { - const setMode = (ev: CustomEvent<{ value: ProxyMode }>) => { - this.mode = ev.detail.value; - }; - - // prettier-ignore - return html` - - - - - - `; - } - - renderProxyModeProxy() { - return html`

- ${msg( - "This provider will behave like a transparent reverse-proxy, except requests must be authenticated. If your upstream application uses HTTPS, make sure to connect to the outpost using HTTPS as well.", - )} -

- - - - `; - } - - renderProxyModeForwardSingle() { - return html`

- ${msg( - "Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a manged outpost, this is done for you).", - )} -

- `; - } - - renderProxyModeForwardDomain() { - return html`

- ${msg( - "Use this provider with nginx's auth_request or traefik's forwardAuth. Only a single provider is required per root domain. You can't do per-application authorization, but you don't have to create a provider for each application.", - )} -

-
- ${msg("An example setup can look like this:")} -
    -
  • ${msg("authentik running on auth.example.com")}
  • -
  • ${msg("app1 running on app1.example.com")}
  • -
- ${msg( - "In this case, you'd set the Authentication URL to auth.example.com and Cookie domain to example.com.", - )} -
- - `; - } - - renderSettings() { - switch (this.mode) { - case ProxyMode.Proxy: - return this.renderProxyModeProxy(); - case ProxyMode.ForwardSingle: - return this.renderProxyModeForwardSingle(); - case ProxyMode.ForwardDomain: - return this.renderProxyModeForwardDomain(); - case ProxyMode.UnknownDefaultOpenApi: - return html`

${msg("Unknown proxy mode")}

`; - } - } - render() { return html`
+ ${this.renderModeDescription()} -
-
${this.renderModeSelector()}
- -
+ + + ${msg( + "This provider will behave like a transparent reverse-proxy, except requests must be authenticated. If your upstream application uses HTTPS, make sure to connect to the outpost using HTTPS as well.", + )} +

`; + } + + renderProxyMode() { + return html` + + + `; + } +} + +export default AkReverseProxyApplicationWizardPage; diff --git a/web/src/admin/applications/wizard/proxy/ak-application-wizard-authentication-for-single-forward-proxy.ts b/web/src/admin/applications/wizard/proxy/ak-application-wizard-authentication-for-single-forward-proxy.ts new file mode 100644 index 000000000..0840c698f --- /dev/null +++ b/web/src/admin/applications/wizard/proxy/ak-application-wizard-authentication-for-single-forward-proxy.ts @@ -0,0 +1,36 @@ +import "@goauthentik/components/ak-text-input"; + +import { msg } from "@lit/localize"; +import { customElement } from "@lit/reactive-element/decorators.js"; +import { html } from "lit"; +import { ifDefined } from "lit/directives/if-defined.js"; + +import AkTypeProxyApplicationWizardPage from "./AuthenticationByProxyPage"; + +@customElement("ak-application-wizard-authentication-for-single-forward-proxy") +export class AkForwardSingleProxyApplicationWizardPage extends AkTypeProxyApplicationWizardPage { + renderModeDescription() { + return html`

+ ${msg( + html`Use this provider with nginx's auth_request or traefik's + forwardAuth. Each application/domain needs its own provider. + Additionally, on each domain, /outpost.goauthentik.io must be + routed to the outpost (when using a managed outpost, this is done for you).`, + )} +

`; + } + + renderProxyMode() { + return html``; + } +} + +export default AkForwardSingleProxyApplicationWizardPage; diff --git a/web/src/admin/applications/wizard/stories/ak-application-wizard.stories.ts b/web/src/admin/applications/wizard/stories/ak-application-wizard.stories.ts index 203aded62..5aa678935 100644 --- a/web/src/admin/applications/wizard/stories/ak-application-wizard.stories.ts +++ b/web/src/admin/applications/wizard/stories/ak-application-wizard.stories.ts @@ -7,8 +7,9 @@ import AkApplicationWizardApplicationDetails from "../ak-application-wizard-appl import "../ak-application-wizard-authentication-method-choice"; import "../ak-application-wizard-context"; import "../ldap/ak-application-wizard-authentication-by-ldap"; -import "../proxy/ak-application-wizard-authentication-by-proxy"; import "../oauth/ak-application-wizard-authentication-by-oauth"; +import "../proxy/ak-application-wizard-authentication-for-reverse-proxy"; +import "../proxy/ak-application-wizard-authentication-for-single-forward-proxy"; import "./ak-application-context-display-for-test"; import { dummyAuthenticationFlowsSearch, @@ -103,7 +104,7 @@ const container = (testItem: TemplateResult) => { `; }; -export const PageOne = () => { +export const DescribeApplication = () => { return container( html` @@ -113,7 +114,7 @@ export const PageOne = () => { ); }; -export const PageTwo = () => { +export const ChooseAuthMethod = () => { return container( html` @@ -123,7 +124,7 @@ export const PageTwo = () => { ); }; -export const PageThreeLdap = () => { +export const ConfigureLdap = () => { return container( html` @@ -133,7 +134,7 @@ export const PageThreeLdap = () => { ); }; -export const PageThreeOauth2 = () => { +export const ConfigureOauth2 = () => { return container( html` @@ -143,10 +144,20 @@ export const PageThreeOauth2 = () => { ); }; -export const PageThreeProxy = () => { +export const ConfigureReverseProxy = () => { return container( html` - + +
+ +
`, + ); +}; + +export const ConfigureSingleForwardProxy = () => { + return container( + html` +
`,