From 889adecad1bfb3a62027d85f135fd625504fd299 Mon Sep 17 00:00:00 2001
From: Ken Sternberg
Date: Mon, 9 Oct 2023 14:56:29 -0700
Subject: [PATCH] web: better converter configuration, CSS repair, and
forward-domain-proxy
1. Forward Domain Proxy. I wasn't sure if this method was appropriate for the wizard,
but Jens says it is. I've added it.
2. In the process of doing so, I decided that the Provider.converter field was overly
complexified; I tried too hard to reduce the number of functions I needed to define,
but in the process outsourced some of the logic of converting the Wizard's dataset
into a property typed request to the `commit` phase, which was inappropriate. All
of the logic about a provider, aside from its display, should be here with the code
that distinguishes between providers. This commit makes it so.
3. Small CSS fix: the fields inherited from the Proxy provider forms had some unexpected
CSS which was causing a bit of a weird indent. That has been rectified.
---
...rd-authentication-method-choice.choices.ts | 121 +++++++++---------
...k-application-wizard-commit-application.ts | 52 +++-----
...pplication-wizard-authentication-method.ts | 1 +
.../proxy/AuthenticationByProxyPage.ts | 2 +-
...authentication-for-forward-domain-proxy.ts | 55 ++++++++
web/src/admin/applications/wizard/steps.ts | 6 +-
6 files changed, 136 insertions(+), 101 deletions(-)
create mode 100644 web/src/admin/applications/wizard/methods/proxy/ak-application-wizard-authentication-for-forward-domain-proxy.ts
diff --git a/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts
index f18b3dc43..dd50b2ae2 100644
--- a/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts
+++ b/web/src/admin/applications/wizard/auth-method-choice/ak-application-wizard-authentication-method-choice.choices.ts
@@ -2,7 +2,8 @@ import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
import type { ProviderModelEnum as ProviderModelEnumType, TypeCreate } from "@goauthentik/api";
-import { ProviderModelEnum } from "@goauthentik/api";
+import { ProviderModelEnum, ProxyMode,
+ } from "@goauthentik/api";
import type {
LDAPProviderRequest,
ModelRequest,
@@ -17,10 +18,10 @@ import { OneOfProvider } from "../types";
type ProviderRenderer = () => TemplateResult;
-type ProviderType = [string, string, string, ProviderRenderer, ProviderModelEnumType];
-
type ModelConverter = (provider: OneOfProvider) => ModelRequest;
+type ProviderType = [string, string, string, ProviderRenderer, ProviderModelEnumType, ModelConverter];
+
export type LocalTypeCreate = TypeCreate & {
formName: string;
modelName: ProviderModelEnumType;
@@ -35,6 +36,10 @@ const _providerModelsTable: ProviderType[] = [
msg("Modern applications, APIs and Single-page applications."),
() => html``,
ProviderModelEnum.Oauth2Oauth2provider,
+ (provider: OneOfProvider) => ({
+ providerModel: ProviderModelEnum.Oauth2Oauth2provider,
+ ...(provider as OAuth2ProviderRequest),
+ }),
],
[
"ldapprovider",
@@ -42,20 +47,49 @@ const _providerModelsTable: ProviderType[] = [
msg("Provide an LDAP interface for applications and users to authenticate against."),
() => html``,
ProviderModelEnum.LdapLdapprovider,
+ (provider: OneOfProvider) => ({
+ providerModel: ProviderModelEnum.LdapLdapprovider,
+ ...(provider as LDAPProviderRequest),
+ }),
+
],
[
"proxyprovider-proxy",
msg("Transparent Reverse Proxy"),
msg("For transparent reverse proxies with required authentication"),
() => html``,
- ProviderModelEnum.ProxyProxyprovider
+ ProviderModelEnum.ProxyProxyprovider,
+ (provider: OneOfProvider) => ({
+ providerModel: ProviderModelEnum.ProxyProxyprovider,
+ ...(provider as ProxyProviderRequest),
+ mode: ProxyMode.Proxy,
+ }),
+
],
[
"proxyprovider-forwardsingle",
- msg("Forward Single Proxy"),
+ msg("Forward Auth Single Application"),
msg("For nginx's auth_request or traefix's forwardAuth"),
() => html``,
- ProviderModelEnum.ProxyProxyprovider
+ ProviderModelEnum.ProxyProxyprovider ,
+ (provider: OneOfProvider) => ({
+ providerModel: ProviderModelEnum.ProxyProxyprovider,
+ ...(provider as ProxyProviderRequest),
+ mode: ProxyMode.ForwardSingle,
+ }),
+
+ ],
+ [
+ "proxyprovider-forwarddomain",
+ msg("Forward Auth Domain Level"),
+ msg("For nginx's auth_request or traefix's forwardAuth per root domain"),
+ () => html``,
+ ProviderModelEnum.ProxyProxyprovider ,
+ (provider: OneOfProvider) => ({
+ providerModel: ProviderModelEnum.ProxyProxyprovider,
+ ...(provider as ProxyProviderRequest),
+ mode: ProxyMode.ForwardDomain,
+ }),
],
[
@@ -63,93 +97,54 @@ const _providerModelsTable: ProviderType[] = [
msg("SAML Configuration"),
msg("Configure SAML provider manually"),
() => html``,
- ProviderModelEnum.SamlSamlprovider
+ ProviderModelEnum.SamlSamlprovider,
+ (provider: OneOfProvider) => ({
+ providerModel: ProviderModelEnum.SamlSamlprovider,
+ ...(provider as SAMLProviderRequest),
+ }),
+
],
[
"radiusprovider",
msg("RADIUS Configuration"),
msg("Configure RADIUS provider manually"),
() => html``,
- ProviderModelEnum.RadiusRadiusprovider
+ ProviderModelEnum.RadiusRadiusprovider,
+ (provider: OneOfProvider) => ({
+ providerModel: ProviderModelEnum.RadiusRadiusprovider,
+ ...(provider as RadiusProviderRequest),
+ }),
+
],
[
"scimprovider",
msg("SCIM Manual configuration"),
msg("Configure SCIM provider manually"),
() => html``,
- ProviderModelEnum.ScimScimprovider
- ],
-];
-
-const converters = new Map([
- [
- ProviderModelEnum.Oauth2Oauth2provider,
- (provider: OneOfProvider) => ({
- providerModel: ProviderModelEnum.Oauth2Oauth2provider,
- ...(provider as OAuth2ProviderRequest),
- }),
- ],
- [
- ProviderModelEnum.LdapLdapprovider,
- (provider: OneOfProvider) => ({
- providerModel: ProviderModelEnum.LdapLdapprovider,
- ...(provider as LDAPProviderRequest),
- }),
- ],
- [
- ProviderModelEnum.ProxyProxyprovider,
- (provider: OneOfProvider) => ({
- providerModel: ProviderModelEnum.ProxyProxyprovider,
- ...(provider as ProxyProviderRequest),
- }),
- ],
- [
- ProviderModelEnum.SamlSamlprovider,
- (provider: OneOfProvider) => ({
- providerModel: ProviderModelEnum.SamlSamlprovider,
- ...(provider as SAMLProviderRequest),
- }),
- ],
- [
ProviderModelEnum.ScimScimprovider,
- (provider: OneOfProvider) => ({
+ (provider: OneOfProvider) => ({
providerModel: ProviderModelEnum.ScimScimprovider,
...(provider as SCIMProviderRequest),
}),
- ],
- [
- ProviderModelEnum.RadiusRadiusprovider,
- (provider: OneOfProvider) => ({
- providerModel: ProviderModelEnum.RadiusRadiusprovider,
- ...(provider as RadiusProviderRequest),
- }),
- ],
-]);
-// Contract enforcement
-const getConverter = (modelName: ProviderModelEnumType): ModelConverter => {
- const maybeConverter = converters.get(modelName);
- if (!maybeConverter) {
- throw new Error(`ModelName lookup failed in model converter definition: ${"modelName"}`);
- }
- return maybeConverter;
-};
+ ],
+];
-function mapProviders([formName, name, description, _, modelName]: ProviderType): LocalTypeCreate {
+function mapProviders([formName, name, description, _, modelName, converter]: ProviderType): LocalTypeCreate {
return {
formName,
name,
description,
component: "",
modelName,
- converter: getConverter(modelName),
+ converter
};
}
export const providerModelsList = _providerModelsTable.map(mapProviders);
export const providerRendererList = new Map(
- _providerModelsTable.map(([modelName, _0, _1, renderer]) => [modelName, renderer]),
+ _providerModelsTable.map(([modelName, _0, _1, renderer]) => [modelName, renderer])
);
export default providerModelsList;
diff --git a/web/src/admin/applications/wizard/commit/ak-application-wizard-commit-application.ts b/web/src/admin/applications/wizard/commit/ak-application-wizard-commit-application.ts
index 906856344..9d8af10b7 100644
--- a/web/src/admin/applications/wizard/commit/ak-application-wizard-commit-application.ts
+++ b/web/src/admin/applications/wizard/commit/ak-application-wizard-commit-application.ts
@@ -58,7 +58,7 @@ const runningState: State = {
};
const errorState: State = {
state: "error",
- label: msg("There was an error in saving your application:"),
+ label: msg("Authentik was unable to save this application:"),
icon: ["fa-times-circle", "pf-m-danger"],
};
@@ -68,21 +68,6 @@ const successState: State = {
icon: ["fa-check-circle", "pf-m-success"],
};
-function extract(o: Record): string[] {
- function inner(o: Record): string[] {
- if (typeof o !== "object") {
- return [];
- }
- if (Array.isArray(o)) {
- return o;
- }
- return Object.keys(o)
- .map((k) => inner(o[k]))
- .flat();
- }
- return inner(o);
-}
-
@customElement("ak-application-wizard-commit-application")
export class ApplicationWizardCommitApplication extends BasePanel {
static get styles() {
@@ -126,26 +111,10 @@ export class ApplicationWizardCommitApplication extends BasePanel {
);
}
- const provider = (() => {
- if (this.wizard.providerModel === "proxyprovider-forwardsingle") {
- return {
- ...providerModel.converter(this.wizard.provider),
- mode: ProxyMode.ForwardSingle,
- };
- }
- if (this.wizard.providerModel === "proxyprovider-proxy") {
- return {
- ...providerModel.converter(this.wizard.provider),
- mode: ProxyMode.Proxy,
- };
- }
- return providerModel.converter(this.wizard.provider);
- })();
-
const request: TransactionApplicationRequest = {
providerModel: providerModel.modelName as ProviderModelType,
app: cleanApplication(this.wizard.app),
- provider,
+ provider: providerModel.converter(this.wizard.provider)
};
this.send(request);
@@ -153,6 +122,21 @@ export class ApplicationWizardCommitApplication extends BasePanel {
}
}
+ decodeErrors(body: Record) {
+ const spaceify = (src: Record) =>
+ Object.values(src).map((msg) => `\u00a0\u00a0\u00a0\u00a0${msg}`);
+
+ let errs: string[] = [];
+ if (body["app"] !== undefined) {
+ errs = [...errs, msg("In the Application:"), ...spaceify(body["app"])];
+ }
+ if (body["provider"] !== undefined) {
+ errs = [...errs, msg("In the Provider:"), ...spaceify(body["provider"])];
+ }
+ console.log(body, errs);
+ return errs;
+ }
+
async send(
data: TransactionApplicationRequest,
): Promise {
@@ -170,7 +154,7 @@ export class ApplicationWizardCommitApplication extends BasePanel {
})
.catch((resolution: any) => {
resolution.response.json().then((body: Record) => {
- this.errors = extract(body);
+ this.errors = this.decodeErrors(body);
this.commitState = errorState;
});
});
diff --git a/web/src/admin/applications/wizard/methods/ak-application-wizard-authentication-method.ts b/web/src/admin/applications/wizard/methods/ak-application-wizard-authentication-method.ts
index f308bcbab..36d412315 100644
--- a/web/src/admin/applications/wizard/methods/ak-application-wizard-authentication-method.ts
+++ b/web/src/admin/applications/wizard/methods/ak-application-wizard-authentication-method.ts
@@ -6,6 +6,7 @@ import "./ldap/ak-application-wizard-authentication-by-ldap";
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 "./proxy/ak-application-wizard-authentication-for-forward-domain-proxy";
import "./radius/ak-application-wizard-authentication-by-radius";
import "./saml/ak-application-wizard-authentication-by-saml-configuration";
import "./scim/ak-application-wizard-authentication-by-scim";
diff --git a/web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts b/web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts
index c3ac7f44f..4b32fe2d7 100644
--- a/web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts
+++ b/web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts
@@ -127,7 +127,7 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel {
-
+ ${this.renderProxyMode()}
+ ${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."
+ )}
+
`;
+ }
+
+ renderProxyMode() {
+ return html`
+
+
+
+ `;
+ }
+}
+
+export default AkForwardDomainProxyApplicationWizardPage;
diff --git a/web/src/admin/applications/wizard/steps.ts b/web/src/admin/applications/wizard/steps.ts
index a04cc0bee..451367bf8 100644
--- a/web/src/admin/applications/wizard/steps.ts
+++ b/web/src/admin/applications/wizard/steps.ts
@@ -30,7 +30,7 @@ class ApplicationStep implements ApplicationStepType {
class ProviderMethodStep implements ApplicationStepType {
id = "provider-method";
- label = "Authentication Method";
+ label = "Provider Type";
disabled = false;
valid = false;
@@ -47,7 +47,7 @@ class ProviderMethodStep implements ApplicationStepType {
class ProviderStepDetails implements ApplicationStepType {
id = "provider-details";
- label = "Authentication Details";
+ label = "Provider Configuration";
disabled = true;
valid = false;
get buttons() {
@@ -61,7 +61,7 @@ class ProviderStepDetails implements ApplicationStepType {
class SubmitApplicationStep implements ApplicationStepType {
id = "submit";
- label = "Submit New Application";
+ label = "Submit Application";
disabled = true;
valid = false;