From 18dbffc02da9fc4b427af50eafa4d10a930fcc65 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Thu, 16 Jan 2025 09:50:25 +0100 Subject: [PATCH] host context --- apps/login/src/lib/server/cookie.ts | 2 + apps/login/src/lib/server/session.ts | 49 +++++++++++++++++------ apps/login/src/lib/server/u2f.ts | 26 +++++++----- apps/login/src/lib/server/verify.ts | 60 +++++++++++++++++++++++----- 4 files changed, 106 insertions(+), 31 deletions(-) diff --git a/apps/login/src/lib/server/cookie.ts b/apps/login/src/lib/server/cookie.ts index 65409db7d22..3e3347e7506 100644 --- a/apps/login/src/lib/server/cookie.ts +++ b/apps/login/src/lib/server/cookie.ts @@ -31,6 +31,7 @@ export async function createSessionAndUpdateCookie( checks: Checks, challenges: RequestChallenges | undefined, authRequestId: string | undefined, + lifetime?: Duration, ): Promise { const host = (await headers()).get("host"); @@ -42,6 +43,7 @@ export async function createSessionAndUpdateCookie( host, checks, challenges, + lifetime, }); if (createdSession) { diff --git a/apps/login/src/lib/server/session.ts b/apps/login/src/lib/server/session.ts index 70bc18f6d56..84f028db44e 100644 --- a/apps/login/src/lib/server/session.ts +++ b/apps/login/src/lib/server/session.ts @@ -23,9 +23,16 @@ export async function continueWithSession({ authRequestId, ...session }: Session & { authRequestId?: string }) { - const loginSettings = await getLoginSettings( - session.factors?.user?.organizationId, - ); + const host = (await headers()).get("host"); + + if (!host || typeof host !== "string") { + throw new Error("No host found"); + } + + const loginSettings = await getLoginSettings({ + host, + organization: session.factors?.user?.organizationId, + }); const url = authRequestId && session.id && session.factors?.user @@ -99,7 +106,7 @@ export async function updateSession(options: UpdateSessionCommand) { challenges.webAuthN.domain = hostname; } - const loginSettings = await getLoginSettings(organization); + const loginSettings = await getLoginSettings({ host, organization }); const lifetime = checks?.webAuthN ? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey @@ -122,9 +129,10 @@ export async function updateSession(options: UpdateSessionCommand) { // if password, check if user has MFA methods let authMethods; if (checks && checks.password && session.factors?.user?.id) { - const response = await listAuthenticationMethodTypes( - session.factors.user.id, - ); + const response = await listAuthenticationMethodTypes({ + host, + userId: session.factors.user.id, + }); if (response.authMethodTypes && response.authMethodTypes.length) { authMethods = response.authMethodTypes; } @@ -143,11 +151,21 @@ type ClearSessionOptions = { }; export async function clearSession(options: ClearSessionOptions) { + const host = (await headers()).get("host"); + + if (!host || typeof host !== "string") { + throw new Error("No host found"); + } + const { sessionId } = options; const session = await getSessionCookieById({ sessionId }); - const deletedSession = await deleteSession(session.id, session.token); + const deletedSession = await deleteSession({ + host, + sessionId: session.id, + sessionToken: session.token, + }); if (deletedSession) { return removeSessionFromCookie(session); @@ -159,12 +177,19 @@ type CleanupSessionCommand = { }; export async function cleanupSession({ sessionId }: CleanupSessionCommand) { + const host = (await headers()).get("host"); + + if (!host || typeof host !== "string") { + throw new Error("No host found"); + } + const sessionCookie = await getSessionCookieById({ sessionId }); - const deleteResponse = await deleteSession( - sessionCookie.id, - sessionCookie.token, - ); + const deleteResponse = await deleteSession({ + host, + sessionId: sessionCookie.id, + sessionToken: sessionCookie.token, + }); if (!deleteResponse) { throw new Error("Could not delete session"); diff --git a/apps/login/src/lib/server/u2f.ts b/apps/login/src/lib/server/u2f.ts index 5cbd80611bf..8620350656c 100644 --- a/apps/login/src/lib/server/u2f.ts +++ b/apps/login/src/lib/server/u2f.ts @@ -19,6 +19,12 @@ type VerifyU2FCommand = { }; export async function addU2F(command: RegisterU2FCommand) { + const host = (await headers()).get("host"); + + if (!host || typeof host !== "string") { + throw new Error("No host found"); + } + const sessionCookie = await getSessionCookieById({ sessionId: command.sessionId, }); @@ -28,16 +34,11 @@ export async function addU2F(command: RegisterU2FCommand) { } const session = await getSession({ + host, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); - const host = (await headers()).get("host"); - - if (!host) { - return { error: "Could not get domain" }; - } - const [hostname, port] = host.split(":"); if (!hostname) { @@ -50,10 +51,16 @@ export async function addU2F(command: RegisterU2FCommand) { return { error: "Could not get session" }; } - return registerU2F(userId, hostname); + return registerU2F({ host, userId, domain: hostname }); } export async function verifyU2F(command: VerifyU2FCommand) { + const host = (await headers()).get("host"); + + if (!host || typeof host !== "string") { + throw new Error("No host found"); + } + let passkeyName = command.passkeyName; if (!!!passkeyName) { const headersList = await headers(); @@ -69,6 +76,7 @@ export async function verifyU2F(command: VerifyU2FCommand) { }); const session = await getSession({ + host, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }); @@ -79,12 +87,12 @@ export async function verifyU2F(command: VerifyU2FCommand) { return { error: "Could not get session" }; } - const req = create(VerifyU2FRegistrationRequestSchema, { + const request = create(VerifyU2FRegistrationRequestSchema, { u2fId: command.u2fId, publicKeyCredential: command.publicKeyCredential, tokenName: passkeyName, userId, }); - return verifyU2FRegistration(req); + return verifyU2FRegistration({ host, request }); } diff --git a/apps/login/src/lib/server/verify.ts b/apps/login/src/lib/server/verify.ts index 37499c80e39..7b6f0feca7d 100644 --- a/apps/login/src/lib/server/verify.ts +++ b/apps/login/src/lib/server/verify.ts @@ -31,11 +31,25 @@ type VerifyUserByEmailCommand = { }; export async function sendVerification(command: VerifyUserByEmailCommand) { + const host = (await headers()).get("host"); + + if (!host || typeof host !== "string") { + throw new Error("No host found"); + } + const verifyResponse = command.isInvite - ? await verifyInviteCode(command.userId, command.code).catch(() => { + ? await verifyInviteCode({ + host, + userId: command.userId, + verificationCode: command.code, + }).catch(() => { return { error: "Could not verify invite" }; }) - : await verifyEmail(command.userId, command.code).catch(() => { + : await verifyEmail({ + host, + userId: command.userId, + verificationCode: command.code, + }).catch(() => { return { error: "Could not verify email" }; }); @@ -63,6 +77,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { } session = await getSession({ + host, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }).then((response) => { @@ -75,7 +90,10 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { return { error: "Could not create session for user" }; } - const userResponse = await getUserByID(session?.factors?.user?.id); + const userResponse = await getUserByID({ + host, + userId: session?.factors?.user?.id, + }); if (!userResponse?.user) { return { error: "Could not load user" }; @@ -83,7 +101,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { user = userResponse.user; } else { - const userResponse = await getUserByID(command.userId); + const userResponse = await getUserByID({ host, userId: command.userId }); if (!userResponse || !userResponse.user) { return { error: "Could not load user" }; @@ -119,9 +137,15 @@ export async function sendVerification(command: VerifyUserByEmailCommand) { return { error: "Could not load user" }; } - const loginSettings = await getLoginSettings(user.details?.resourceOwner); + const loginSettings = await getLoginSettings({ + host, + organization: user.details?.resourceOwner, + }); - const authMethodResponse = await listAuthenticationMethodTypes(user.userId); + const authMethodResponse = await listAuthenticationMethodTypes({ + host, + userId: user.userId, + }); if (!authMethodResponse || !authMethodResponse.authMethodTypes) { return { error: "Could not load possible authenticators" }; @@ -230,6 +254,12 @@ export type SendVerificationRedirectWithoutCheckCommand = { export async function sendVerificationRedirectWithoutCheck( command: SendVerificationRedirectWithoutCheckCommand, ) { + const host = (await headers()).get("host"); + + if (!host || typeof host !== "string") { + throw new Error("No host found"); + } + if (!("loginName" in command || "userId" in command)) { return { error: "No userId, nor loginname provided" }; } @@ -250,6 +280,7 @@ export async function sendVerificationRedirectWithoutCheck( } session = await getSession({ + host, sessionId: sessionCookie.id, sessionToken: sessionCookie.token, }).then((response) => { @@ -262,7 +293,10 @@ export async function sendVerificationRedirectWithoutCheck( return { error: "Could not create session for user" }; } - const userResponse = await getUserByID(session?.factors?.user?.id); + const userResponse = await getUserByID({ + host, + userId: session?.factors?.user?.id, + }); if (!userResponse?.user) { return { error: "Could not load user" }; @@ -270,7 +304,7 @@ export async function sendVerificationRedirectWithoutCheck( user = userResponse.user; } else if ("userId" in command) { - const userResponse = await getUserByID(command.userId); + const userResponse = await getUserByID({ host, userId: command.userId }); if (!userResponse?.user) { return { error: "Could not load user" }; @@ -306,7 +340,10 @@ export async function sendVerificationRedirectWithoutCheck( return { error: "Could not load user" }; } - const authMethodResponse = await listAuthenticationMethodTypes(user.userId); + const authMethodResponse = await listAuthenticationMethodTypes({ + host, + userId: user.userId, + }); if (!authMethodResponse || !authMethodResponse.authMethodTypes) { return { error: "Could not load possible authenticators" }; @@ -328,7 +365,10 @@ export async function sendVerificationRedirectWithoutCheck( return { redirect: `/authenticator/set?${params}` }; } - const loginSettings = await getLoginSettings(user.details?.resourceOwner); + const loginSettings = await getLoginSettings({ + host, + organization: user.details?.resourceOwner, + }); // redirect to mfa factor if user has one, or redirect to set one up const mfaFactorCheck = checkMFAFactors(