From 8d4f6082ca9bcffa4b5bb7bf2d20dc78f443977d Mon Sep 17 00:00:00 2001 From: Livio Spring Date: Tue, 11 Nov 2025 06:55:59 +0100 Subject: [PATCH] fix(authz): ignore unready auth methods for mfa requirement check (#11056) # Which Problems Are Solved The recent [fix](https://github.com/zitadel/zitadel/commit/2a7db648817d95eaf6716b12345f958eecdff15d) made sure the Zitadel API always requires MFA if a user has set up so even though not required by the login policy. After the deployment, multiple users reached out that also users without any MFA set up got the corresponding `[permission_denied] mfa required (AUTHZ-KI3p0)`error. # How the Problems Are Solved - Only check the set up factors with are verified and ready to use. Ignore all unready auth methods. # Additional Changes None # Additional Context - relates to https://github.com/zitadel/zitadel/commit/2a7db648817d95eaf6716b12345f958eecdff15d - closes https://github.com/zitadel/zitadel/issues/11055 - requires backport to v2.71.x, v3.x and v4.x (cherry picked from commit e4a959c3217a456bcbc6558e5df57484653fd7f0) --- .../session/v2/integration_test/session_test.go | 15 +++++++++++++-- .../query/user_auth_method_types_required.sql | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/internal/api/grpc/session/v2/integration_test/session_test.go b/internal/api/grpc/session/v2/integration_test/session_test.go index 88eedd22258..5cfbab97b0b 100644 --- a/internal/api/grpc/session/v2/integration_test/session_test.go +++ b/internal/api/grpc/session/v2/integration_test/session_test.go @@ -972,11 +972,22 @@ func Test_ZITADEL_API_missing_authentication(t *testing.T) { func Test_ZITADEL_API_missing_mfa(t *testing.T) { mfaUser := createFullUser(CTX) - registerTOTP(CTX, t, mfaUser.GetUserId()) + + // make sure the session works even with a not fully set up MFA factor + _, err := Instance.Client.UserV2.RegisterTOTP(CTX, &user.RegisterTOTPRequest{ + UserId: mfaUser.GetUserId(), + }) + require.NoError(t, err) id, token, _, _ := Instance.CreatePasswordSession(t, LoginCTX, mfaUser.GetUserId(), integration.UserPassword) ctx := integration.WithAuthorizationToken(context.Background(), token) - sessionResp, err := Instance.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id}) + require.NoError(t, err) + + // now fully set up MFA and make sure the session is rejected without MFA + registerTOTP(CTX, t, mfaUser.GetUserId()) + id, token, _, _ = Instance.CreatePasswordSession(t, LoginCTX, mfaUser.GetUserId(), integration.UserPassword) + ctx = integration.WithAuthorizationToken(context.Background(), token) + sessionResp, err = Instance.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id}) require.Error(t, err) require.Nil(t, sessionResp) } diff --git a/internal/query/user_auth_method_types_required.sql b/internal/query/user_auth_method_types_required.sql index 3c24b39fc9e..058c1abc138 100644 --- a/internal/query/user_auth_method_types_required.sql +++ b/internal/query/user_auth_method_types_required.sql @@ -19,6 +19,7 @@ LEFT JOIN LATERAL ( WHERE projections.user_auth_methods5.user_id = projections.users14.id AND projections.user_auth_methods5.instance_id = projections.users14.instance_id + AND projections.user_auth_methods5.state = 2 ) AS user_auth_methods5 ON TRUE WHERE projections.users14.id = $1