fix(iam): actually enforce MFA
forceMFA never took effect because of the JSON key. ZITADEL's v1 endpoint speaks protojson, which accepts "forceMfa" (lowerCamel of force_mfa). The spelling "forceMFA" is treated as an unknown field and silently dropped, so every earlier run returned 200 with a new sequence while force_mfa stayed false in projections.login_policies5. Send forceMfa and forceMfaLocalOnly. Verified in the database: force_mfa = t | force_mfa_local_only = t | mfa_init_skip_lifetime = 0 and in the login flow: after the password step the browser lands on /ui/login/mfa/prompt with the "2-Factor Setup" page, so a second factor is now required instead of optional.
This commit is contained in:
@@ -420,15 +420,20 @@ def _ensure_smtp(token: str) -> str:
|
|||||||
def _ensure_login_policy(token: str) -> None:
|
def _ensure_login_policy(token: str) -> None:
|
||||||
"""Require password + a second factor, and demand enrolment at login.
|
"""Require password + a second factor, and demand enrolment at login.
|
||||||
|
|
||||||
forceMFA does not persist through the v1 policy endpoint (it reads back
|
Enforcement needs forceMfa. The v1 endpoint ignores the spelling "forceMFA"
|
||||||
absent), so the effective lever is mfaInitSkipLifetime: 0s, which makes the
|
as an unknown field, which is why earlier runs looked successful while
|
||||||
login flow require enrolment instead of letting a user skip it for 30 days.
|
projections.login_policies5 kept force_mfa = false.
|
||||||
|
|
||||||
Second factors stay OTP and U2F: an authenticator app or a hardware key.
|
Second factors stay OTP and U2F: an authenticator app or a hardware key.
|
||||||
Multi-factor is left configured for U2F with verification so a later step
|
Multi-factor is left configured for U2F with verification so a later step
|
||||||
can move 2FA to 2MFA without another policy change.
|
can move 2FA to 2MFA without another policy change.
|
||||||
"""
|
"""
|
||||||
code, d = _api("PUT", "/admin/v1/policies/login", token, {
|
code, d = _api("PUT", "/admin/v1/policies/login", token, {
|
||||||
|
# Case matters: protojson accepts "forceMfa", the lowerCamel form of
|
||||||
|
# force_mfa. Sending "forceMFA" is silently ignored as an unknown field,
|
||||||
|
# so the policy looks unchanged and MFA is never enforced.
|
||||||
|
"forceMfa": True,
|
||||||
|
"forceMfaLocalOnly": True,
|
||||||
"allowUsernamePassword": True,
|
"allowUsernamePassword": True,
|
||||||
"allowRegister": False,
|
"allowRegister": False,
|
||||||
"allowExternalIDP": True,
|
"allowExternalIDP": True,
|
||||||
|
|||||||
Reference in New Issue
Block a user