allow account recovery for revoked status users

This commit is contained in:
Kyle Spearrin
2026-04-10 14:06:35 -04:00
parent b3c8950838
commit 67d670d78c
2 changed files with 109 additions and 2 deletions

View File

@@ -49,10 +49,11 @@ public class AdminRecoverAccountValidator(
return Invalid(request, new PolicyNotEnabledError());
}
// Org User must be confirmed and have a ResetPasswordKey
// Org User must be confirmed or revoked and have a ResetPasswordKey
var orgUser = request.OrganizationUser;
if (orgUser == null ||
orgUser.Status != OrganizationUserStatusType.Confirmed ||
(orgUser.Status != OrganizationUserStatusType.Confirmed &&
orgUser.Status != OrganizationUserStatusType.Revoked) ||
orgUser.OrganizationId != request.OrgId ||
!orgUser.IsEnrolledInAccountRecovery() ||
!orgUser.UserId.HasValue)

View File

@@ -600,6 +600,112 @@ public class AdminRecoverAccountValidatorTests
Assert.Equal(request, result.Request);
}
// region Success paths: Revoked users
[Theory]
[BitAutoData]
public async Task ValidateAsync_RevokedUser_ResetMasterPassword_ReturnsValid(
Organization organization,
OrganizationUser organizationUser,
User user,
[Policy(PolicyType.ResetPassword, true)] PolicyStatus policy,
SutProvider<AdminRecoverAccountValidator> sutProvider)
{
// Arrange
SetupValidOrganization(sutProvider, organization);
SetupValidPolicy(sutProvider, organization, policy);
SetupValidOrganizationUser(organizationUser, organization.Id);
organizationUser.Status = OrganizationUserStatusType.Revoked;
SetupValidUser(sutProvider, user, organizationUser);
var request = new RecoverAccountRequest
{
OrgId = organization.Id,
OrganizationUser = organizationUser,
ResetMasterPassword = true,
ResetTwoFactor = false,
NewMasterPasswordHash = "some-hash",
Key = "some-key",
};
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
// Assert
Assert.True(result.IsValid);
Assert.Equal(request, result.Request);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_RevokedUser_ResetTwoFactor_ReturnsValid(
Organization organization,
OrganizationUser organizationUser,
User user,
[Policy(PolicyType.ResetPassword, true)] PolicyStatus policy,
SutProvider<AdminRecoverAccountValidator> sutProvider)
{
// Arrange
SetupValidOrganization(sutProvider, organization);
SetupValidPolicy(sutProvider, organization, policy);
SetupValidOrganizationUser(organizationUser, organization.Id);
organizationUser.Status = OrganizationUserStatusType.Revoked;
SetupValidUser(sutProvider, user, organizationUser);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AdminResetTwoFactor)
.Returns(true);
var request = new RecoverAccountRequest
{
OrgId = organization.Id,
OrganizationUser = organizationUser,
ResetMasterPassword = false,
ResetTwoFactor = true,
};
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
// Assert
Assert.True(result.IsValid);
Assert.Equal(request, result.Request);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_RevokedUser_NotEnrolledInAccountRecovery_ReturnsInvalidOrgUserError(
Organization organization,
OrganizationUser organizationUser,
[Policy(PolicyType.ResetPassword, true)] PolicyStatus policy,
SutProvider<AdminRecoverAccountValidator> sutProvider)
{
// Arrange
SetupValidOrganization(sutProvider, organization);
SetupValidPolicy(sutProvider, organization, policy);
organizationUser.Status = OrganizationUserStatusType.Revoked;
organizationUser.OrganizationId = organization.Id;
organizationUser.ResetPasswordKey = null; // Not enrolled
organizationUser.UserId = Guid.NewGuid();
var request = new RecoverAccountRequest
{
OrgId = organization.Id,
OrganizationUser = organizationUser,
ResetMasterPassword = true,
ResetTwoFactor = false,
NewMasterPasswordHash = "some-hash",
Key = "some-key",
};
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<InvalidOrgUserError>(result.AsError);
}
// region Helper methods
private static void SetupValidOrganization(