mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-07 14:52:15 +00:00
fix: make recovery code active on add (#11734)
# Which Problems Are Solved - Recovery codes added via `GenerateRecoveryCodes` were never listed as active authentication methods by `ListAuthenticationMethodTypes`. The `user_auth_method` projection reducer (`reduceInitAuthMethod`) set the state to `MFAStateNotReady`, expecting a subsequent verification event to transition it to `MFAStateReady`. Unlike TOTP, U2F, and Passwordless — which all have distinct verification events — recovery codes have no such event, so they were permanently stuck in `NotReady`. # How the Problems Are Solved - Introduced a dedicated `reduceAddRecoveryCodes` reducer for `HumanRecoveryCodesAddedEvent` that sets `MFAStateReady` immediately, since recovery codes are usable as soon as they are generated. - Uses `NewUpsertStatement` (instead of `NewCreateStatement`) so that regenerating recovery codes for the same user updates the existing row rather than failing on a duplicate key conflict. - Removed the `HumanRecoveryCodesAddedEvent` case from `reduceInitAuthMethod`. # Additional Changes - Added `UserAuthMethodTypeRecoveryCode` mapping in `authMethodTypeToPb` unit test. - Added integration tests for `ListAuthenticationMethodTypes` covering both the "recovery codes present" and "recovery codes removed" cases. # Additional Context * https://github.com/zitadel/zitadel/issues/11317 --------- Co-authored-by: Marco A. <[email protected]> Co-authored-by: Cursor <[email protected]>
This commit is contained in:
co-authored by
Marco A.
Cursor
parent
f99142bc4a
commit
ec7a6d5526
@@ -1972,6 +1972,24 @@ func TestServer_ListAuthenticationMethodTypes(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
userIDWithRecoveryCodes := Instance.CreateHumanUser(OrgCTX).GetUserId()
|
||||
_, err = Client.GenerateRecoveryCodes(OrgCTX, &user.GenerateRecoveryCodesRequest{
|
||||
UserId: userIDWithRecoveryCodes,
|
||||
Count: 5,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
userIDWithRemovedRecoveryCodes := Instance.CreateHumanUser(OrgCTX).GetUserId()
|
||||
_, err = Client.GenerateRecoveryCodes(OrgCTX, &user.GenerateRecoveryCodesRequest{
|
||||
UserId: userIDWithRemovedRecoveryCodes,
|
||||
Count: 5,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = Client.RemoveRecoveryCodes(OrgCTX, &user.RemoveRecoveryCodesRequest{
|
||||
UserId: userIDWithRemovedRecoveryCodes,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, userLegacyID := ctxFromNewUserWithVerifiedPasswordlessLegacy(t)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -2149,6 +2167,37 @@ func TestServer_ListAuthenticationMethodTypes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with auth (recovery codes)",
|
||||
args: args{
|
||||
OrgCTX,
|
||||
&user.ListAuthenticationMethodTypesRequest{
|
||||
UserId: userIDWithRecoveryCodes,
|
||||
},
|
||||
},
|
||||
want: &user.ListAuthenticationMethodTypesResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 1,
|
||||
},
|
||||
AuthMethodTypes: []user.AuthenticationMethodType{
|
||||
user.AuthenticationMethodType_AUTHENTICATION_METHOD_TYPE_RECOVERY_CODE,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "with removed recovery codes",
|
||||
args: args{
|
||||
OrgCTX,
|
||||
&user.ListAuthenticationMethodTypesRequest{
|
||||
UserId: userIDWithRemovedRecoveryCodes,
|
||||
},
|
||||
},
|
||||
want: &user.ListAuthenticationMethodTypesResponse{
|
||||
Details: &object.ListDetails{
|
||||
TotalResult: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user