From c5474111f94bf444b4756a55a6890a9d5d278bcc Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 28 Oct 2026 15:59:16 +0100 Subject: [PATCH] web: Modul-Tokens mit explizitem Zielmodul anfordern (NEXT_PUBLIC_TOKEN_MODULE, Standard dms) Vorbereitung auf mehrere NEXARCH_ACCOUNT_MODULE_AUDIENCES: der Core lehnt Token-Anfragen ohne ?module ab, sobald mehr als eine Audience konfiguriert ist. Co-Authored-By: Claude Sonnet 5.5 --- web/core-control/lib/http.ts | 1 + web/dms-browser/lib/http.test.ts | 10 +++++----- web/dms-browser/lib/http.ts | 1 + web/dms-upload/lib/http.test.ts | 8 ++++---- web/dms-upload/lib/http.ts | 1 + web/mail-postfach/lib/http.ts | 1 + web/mail-search/lib/http.ts | 1 + web/pdf-viewer/lib/http.ts | 1 + 8 files changed, 15 insertions(+), 9 deletions(-) diff --git a/web/core-control/lib/http.ts b/web/core-control/lib/http.ts index ecf03697..d3a5b4fc 100644 --- a/web/core-control/lib/http.ts +++ b/web/core-control/lib/http.ts @@ -10,6 +10,7 @@ export function getSession(): Session { } session = createSession({ coreBase, + module: process.env.NEXT_PUBLIC_TOKEN_MODULE || "dms", onLoginRequired: () => redirectToLogin(process.env.NEXT_PUBLIC_LOGIN_URL), }); } diff --git a/web/dms-browser/lib/http.test.ts b/web/dms-browser/lib/http.test.ts index 74e3ff4d..20b5ceda 100644 --- a/web/dms-browser/lib/http.test.ts +++ b/web/dms-browser/lib/http.test.ts @@ -25,7 +25,7 @@ const json = (body: unknown, status = 200) => new Response(JSON.stringify(body), beforeEach(() => { calls = []; handler = (url) => { - if (url.endsWith("/auth/module-token")) return json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme", role: "user" }); + if (url.includes("/auth/module-token")) return json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme", role: "user" }); return json([]); }; vi.stubGlobal( @@ -54,7 +54,7 @@ function dmsCalls(): Call[] { describe("UX-10 AK1: alle DMS-Aufrufe im Token-Modus (Standard)", () => { it("senden Authorization: Bearer und nie caller/X-User-Id/actor", async () => { - handler = (url) => (url.endsWith("/auth/module-token") ? json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme", role: "user" }) : json({ hits: [], total: 0, limit: 20, offset: 0, took_ms: 1, facets: {} })); + handler = (url) => (url.includes("/auth/module-token") ? json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme", role: "user" }) : json({ hits: [], total: 0, limit: 20, offset: 0, took_ms: 1, facets: {} })); const attempts: Array<() => Promise> = [ () => fetchChildren(null), () => fetchDocuments("f-1"), @@ -114,14 +114,14 @@ describe("UX-10 AK2: Fehlerbehandlung", () => { vi.stubEnv("NEXT_PUBLIC_LOGIN_URL", "/anmelden"); const assign = vi.fn(); vi.stubGlobal("location", { pathname: "/", search: "", assign }); - handler = (url) => (url.endsWith("/auth/module-token") ? json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme" }) : new Response("", { status: 401 })); + handler = (url) => (url.includes("/auth/module-token") ? json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme" }) : new Response("", { status: 401 })); await expect(fetchAllTags()).rejects.toMatchObject({ kind: "unauthenticated" }); expect(assign).toHaveBeenCalledWith("/anmelden?return=%2F"); expect(dmsCalls().every((c) => !/caller=/.test(c.url))).toBe(true); }); it("Token fremden Mandanten wird vom DMS mit 401 abgewiesen und liefert keine Daten", async () => { - handler = (url) => (url.endsWith("/auth/module-token") ? json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "globex" }) : new Response(JSON.stringify({ error: { code: "unauthenticated" } }), { status: 401 })); + handler = (url) => (url.includes("/auth/module-token") ? json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "globex" }) : new Response(JSON.stringify({ error: { code: "unauthenticated" } }), { status: 401 })); await expect(fetchFields()).rejects.toMatchObject({ kind: "unauthenticated" }); }); @@ -129,7 +129,7 @@ describe("UX-10 AK2: Fehlerbehandlung", () => { [403, /Berechtigung/], [503, /nicht verfügbar/], ])("%i wird als verstaendliche Meldung ausgegeben", async (status, text) => { - handler = (url) => (url.endsWith("/auth/module-token") ? json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme" }) : new Response("", { status })); + handler = (url) => (url.includes("/auth/module-token") ? json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme" }) : new Response("", { status })); await expect(fetchAllTags()).rejects.toThrow(text); }); diff --git a/web/dms-browser/lib/http.ts b/web/dms-browser/lib/http.ts index 5045dd64..f3ecc62b 100644 --- a/web/dms-browser/lib/http.ts +++ b/web/dms-browser/lib/http.ts @@ -16,6 +16,7 @@ export function getSession(): Session { } session = createSession({ coreBase, + module: process.env.NEXT_PUBLIC_TOKEN_MODULE || "dms", onLoginRequired: () => redirectToLogin(process.env.NEXT_PUBLIC_LOGIN_URL), }); } diff --git a/web/dms-upload/lib/http.test.ts b/web/dms-upload/lib/http.test.ts index 1d1a7a83..2bbcb24e 100644 --- a/web/dms-upload/lib/http.test.ts +++ b/web/dms-upload/lib/http.test.ts @@ -17,7 +17,7 @@ beforeEach(() => { vi.fn(async (input: RequestInfo | URL, init: RequestInit = {}) => { const url = String(input); calls.push({ url, init }); - if (url.endsWith("/auth/module-token")) return json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme" }); + if (url.includes("/auth/module-token")) return json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme" }); return json({ sessionId: "s-1", offset: 0, bytesReceived: 0, status: "uploading", documentId: "d-1", revisionId: "r-1" }); }) ); @@ -46,7 +46,7 @@ describe("UX-10: Upload im Token-Modus", () => { expect(c.url).not.toMatch(/caller=/); expect(c.url).not.toContain(TOKEN); } - expect(calls.filter((c) => c.url.endsWith("/auth/module-token"))).toHaveLength(1); + expect(calls.filter((c) => c.url.includes("/auth/module-token"))).toHaveLength(1); }); it("401 beim Chunk: Token wird erneuert und der Chunk einmal wiederholt", async () => { @@ -54,7 +54,7 @@ describe("UX-10: Upload im Token-Modus", () => { (globalThis.fetch as unknown as ReturnType).mockImplementation(async (input: RequestInfo | URL, init: RequestInit = {}) => { const url = String(input); calls.push({ url, init }); - if (url.endsWith("/auth/module-token")) return json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme" }); + if (url.includes("/auth/module-token")) return json({ token: TOKEN, token_type: "Bearer", expires_in: 600, tenant: "acme" }); if (first) { first = false; return new Response("", { status: 401 }); @@ -62,6 +62,6 @@ describe("UX-10: Upload im Token-Modus", () => { return json({ bytesReceived: 3 }); }); await uploadChunk("s-1", 0, new Blob(["abc"])); - expect(calls.filter((c) => c.url.endsWith("/auth/module-token"))).toHaveLength(2); + expect(calls.filter((c) => c.url.includes("/auth/module-token"))).toHaveLength(2); }); }); diff --git a/web/dms-upload/lib/http.ts b/web/dms-upload/lib/http.ts index 7011b578..3aa0a807 100644 --- a/web/dms-upload/lib/http.ts +++ b/web/dms-upload/lib/http.ts @@ -16,6 +16,7 @@ export function getSession(): Session { } session = createSession({ coreBase, + module: process.env.NEXT_PUBLIC_TOKEN_MODULE || "dms", onLoginRequired: () => redirectToLogin(process.env.NEXT_PUBLIC_LOGIN_URL), }); } diff --git a/web/mail-postfach/lib/http.ts b/web/mail-postfach/lib/http.ts index 343d8893..d4ed8554 100644 --- a/web/mail-postfach/lib/http.ts +++ b/web/mail-postfach/lib/http.ts @@ -14,6 +14,7 @@ export function getSession(): Session { } session = createSession({ coreBase, + module: process.env.NEXT_PUBLIC_TOKEN_MODULE || "dms", onLoginRequired: () => redirectToLogin(process.env.NEXT_PUBLIC_LOGIN_URL), }); } diff --git a/web/mail-search/lib/http.ts b/web/mail-search/lib/http.ts index 7b54b3eb..a37e3eab 100644 --- a/web/mail-search/lib/http.ts +++ b/web/mail-search/lib/http.ts @@ -17,6 +17,7 @@ export function getSession(): Session { } session = createSession({ coreBase, + module: process.env.NEXT_PUBLIC_TOKEN_MODULE || "dms", onLoginRequired: () => redirectToLogin(process.env.NEXT_PUBLIC_LOGIN_URL), }); } diff --git a/web/pdf-viewer/lib/http.ts b/web/pdf-viewer/lib/http.ts index 7011b578..3aa0a807 100644 --- a/web/pdf-viewer/lib/http.ts +++ b/web/pdf-viewer/lib/http.ts @@ -16,6 +16,7 @@ export function getSession(): Session { } session = createSession({ coreBase, + module: process.env.NEXT_PUBLIC_TOKEN_MODULE || "dms", onLoginRequired: () => redirectToLogin(process.env.NEXT_PUBLIC_LOGIN_URL), }); }