mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-19 14:07:50 +00:00
implement mfa init prompt
This commit is contained in:
@@ -71,7 +71,8 @@
|
|||||||
},
|
},
|
||||||
"set": {
|
"set": {
|
||||||
"title": "2-Faktor einrichten",
|
"title": "2-Faktor einrichten",
|
||||||
"description": "Wählen Sie einen der folgenden zweiten Faktoren."
|
"description": "Wählen Sie einen der folgenden zweiten Faktoren.",
|
||||||
|
"skip": "Überspringen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"otp": {
|
"otp": {
|
||||||
|
@@ -71,7 +71,8 @@
|
|||||||
},
|
},
|
||||||
"set": {
|
"set": {
|
||||||
"title": "Set up 2-Factor",
|
"title": "Set up 2-Factor",
|
||||||
"description": "Choose one of the following second factors."
|
"description": "Choose one of the following second factors.",
|
||||||
|
"skip": "Skip"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"otp": {
|
"otp": {
|
||||||
|
@@ -71,7 +71,8 @@
|
|||||||
},
|
},
|
||||||
"set": {
|
"set": {
|
||||||
"title": "Configurar autenticación de 2 factores",
|
"title": "Configurar autenticación de 2 factores",
|
||||||
"description": "Elige uno de los siguientes factores secundarios."
|
"description": "Elige uno de los siguientes factores secundarios.",
|
||||||
|
"skip": "Omitir"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"otp": {
|
"otp": {
|
||||||
|
@@ -71,7 +71,8 @@
|
|||||||
},
|
},
|
||||||
"set": {
|
"set": {
|
||||||
"title": "Configura l'autenticazione a 2 fattori",
|
"title": "Configura l'autenticazione a 2 fattori",
|
||||||
"description": "Scegli uno dei seguenti secondi fattori."
|
"description": "Scegli uno dei seguenti secondi fattori.",
|
||||||
|
"skip": "Salta"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"otp": {
|
"otp": {
|
||||||
|
@@ -71,7 +71,8 @@
|
|||||||
},
|
},
|
||||||
"set": {
|
"set": {
|
||||||
"title": "设置双因素认证",
|
"title": "设置双因素认证",
|
||||||
"description": "选择以下的一个第二因素。"
|
"description": "选择以下的一个第二因素。",
|
||||||
|
"skip": "跳过"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"otp": {
|
"otp": {
|
||||||
|
@@ -161,6 +161,12 @@ export default async function Page(props: {
|
|||||||
></ChooseSecondFactorToSetup>
|
></ChooseSecondFactorToSetup>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{force !== "true" && (
|
||||||
|
<div>
|
||||||
|
<p>{t("set.skip")}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="mt-8 flex w-full flex-row items-center">
|
<div className="mt-8 flex w-full flex-row items-center">
|
||||||
<BackButton />
|
<BackButton />
|
||||||
<span className="flex-grow"></span>
|
<span className="flex-grow"></span>
|
||||||
|
@@ -16,7 +16,7 @@ import {
|
|||||||
setPassword,
|
setPassword,
|
||||||
setUserPassword,
|
setUserPassword,
|
||||||
} from "@/lib/zitadel";
|
} from "@/lib/zitadel";
|
||||||
import { create } from "@zitadel/client";
|
import { ConnectError, create } from "@zitadel/client";
|
||||||
import { createServerTransport } from "@zitadel/client/node";
|
import { createServerTransport } from "@zitadel/client/node";
|
||||||
import { createUserServiceClient } from "@zitadel/client/v2";
|
import { createUserServiceClient } from "@zitadel/client/v2";
|
||||||
import {
|
import {
|
||||||
@@ -267,7 +267,8 @@ export async function sendPassword(command: UpdateSessionCommand) {
|
|||||||
return { error: "Could not verify password!" };
|
return { error: "Could not verify password!" };
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfaFactorCheck = checkMFAFactors(
|
const mfaFactorCheck = await checkMFAFactors(
|
||||||
|
serviceUrl,
|
||||||
session,
|
session,
|
||||||
loginSettings,
|
loginSettings,
|
||||||
authMethods,
|
authMethods,
|
||||||
@@ -433,7 +434,7 @@ export async function checkSessionAndSetPassword({
|
|||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
)
|
)
|
||||||
.catch((error) => {
|
.catch((error: ConnectError) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
if (error.code === 7) {
|
if (error.code === 7) {
|
||||||
return { error: "Session is not valid." };
|
return { error: "Session is not valid." };
|
||||||
|
@@ -203,7 +203,8 @@ export async function sendVerification(command: VerifyUserByEmailCommand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 = await checkMFAFactors(
|
||||||
|
serviceUrl,
|
||||||
session,
|
session,
|
||||||
loginSettings,
|
loginSettings,
|
||||||
authMethodResponse.authMethodTypes,
|
authMethodResponse.authMethodTypes,
|
||||||
@@ -407,12 +408,12 @@ export async function sendVerificationRedirectWithoutCheck(
|
|||||||
|
|
||||||
const loginSettings = await getLoginSettings({
|
const loginSettings = await getLoginSettings({
|
||||||
serviceUrl,
|
serviceUrl,
|
||||||
|
|
||||||
organization: user.details?.resourceOwner,
|
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 = await checkMFAFactors(
|
||||||
|
serviceUrl,
|
||||||
session,
|
session,
|
||||||
loginSettings,
|
loginSettings,
|
||||||
authMethodResponse.authMethodTypes,
|
authMethodResponse.authMethodTypes,
|
||||||
|
@@ -5,6 +5,7 @@ import { PasswordExpirySettings } from "@zitadel/proto/zitadel/settings/v2/passw
|
|||||||
import { HumanUser } from "@zitadel/proto/zitadel/user/v2/user_pb";
|
import { HumanUser } from "@zitadel/proto/zitadel/user/v2/user_pb";
|
||||||
import { AuthenticationMethodType } from "@zitadel/proto/zitadel/user/v2/user_service_pb";
|
import { AuthenticationMethodType } from "@zitadel/proto/zitadel/user/v2/user_service_pb";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import { getUserByID } from "./zitadel";
|
||||||
|
|
||||||
export function checkPasswordChangeRequired(
|
export function checkPasswordChangeRequired(
|
||||||
expirySettings: PasswordExpirySettings | undefined,
|
expirySettings: PasswordExpirySettings | undefined,
|
||||||
@@ -100,7 +101,8 @@ export function checkEmailVerification(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkMFAFactors(
|
export async function checkMFAFactors(
|
||||||
|
serviceUrl: string,
|
||||||
session: Session,
|
session: Session,
|
||||||
loginSettings: LoginSettings | undefined,
|
loginSettings: LoginSettings | undefined,
|
||||||
authMethods: AuthenticationMethodType[],
|
authMethods: AuthenticationMethodType[],
|
||||||
@@ -188,31 +190,42 @@ export function checkMFAFactors(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: provide a way to setup passkeys on mfa page?
|
||||||
|
return { redirect: `/mfa/set?` + params };
|
||||||
|
} else if (
|
||||||
|
loginSettings?.mfaInitSkipLifetime &&
|
||||||
|
(loginSettings.mfaInitSkipLifetime.nanos > 0 ||
|
||||||
|
loginSettings.mfaInitSkipLifetime.seconds > 0) &&
|
||||||
|
!availableMultiFactors.length &&
|
||||||
|
session?.factors?.user?.id
|
||||||
|
) {
|
||||||
|
const user = await getUserByID({
|
||||||
|
serviceUrl,
|
||||||
|
userId: session.factors?.user?.id,
|
||||||
|
});
|
||||||
|
if (
|
||||||
|
user.user?.type?.case === "human" &&
|
||||||
|
user.user?.type?.value.mfaInitSkipped
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
loginName: session.factors?.user?.loginName as string,
|
||||||
|
force: "false", // this defines if the mfa is not forced in the settings and can be skipped
|
||||||
|
checkAfter: "true", // this defines if the check is directly made after the setup
|
||||||
|
});
|
||||||
|
|
||||||
|
if (requestId) {
|
||||||
|
params.append("requestId", requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (organization || session.factors?.user?.organizationId) {
|
||||||
|
params.append(
|
||||||
|
"organization",
|
||||||
|
organization ?? (session.factors?.user?.organizationId as string),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: provide a way to setup passkeys on mfa page?
|
// TODO: provide a way to setup passkeys on mfa page?
|
||||||
return { redirect: `/mfa/set?` + params };
|
return { redirect: `/mfa/set?` + params };
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement passkey setup
|
|
||||||
|
|
||||||
// else if (
|
|
||||||
// submitted.factors &&
|
|
||||||
// !submitted.factors.webAuthN && // if session was not verified with a passkey
|
|
||||||
// promptPasswordless && // if explicitly prompted due policy
|
|
||||||
// !isAlternative // escaped if password was used as an alternative method
|
|
||||||
// ) {
|
|
||||||
// const params = new URLSearchParams({
|
|
||||||
// loginName: submitted.factors.user.loginName,
|
|
||||||
// prompt: "true",
|
|
||||||
// });
|
|
||||||
|
|
||||||
// if (requestId) {
|
|
||||||
// params.append("requestId", requestId);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (organization) {
|
|
||||||
// params.append("organization", organization);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return router.push(`/passkey/set?` + params);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user