Squashed commit of the following:
commit b5a751005850115c84fd8fddb83f32a52835a422 Author: fuomag9 <1580624+fuomag9@users.noreply.github.com> Date: Sat Nov 8 13:54:22 2025 +0100 Update ProxyHostsClient.tsx commit c93b3898c31b9c206fba74605dad5a578e326ce4 Author: fuomag9 <1580624+fuomag9@users.noreply.github.com> Date: Sat Nov 8 13:43:00 2025 +0100 test-protected-paths
This commit is contained in:
@@ -658,6 +658,18 @@ function AuthentikFields({ authentik }: { authentik?: ProxyHost["authentik"] | n
|
|||||||
size="small"
|
size="small"
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
|
<TextField
|
||||||
|
name="authentik_protected_paths"
|
||||||
|
label="Protected Paths (Optional)"
|
||||||
|
placeholder="/secret/*, /admin/*"
|
||||||
|
helperText="Leave empty to protect entire domain. Specify paths to protect specific routes only."
|
||||||
|
defaultValue={initial?.protectedPaths?.join(", ") ?? ""}
|
||||||
|
disabled={!enabled}
|
||||||
|
multiline
|
||||||
|
minRows={2}
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
<HiddenCheckboxField
|
<HiddenCheckboxField
|
||||||
name="authentik_set_host_header"
|
name="authentik_set_host_header"
|
||||||
defaultChecked={setHostHeaderDefault}
|
defaultChecked={setHostHeaderDefault}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ function parseAuthentikConfig(formData: FormData): ProxyHostAuthentikInput | und
|
|||||||
const authEndpoint = parseOptionalText(formData.get("authentik_auth_endpoint"));
|
const authEndpoint = parseOptionalText(formData.get("authentik_auth_endpoint"));
|
||||||
const copyHeaders = parseCsv(formData.get("authentik_copy_headers"));
|
const copyHeaders = parseCsv(formData.get("authentik_copy_headers"));
|
||||||
const trustedProxies = parseCsv(formData.get("authentik_trusted_proxies"));
|
const trustedProxies = parseCsv(formData.get("authentik_trusted_proxies"));
|
||||||
|
const protectedPaths = parseCsv(formData.get("authentik_protected_paths"));
|
||||||
const setHostHeader = formData.has("authentik_set_host_header_present")
|
const setHostHeader = formData.has("authentik_set_host_header_present")
|
||||||
? parseCheckbox(formData.get("authentik_set_host_header"))
|
? parseCheckbox(formData.get("authentik_set_host_header"))
|
||||||
: undefined;
|
: undefined;
|
||||||
@@ -67,6 +68,9 @@ function parseAuthentikConfig(formData: FormData): ProxyHostAuthentikInput | und
|
|||||||
if (trustedProxies.length > 0 || formData.has("authentik_trusted_proxies")) {
|
if (trustedProxies.length > 0 || formData.has("authentik_trusted_proxies")) {
|
||||||
result.trustedProxies = trustedProxies;
|
result.trustedProxies = trustedProxies;
|
||||||
}
|
}
|
||||||
|
if (protectedPaths.length > 0 || formData.has("authentik_protected_paths")) {
|
||||||
|
result.protectedPaths = protectedPaths;
|
||||||
|
}
|
||||||
if (setHostHeader !== undefined) {
|
if (setHostHeader !== undefined) {
|
||||||
result.setOutpostHostHeader = setHostHeader;
|
result.setOutpostHostHeader = setHostHeader;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ type ProxyHostAuthentikMeta = {
|
|||||||
copy_headers?: string[];
|
copy_headers?: string[];
|
||||||
trusted_proxies?: string[];
|
trusted_proxies?: string[];
|
||||||
set_outpost_host_header?: boolean;
|
set_outpost_host_header?: boolean;
|
||||||
|
protected_paths?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type AuthentikRouteConfig = {
|
type AuthentikRouteConfig = {
|
||||||
@@ -78,6 +79,7 @@ type AuthentikRouteConfig = {
|
|||||||
copyHeaders: string[];
|
copyHeaders: string[];
|
||||||
trustedProxies: string[];
|
trustedProxies: string[];
|
||||||
setOutpostHostHeader: boolean;
|
setOutpostHostHeader: boolean;
|
||||||
|
protectedPaths: string[] | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RedirectHostRow = {
|
type RedirectHostRow = {
|
||||||
@@ -494,9 +496,44 @@ function buildProxyRoutes(
|
|||||||
forwardAuthHandler.trusted_proxies = trustedProxies;
|
forwardAuthHandler.trusted_proxies = trustedProxies;
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers.push(forwardAuthHandler);
|
// Path-based authentication support
|
||||||
|
if (authentik.protectedPaths && authentik.protectedPaths.length > 0) {
|
||||||
|
// Create separate routes for each protected path
|
||||||
|
for (const protectedPath of authentik.protectedPaths) {
|
||||||
|
const protectedHandlers: Record<string, unknown>[] = [...handlers];
|
||||||
|
const protectedReverseProxy = JSON.parse(JSON.stringify(reverseProxyHandler));
|
||||||
|
|
||||||
|
protectedHandlers.push(forwardAuthHandler);
|
||||||
|
protectedHandlers.push(protectedReverseProxy);
|
||||||
|
|
||||||
|
hostRoutes.push({
|
||||||
|
match: [
|
||||||
|
{
|
||||||
|
host: domains,
|
||||||
|
path: [protectedPath]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
handle: protectedHandlers,
|
||||||
|
terminal: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a catch-all route for non-protected paths (without forward auth)
|
||||||
|
const unprotectedHandlers: Record<string, unknown>[] = [...handlers];
|
||||||
|
unprotectedHandlers.push(reverseProxyHandler);
|
||||||
|
|
||||||
|
hostRoutes.push({
|
||||||
|
match: [
|
||||||
|
{
|
||||||
|
host: domains
|
||||||
|
}
|
||||||
|
],
|
||||||
|
handle: unprotectedHandlers,
|
||||||
|
terminal: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// No path-based protection: protect entire domain (backward compatibility)
|
||||||
|
handlers.push(forwardAuthHandler);
|
||||||
handlers.push(reverseProxyHandler);
|
handlers.push(reverseProxyHandler);
|
||||||
|
|
||||||
const route: CaddyHttpRoute = {
|
const route: CaddyHttpRoute = {
|
||||||
@@ -510,6 +547,24 @@ function buildProxyRoutes(
|
|||||||
};
|
};
|
||||||
|
|
||||||
hostRoutes.push(route);
|
hostRoutes.push(route);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No Authentik: standard reverse proxy
|
||||||
|
handlers.push(reverseProxyHandler);
|
||||||
|
|
||||||
|
const route: CaddyHttpRoute = {
|
||||||
|
match: [
|
||||||
|
{
|
||||||
|
host: domains
|
||||||
|
}
|
||||||
|
],
|
||||||
|
handle: handlers,
|
||||||
|
terminal: true
|
||||||
|
};
|
||||||
|
|
||||||
|
hostRoutes.push(route);
|
||||||
|
}
|
||||||
|
|
||||||
routes.push(...hostRoutes);
|
routes.push(...hostRoutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,6 +1015,11 @@ function parseAuthentikConfig(meta: ProxyHostAuthentikMeta | undefined | null):
|
|||||||
const setOutpostHostHeader =
|
const setOutpostHostHeader =
|
||||||
meta.set_outpost_host_header !== undefined ? Boolean(meta.set_outpost_host_header) : true;
|
meta.set_outpost_host_header !== undefined ? Boolean(meta.set_outpost_host_header) : true;
|
||||||
|
|
||||||
|
const protectedPaths =
|
||||||
|
Array.isArray(meta.protected_paths) && meta.protected_paths.length > 0
|
||||||
|
? meta.protected_paths.map((path) => path?.trim()).filter((path): path is string => Boolean(path))
|
||||||
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
outpostDomain,
|
outpostDomain,
|
||||||
@@ -967,6 +1027,7 @@ function parseAuthentikConfig(meta: ProxyHostAuthentikMeta | undefined | null):
|
|||||||
authEndpoint,
|
authEndpoint,
|
||||||
copyHeaders,
|
copyHeaders,
|
||||||
trustedProxies,
|
trustedProxies,
|
||||||
setOutpostHostHeader
|
setOutpostHostHeader,
|
||||||
|
protectedPaths
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export type ProxyHostAuthentikConfig = {
|
|||||||
copyHeaders: string[];
|
copyHeaders: string[];
|
||||||
trustedProxies: string[];
|
trustedProxies: string[];
|
||||||
setOutpostHostHeader: boolean;
|
setOutpostHostHeader: boolean;
|
||||||
|
protectedPaths: string[] | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProxyHostAuthentikInput = {
|
export type ProxyHostAuthentikInput = {
|
||||||
@@ -39,6 +40,7 @@ export type ProxyHostAuthentikInput = {
|
|||||||
copyHeaders?: string[] | null;
|
copyHeaders?: string[] | null;
|
||||||
trustedProxies?: string[] | null;
|
trustedProxies?: string[] | null;
|
||||||
setOutpostHostHeader?: boolean | null;
|
setOutpostHostHeader?: boolean | null;
|
||||||
|
protectedPaths?: string[] | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ProxyHostAuthentikMeta = {
|
type ProxyHostAuthentikMeta = {
|
||||||
@@ -49,6 +51,7 @@ type ProxyHostAuthentikMeta = {
|
|||||||
copy_headers?: string[];
|
copy_headers?: string[];
|
||||||
trusted_proxies?: string[];
|
trusted_proxies?: string[];
|
||||||
set_outpost_host_header?: boolean;
|
set_outpost_host_header?: boolean;
|
||||||
|
protected_paths?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type ProxyHostMeta = {
|
type ProxyHostMeta = {
|
||||||
@@ -150,6 +153,13 @@ function sanitizeAuthentikMeta(meta: ProxyHostAuthentikMeta | undefined): ProxyH
|
|||||||
normalized.set_outpost_host_header = Boolean(meta.set_outpost_host_header);
|
normalized.set_outpost_host_header = Boolean(meta.set_outpost_host_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(meta.protected_paths)) {
|
||||||
|
const paths = meta.protected_paths.map((path) => path?.trim()).filter((path): path is string => Boolean(path));
|
||||||
|
if (paths.length > 0) {
|
||||||
|
normalized.protected_paths = paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Object.keys(normalized).length > 0 ? normalized : undefined;
|
return Object.keys(normalized).length > 0 ? normalized : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,6 +273,17 @@ function normalizeAuthentikInput(
|
|||||||
next.set_outpost_host_header = Boolean(input.setOutpostHostHeader);
|
next.set_outpost_host_header = Boolean(input.setOutpostHostHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.protectedPaths !== undefined) {
|
||||||
|
const paths = (input.protectedPaths ?? [])
|
||||||
|
.map((path) => path?.trim())
|
||||||
|
.filter((path): path is string => Boolean(path));
|
||||||
|
if (paths.length > 0) {
|
||||||
|
next.protected_paths = paths;
|
||||||
|
} else {
|
||||||
|
delete next.protected_paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((next.enabled ?? false) && next.outpost_domain && !next.auth_endpoint) {
|
if ((next.enabled ?? false) && next.outpost_domain && !next.auth_endpoint) {
|
||||||
next.auth_endpoint = `/${next.outpost_domain}/auth/caddy`;
|
next.auth_endpoint = `/${next.outpost_domain}/auth/caddy`;
|
||||||
}
|
}
|
||||||
@@ -321,6 +342,8 @@ function hydrateAuthentik(meta: ProxyHostAuthentikMeta | undefined): ProxyHostAu
|
|||||||
: DEFAULT_AUTHENTIK_TRUSTED_PROXIES;
|
: DEFAULT_AUTHENTIK_TRUSTED_PROXIES;
|
||||||
const setOutpostHostHeader =
|
const setOutpostHostHeader =
|
||||||
meta.set_outpost_host_header !== undefined ? Boolean(meta.set_outpost_host_header) : true;
|
meta.set_outpost_host_header !== undefined ? Boolean(meta.set_outpost_host_header) : true;
|
||||||
|
const protectedPaths =
|
||||||
|
Array.isArray(meta.protected_paths) && meta.protected_paths.length > 0 ? meta.protected_paths : null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
enabled,
|
enabled,
|
||||||
@@ -329,7 +352,8 @@ function hydrateAuthentik(meta: ProxyHostAuthentikMeta | undefined): ProxyHostAu
|
|||||||
authEndpoint,
|
authEndpoint,
|
||||||
copyHeaders,
|
copyHeaders,
|
||||||
trustedProxies,
|
trustedProxies,
|
||||||
setOutpostHostHeader
|
setOutpostHostHeader,
|
||||||
|
protectedPaths
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,6 +382,9 @@ function dehydrateAuthentik(config: ProxyHostAuthentikConfig | null): ProxyHostA
|
|||||||
meta.trusted_proxies = [...config.trustedProxies];
|
meta.trusted_proxies = [...config.trustedProxies];
|
||||||
}
|
}
|
||||||
meta.set_outpost_host_header = config.setOutpostHostHeader;
|
meta.set_outpost_host_header = config.setOutpostHostHeader;
|
||||||
|
if (config.protectedPaths && config.protectedPaths.length > 0) {
|
||||||
|
meta.protected_paths = [...config.protectedPaths];
|
||||||
|
}
|
||||||
|
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user