Browse Source
* 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.pull/5745/head
18 changed files with 318 additions and 16 deletions
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
using Bit.Core.Entities; |
||||
using Xunit; |
||||
|
||||
namespace Bit.Core.Test.AdminConsole.Entities; |
||||
|
||||
public class OrganizationUserTests |
||||
{ |
||||
[Theory] |
||||
[InlineData(null)] |
||||
[InlineData("")] |
||||
[InlineData(" ")] |
||||
public void IsValidResetPasswordKey_InvalidKeys_ReturnsFalse(string? resetPasswordKey) |
||||
{ |
||||
Assert.False(OrganizationUser.IsValidResetPasswordKey(resetPasswordKey)); |
||||
} |
||||
|
||||
[Fact] |
||||
public void IsValidResetPasswordKey_ValidKey_ReturnsTrue() |
||||
{ |
||||
Assert.True(OrganizationUser.IsValidResetPasswordKey("validKey")); |
||||
} |
||||
|
||||
[Fact] |
||||
public void IsEnrolledInAccountRecovery_NullKey_ReturnsFalse() |
||||
{ |
||||
var orgUser = new OrganizationUser { ResetPasswordKey = null }; |
||||
|
||||
Assert.False(orgUser.IsEnrolledInAccountRecovery()); |
||||
} |
||||
|
||||
[Fact] |
||||
public void IsEnrolledInAccountRecovery_ValidKey_ReturnsTrue() |
||||
{ |
||||
var orgUser = new OrganizationUser { ResetPasswordKey = "validKey" }; |
||||
|
||||
Assert.True(orgUser.IsEnrolledInAccountRecovery()); |
||||
} |
||||
} |
||||
@ -0,0 +1,107 @@
@@ -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); |
||||
}); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue