mirror of
https://github.com/bitwarden/server
synced 2026-02-26 01:13:35 +00:00
[PM-21179] Add interface to check if user is enrolled in account recovery (#6993)
* Add validation for reset password key and account recovery enrollment in OrganizationUser * Update admin approval logic to check account recovery enrollment and add tests for reset password key validation * Enhance UserService validation to include account recovery enrollment and add unit test for empty or whitespace reset password key handling * Refactor OrganizationUserUserDetailsQuery to validate reset password keys and add unit tests for filtering out invalid keys * Update AdminRecoverAccountCommand to validate account recovery enrollment and adjust tests for whitespace reset password keys * Enhance OrganizationUserRotationValidator to validate reset password keys, including filtering out whitespace-only keys, and add corresponding unit tests for validation logic. * Refactor OrganizationUserUserDetailsQueryTests to remove unnecessary whitespace-only test cases for account recovery key validation. * Refactor MemberResponseModel to use OrganizationUser's validation method for ResetPasswordEnrolled status and update corresponding unit test for clarity. * Refactor OrganizationUsersController and response models to utilize OrganizationUser's validation method for ResetPasswordKey, ensuring consistent validation across the application. Add unit tests for OrganizationUser to verify key validation logic. * Update OrganizationUserRotationValidator to handle null reset password keys and adjust tests for client-side bug. Add comments for future migration after resolving PM-31001. * Fix whitespace issue in UserServiceTests.cs by removing BOM character from the file header.
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
||||
using Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Requests;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationUserUserDetailsQueryTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData(" ")]
|
||||
public async Task GetAccountRecoveryEnrolledUsers_InvalidKey_FiltersOut(
|
||||
string invalidKey,
|
||||
Guid orgId,
|
||||
SutProvider<OrganizationUserUserDetailsQuery> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var request = new OrganizationUserUserDetailsQueryRequest { OrganizationId = orgId };
|
||||
|
||||
var validUser = CreateOrgUserDetails(orgId, "valid-key");
|
||||
var invalidUser = CreateOrgUserDetails(orgId, invalidKey);
|
||||
var allUsers = new[] { validUser, invalidUser };
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyDetailsByOrganizationAsync_vNext(orgId, false, false)
|
||||
.Returns(allUsers);
|
||||
|
||||
SetupTwoFactorAndClaimedStatus(sutProvider, orgId);
|
||||
|
||||
// Act
|
||||
var result = (await sutProvider.Sut.GetAccountRecoveryEnrolledUsers(request)).ToList();
|
||||
|
||||
// Assert - invalid key user should be filtered out
|
||||
Assert.Single(result);
|
||||
Assert.Equal(validUser.Id, result[0].OrgUser.Id);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetAccountRecoveryEnrolledUsers_NullKey_FiltersOut(
|
||||
Guid orgId,
|
||||
SutProvider<OrganizationUserUserDetailsQuery> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
var request = new OrganizationUserUserDetailsQueryRequest { OrganizationId = orgId };
|
||||
|
||||
var validUser = CreateOrgUserDetails(orgId, "valid-key");
|
||||
var nullUser = CreateOrgUserDetails(orgId, null!);
|
||||
var allUsers = new[] { validUser, nullUser };
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyDetailsByOrganizationAsync_vNext(orgId, false, false)
|
||||
.Returns(allUsers);
|
||||
|
||||
SetupTwoFactorAndClaimedStatus(sutProvider, orgId);
|
||||
|
||||
// Act
|
||||
var result = (await sutProvider.Sut.GetAccountRecoveryEnrolledUsers(request)).ToList();
|
||||
|
||||
// Assert
|
||||
Assert.Single(result);
|
||||
Assert.Equal(validUser.Id, result[0].OrgUser.Id);
|
||||
}
|
||||
|
||||
private static OrganizationUserUserDetails CreateOrgUserDetails(Guid orgId, string resetPasswordKey)
|
||||
{
|
||||
return new OrganizationUserUserDetails
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
OrganizationId = orgId,
|
||||
UserId = Guid.NewGuid(),
|
||||
Status = OrganizationUserStatusType.Confirmed,
|
||||
Type = OrganizationUserType.User,
|
||||
UsesKeyConnector = false,
|
||||
ResetPasswordKey = resetPasswordKey,
|
||||
Email = "test@example.com"
|
||||
};
|
||||
}
|
||||
|
||||
private static void SetupTwoFactorAndClaimedStatus(
|
||||
SutProvider<OrganizationUserUserDetailsQuery> sutProvider, Guid orgId)
|
||||
{
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<OrganizationUserUserDetails>>())
|
||||
.Returns(callInfo =>
|
||||
{
|
||||
var users = callInfo.Arg<IEnumerable<OrganizationUserUserDetails>>();
|
||||
return users.Select(u => (user: u, twoFactorIsEnabled: false)).ToList();
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IGetOrganizationUsersClaimedStatusQuery>()
|
||||
.GetUsersOrganizationClaimedStatusAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns(callInfo =>
|
||||
{
|
||||
var userIds = callInfo.Arg<IEnumerable<Guid>>();
|
||||
return userIds.ToDictionary(id => id, _ => false);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user