host context

This commit is contained in:
Max Peintner
2025-01-16 09:50:25 +01:00
parent c3ba56870f
commit 18dbffc02d
4 changed files with 106 additions and 31 deletions

View File

@@ -31,6 +31,7 @@ export async function createSessionAndUpdateCookie(
checks: Checks, checks: Checks,
challenges: RequestChallenges | undefined, challenges: RequestChallenges | undefined,
authRequestId: string | undefined, authRequestId: string | undefined,
lifetime?: Duration,
): Promise<Session> { ): Promise<Session> {
const host = (await headers()).get("host"); const host = (await headers()).get("host");
@@ -42,6 +43,7 @@ export async function createSessionAndUpdateCookie(
host, host,
checks, checks,
challenges, challenges,
lifetime,
}); });
if (createdSession) { if (createdSession) {

View File

@@ -23,9 +23,16 @@ export async function continueWithSession({
authRequestId, authRequestId,
...session ...session
}: Session & { authRequestId?: string }) { }: Session & { authRequestId?: string }) {
const loginSettings = await getLoginSettings( const host = (await headers()).get("host");
session.factors?.user?.organizationId,
); if (!host || typeof host !== "string") {
throw new Error("No host found");
}
const loginSettings = await getLoginSettings({
host,
organization: session.factors?.user?.organizationId,
});
const url = const url =
authRequestId && session.id && session.factors?.user authRequestId && session.id && session.factors?.user
@@ -99,7 +106,7 @@ export async function updateSession(options: UpdateSessionCommand) {
challenges.webAuthN.domain = hostname; challenges.webAuthN.domain = hostname;
} }
const loginSettings = await getLoginSettings(organization); const loginSettings = await getLoginSettings({ host, organization });
const lifetime = checks?.webAuthN const lifetime = checks?.webAuthN
? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey ? 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 // if password, check if user has MFA methods
let authMethods; let authMethods;
if (checks && checks.password && session.factors?.user?.id) { if (checks && checks.password && session.factors?.user?.id) {
const response = await listAuthenticationMethodTypes( const response = await listAuthenticationMethodTypes({
session.factors.user.id, host,
); userId: session.factors.user.id,
});
if (response.authMethodTypes && response.authMethodTypes.length) { if (response.authMethodTypes && response.authMethodTypes.length) {
authMethods = response.authMethodTypes; authMethods = response.authMethodTypes;
} }
@@ -143,11 +151,21 @@ type ClearSessionOptions = {
}; };
export async function clearSession(options: 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 { sessionId } = options;
const session = await getSessionCookieById({ sessionId }); 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) { if (deletedSession) {
return removeSessionFromCookie(session); return removeSessionFromCookie(session);
@@ -159,12 +177,19 @@ type CleanupSessionCommand = {
}; };
export async function cleanupSession({ sessionId }: 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 sessionCookie = await getSessionCookieById({ sessionId });
const deleteResponse = await deleteSession( const deleteResponse = await deleteSession({
sessionCookie.id, host,
sessionCookie.token, sessionId: sessionCookie.id,
); sessionToken: sessionCookie.token,
});
if (!deleteResponse) { if (!deleteResponse) {
throw new Error("Could not delete session"); throw new Error("Could not delete session");

View File

@@ -19,6 +19,12 @@ type VerifyU2FCommand = {
}; };
export async function addU2F(command: RegisterU2FCommand) { 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({ const sessionCookie = await getSessionCookieById({
sessionId: command.sessionId, sessionId: command.sessionId,
}); });
@@ -28,16 +34,11 @@ export async function addU2F(command: RegisterU2FCommand) {
} }
const session = await getSession({ const session = await getSession({
host,
sessionId: sessionCookie.id, sessionId: sessionCookie.id,
sessionToken: sessionCookie.token, sessionToken: sessionCookie.token,
}); });
const host = (await headers()).get("host");
if (!host) {
return { error: "Could not get domain" };
}
const [hostname, port] = host.split(":"); const [hostname, port] = host.split(":");
if (!hostname) { if (!hostname) {
@@ -50,10 +51,16 @@ export async function addU2F(command: RegisterU2FCommand) {
return { error: "Could not get session" }; return { error: "Could not get session" };
} }
return registerU2F(userId, hostname); return registerU2F({ host, userId, domain: hostname });
} }
export async function verifyU2F(command: VerifyU2FCommand) { 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; let passkeyName = command.passkeyName;
if (!!!passkeyName) { if (!!!passkeyName) {
const headersList = await headers(); const headersList = await headers();
@@ -69,6 +76,7 @@ export async function verifyU2F(command: VerifyU2FCommand) {
}); });
const session = await getSession({ const session = await getSession({
host,
sessionId: sessionCookie.id, sessionId: sessionCookie.id,
sessionToken: sessionCookie.token, sessionToken: sessionCookie.token,
}); });
@@ -79,12 +87,12 @@ export async function verifyU2F(command: VerifyU2FCommand) {
return { error: "Could not get session" }; return { error: "Could not get session" };
} }
const req = create(VerifyU2FRegistrationRequestSchema, { const request = create(VerifyU2FRegistrationRequestSchema, {
u2fId: command.u2fId, u2fId: command.u2fId,
publicKeyCredential: command.publicKeyCredential, publicKeyCredential: command.publicKeyCredential,
tokenName: passkeyName, tokenName: passkeyName,
userId, userId,
}); });
return verifyU2FRegistration(req); return verifyU2FRegistration({ host, request });
} }

View File

@@ -31,11 +31,25 @@ type VerifyUserByEmailCommand = {
}; };
export async function sendVerification(command: 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 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" }; 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" }; return { error: "Could not verify email" };
}); });
@@ -63,6 +77,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) {
} }
session = await getSession({ session = await getSession({
host,
sessionId: sessionCookie.id, sessionId: sessionCookie.id,
sessionToken: sessionCookie.token, sessionToken: sessionCookie.token,
}).then((response) => { }).then((response) => {
@@ -75,7 +90,10 @@ export async function sendVerification(command: VerifyUserByEmailCommand) {
return { error: "Could not create session for user" }; 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) { if (!userResponse?.user) {
return { error: "Could not load user" }; return { error: "Could not load user" };
@@ -83,7 +101,7 @@ export async function sendVerification(command: VerifyUserByEmailCommand) {
user = userResponse.user; user = userResponse.user;
} else { } else {
const userResponse = await getUserByID(command.userId); const userResponse = await getUserByID({ host, userId: command.userId });
if (!userResponse || !userResponse.user) { if (!userResponse || !userResponse.user) {
return { error: "Could not load user" }; return { error: "Could not load user" };
@@ -119,9 +137,15 @@ export async function sendVerification(command: VerifyUserByEmailCommand) {
return { error: "Could not load user" }; 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) { if (!authMethodResponse || !authMethodResponse.authMethodTypes) {
return { error: "Could not load possible authenticators" }; return { error: "Could not load possible authenticators" };
@@ -230,6 +254,12 @@ export type SendVerificationRedirectWithoutCheckCommand = {
export async function sendVerificationRedirectWithoutCheck( export async function sendVerificationRedirectWithoutCheck(
command: SendVerificationRedirectWithoutCheckCommand, 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)) { if (!("loginName" in command || "userId" in command)) {
return { error: "No userId, nor loginname provided" }; return { error: "No userId, nor loginname provided" };
} }
@@ -250,6 +280,7 @@ export async function sendVerificationRedirectWithoutCheck(
} }
session = await getSession({ session = await getSession({
host,
sessionId: sessionCookie.id, sessionId: sessionCookie.id,
sessionToken: sessionCookie.token, sessionToken: sessionCookie.token,
}).then((response) => { }).then((response) => {
@@ -262,7 +293,10 @@ export async function sendVerificationRedirectWithoutCheck(
return { error: "Could not create session for user" }; 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) { if (!userResponse?.user) {
return { error: "Could not load user" }; return { error: "Could not load user" };
@@ -270,7 +304,7 @@ export async function sendVerificationRedirectWithoutCheck(
user = userResponse.user; user = userResponse.user;
} else if ("userId" in command) { } else if ("userId" in command) {
const userResponse = await getUserByID(command.userId); const userResponse = await getUserByID({ host, userId: command.userId });
if (!userResponse?.user) { if (!userResponse?.user) {
return { error: "Could not load user" }; return { error: "Could not load user" };
@@ -306,7 +340,10 @@ export async function sendVerificationRedirectWithoutCheck(
return { error: "Could not load user" }; return { error: "Could not load user" };
} }
const authMethodResponse = await listAuthenticationMethodTypes(user.userId); const authMethodResponse = await listAuthenticationMethodTypes({
host,
userId: user.userId,
});
if (!authMethodResponse || !authMethodResponse.authMethodTypes) { if (!authMethodResponse || !authMethodResponse.authMethodTypes) {
return { error: "Could not load possible authenticators" }; return { error: "Could not load possible authenticators" };
@@ -328,7 +365,10 @@ export async function sendVerificationRedirectWithoutCheck(
return { redirect: `/authenticator/set?${params}` }; 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 // redirect to mfa factor if user has one, or redirect to set one up
const mfaFactorCheck = checkMFAFactors( const mfaFactorCheck = checkMFAFactors(