import { env } from "cloudflare:workers"; import { describe, expect, it } from "vitest"; import { createControlPlaneDb } from "@/worker/db/d1/client"; import { getSubjectById } from "@/worker/db/d1/repository"; import { completeOidcLogin, startOidcLogin } from "@tests/worker/helpers/auth"; import { controlRequest, cookiePairFor, fetchWorker, setCookieHeaders } from "@tests/worker/helpers/http"; describe("tessera OIDC control-plane auth", () => { it("starts login with discovery, state, nonce, PKCE, and a signed transaction cookie", async () => { const { loginResponse, authorizationUrl } = await startOidcLogin("/after"); expect(loginResponse.status).toBe(302); expect(authorizationUrl.pathname).toBe("/authorize"); expect(authorizationUrl.searchParams.get("response_type")).toBe("code"); expect(authorizationUrl.searchParams.get("scope")).toBe("openid email profile"); expect(authorizationUrl.searchParams.get("state")).toMatch(/^[A-Za-z0-9_-]+$/); expect(authorizationUrl.searchParams.get("nonce")).toMatch(/^[A-Za-z0-9_-]+$/); expect(authorizationUrl.searchParams.get("code_challenge_method")).toBe("S256"); expect(authorizationUrl.searchParams.get("code_challenge")).toMatch(/^[A-Za-z0-9_-]+$/); const txCookie = setCookieHeaders(loginResponse).find((header) => header.startsWith("__Host-dab_oidc_tx=")); expect(txCookie).toContain("HttpOnly"); expect(txCookie).toContain("Secure"); expect(txCookie).toContain("SameSite=Lax"); expect(txCookie).toContain("Path=/"); expect(txCookie).not.toContain("Domain="); }); it("rejects foreign and protocol-relative return targets", async () => { const foreign = await fetchWorker( controlRequest(`/api/v1/auth/oidc/login?return_to=${encodeURIComponent("https://attacker.example/after")}`), ); expect(foreign.status).toBe(400); const protocolRelative = await fetchWorker( controlRequest(`/api/v1/auth/oidc/login?return_to=${encodeURIComponent("//attacker.example/after")}`), ); expect(protocolRelative.status).toBe(400); }); it("rejects invalid callbacks and clears the transaction cookie", async () => { const { transactionCookie } = await startOidcLogin(); const response = await fetchWorker( controlRequest("/api/v1/auth/oidc/callback?code=bad&state=wrong", { headers: { cookie: transactionCookie }, }), ); expect(response.status).toBe(400); expect(setCookieHeaders(response).join("\n")).toContain("__Host-dab_oidc_tx=; Max-Age=0"); }); it("bootstraps one stable subject row and creates API sessions", async () => { const first = await completeOidcLogin(); expect(first.callbackResponse.status).toBe(200); expect(setCookieHeaders(first.callbackResponse).join("\n")).toContain("__Host-dab_session="); expect(setCookieHeaders(first.callbackResponse).join("\n")).toContain("__Host-dab_oidc_tx=; Max-Age=0"); const db = createControlPlaneDb(env.DAV_CONTROL_PLANE); const firstSubject = await getSubjectById(db, "tessera-sub-phase1"); expect(firstSubject).toBeDefined(); expect(firstSubject?.storageId).toMatch(/^stg_[0-9a-f]{32}$/); expect(firstSubject?.hostLabel).toMatch(/^[a-z]+(-[a-z]+){4}$/); expect(firstSubject?.hostLabel.length).toBeLessThanOrEqual(63); const meResponse = await fetchWorker(controlRequest("/api/v1/me", { headers: { cookie: first.sessionCookie } })); expect(meResponse.status).toBe(200); await expect(meResponse.json()).resolves.toMatchObject({ subject_id: "tessera-sub-phase1", host_label: firstSubject?.hostLabel, }); const second = await completeOidcLogin(); expect(second.callbackResponse.status).toBe(200); const secondSubject = await getSubjectById(db, "tessera-sub-phase1"); expect(secondSubject?.storageId).toBe(firstSubject?.storageId); expect(secondSubject?.hostLabel).toBe(firstSubject?.hostLabel); }); it("rejects foreign-origin mutating requests before session lookup", async () => { const missingOrigin = await fetchWorker(controlRequest("/api/v1/auth/logout", { method: "POST" })); expect(missingOrigin.status).toBe(403); const foreignOrigin = await fetchWorker( controlRequest("/api/v1/auth/logout", { method: "POST", headers: { origin: "https://attacker.example" }, }), ); expect(foreignOrigin.status).toBe(403); const sameOriginNoSession = await fetchWorker( controlRequest("/api/v1/auth/logout", { method: "POST", headers: { origin: "https://dav.example.com" }, }), ); expect(sameOriginNoSession.status).toBe(401); }); it("logs out a same-origin API session and clears the session cookie", async () => { const login = await completeOidcLogin(); const response = await fetchWorker( controlRequest("/api/v1/auth/logout", { method: "POST", headers: { cookie: login.sessionCookie, origin: "https://dav.example.com", }, }), ); expect(response.status).toBe(200); expect(cookiePairFor(response, "__Host-dab_session")).toBe("__Host-dab_session="); const afterLogout = await fetchWorker(controlRequest("/api/v1/me", { headers: { cookie: login.sessionCookie } })); expect(afterLogout.status).toBe(401); }); });