1
0
mirror of https://github.com/bitwarden/server synced 2025-12-25 12:43:14 +00:00

[PM-27131] Auto confirm policy requirement (#6649)

* Added Auto confirm policy enforcement requirement. Includes strict single org enforcement along with blocking provider users from joining orgs with auto confirm enabled.
This commit is contained in:
Jared McCannon
2025-12-15 15:40:00 -06:00
committed by GitHub
parent bead4f1d5a
commit e646b91a50
20 changed files with 1488 additions and 238 deletions

View File

@@ -2,6 +2,7 @@
using AutoFixture;
using AutoFixture.Xunit2;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.Enums;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
namespace Bit.Core.Test.AdminConsole.AutoFixture;
@@ -9,10 +10,16 @@ namespace Bit.Core.Test.AdminConsole.AutoFixture;
internal class OrganizationUserPolicyDetailsCustomization : ICustomization
{
public PolicyType Type { get; set; }
public OrganizationUserStatusType Status { get; set; }
public OrganizationUserType UserType { get; set; }
public bool IsProvider { get; set; }
public OrganizationUserPolicyDetailsCustomization(PolicyType type)
public OrganizationUserPolicyDetailsCustomization(PolicyType type, OrganizationUserStatusType status, OrganizationUserType userType, bool isProvider)
{
Type = type;
Status = status;
UserType = userType;
IsProvider = isProvider;
}
public void Customize(IFixture fixture)
@@ -20,6 +27,9 @@ internal class OrganizationUserPolicyDetailsCustomization : ICustomization
fixture.Customize<OrganizationUserPolicyDetails>(composer => composer
.With(o => o.OrganizationId, Guid.NewGuid())
.With(o => o.PolicyType, Type)
.With(o => o.OrganizationUserStatus, Status)
.With(o => o.OrganizationUserType, UserType)
.With(o => o.IsProvider, IsProvider)
.With(o => o.PolicyEnabled, true));
}
}
@@ -27,14 +37,25 @@ internal class OrganizationUserPolicyDetailsCustomization : ICustomization
public class OrganizationUserPolicyDetailsAttribute : CustomizeAttribute
{
private readonly PolicyType _type;
private readonly OrganizationUserStatusType _status;
private readonly OrganizationUserType _userType;
private readonly bool _isProvider;
public OrganizationUserPolicyDetailsAttribute(PolicyType type)
public OrganizationUserPolicyDetailsAttribute(PolicyType type) : this(type, OrganizationUserStatusType.Accepted, OrganizationUserType.User, false)
{
_type = type;
}
public OrganizationUserPolicyDetailsAttribute(PolicyType type, OrganizationUserStatusType status, OrganizationUserType userType, bool isProvider)
{
_type = type;
_status = status;
_userType = userType;
_isProvider = isProvider;
}
public override ICustomization GetCustomization(ParameterInfo parameter)
{
return new OrganizationUserPolicyDetailsCustomization(_type);
return new OrganizationUserPolicyDetailsCustomization(_type, _status, _userType, _isProvider);
}
}

View File

@@ -1,7 +1,9 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoConfirm;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Models.Business.Tokenables;
@@ -24,6 +26,7 @@ using Bit.Test.Common.Fakes;
using Microsoft.AspNetCore.DataProtection;
using NSubstitute;
using Xunit;
using static Bit.Core.AdminConsole.Utilities.v2.Validation.ValidationResultHelpers;
namespace Bit.Core.Test.OrganizationFeatures.OrganizationUsers;
@@ -673,6 +676,79 @@ public class AcceptOrgUserCommandTests
Assert.Equal("User not found within organization.", exception.Message);
}
// Auto-confirm policy validation tests --------------------------------------------------------------------------
[Theory]
[BitAutoData]
public async Task AcceptOrgUserAsync_WithAutoConfirmIsNotEnabled_DoesNotCheckCompliance(
SutProvider<AcceptOrgUserCommand> sutProvider,
User user, Organization org, OrganizationUser orgUser, OrganizationUserUserDetails adminUserDetails)
{
// Arrange
SetupCommonAcceptOrgUserMocks(sutProvider, user, org, orgUser, adminUserDetails);
// Act
var resultOrgUser = await sutProvider.Sut.AcceptOrgUserAsync(orgUser, user, _userService);
// Assert
AssertValidAcceptedOrgUser(resultOrgUser, orgUser, user);
await sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>().DidNotReceiveWithAnyArgs()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>());
}
[Theory]
[BitAutoData]
public async Task AcceptOrgUserAsync_WithUserThatIsCompliantWithAutoConfirm_AcceptsUser(
SutProvider<AcceptOrgUserCommand> sutProvider,
User user, Organization org, OrganizationUser orgUser, OrganizationUserUserDetails adminUserDetails)
{
// Arrange
SetupCommonAcceptOrgUserMocks(sutProvider, user, org, orgUser, adminUserDetails);
// Mock auto-confirm enforcement query to return valid (no auto-confirm restrictions)
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser], user)));
// Act
var resultOrgUser = await sutProvider.Sut.AcceptOrgUserAsync(orgUser, user, _userService);
// Assert
AssertValidAcceptedOrgUser(resultOrgUser, orgUser, user);
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).ReplaceAsync(
Arg.Is<OrganizationUser>(ou => ou.Id == orgUser.Id && ou.Status == OrganizationUserStatusType.Accepted));
}
[Theory]
[BitAutoData]
public async Task AcceptOrgUserAsync_WithAutoConfirmIsEnabledAndFailsCompliance_ThrowsBadRequestException(
SutProvider<AcceptOrgUserCommand> sutProvider,
User user, Organization org, OrganizationUser orgUser, OrganizationUserUserDetails adminUserDetails,
OrganizationUser otherOrgUser)
{
// Arrange
SetupCommonAcceptOrgUserMocks(sutProvider, user, org, orgUser, adminUserDetails);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser, otherOrgUser], user),
new UserCannotBelongToAnotherOrganization()));
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.AcceptOrgUserAsync(orgUser, user, _userService));
// Should get auto-confirm error
Assert.Equal(new UserCannotBelongToAnotherOrganization().Message, exception.Message);
}
// Private helpers -------------------------------------------------------------------------------------------------
/// <summary>
@@ -716,7 +792,7 @@ public class AcceptOrgUserCommandTests
/// - Provides mock data for an admin to validate email functionality.
/// - Returns the corresponding organization for the given org ID.
/// </summary>
private void SetupCommonAcceptOrgUserMocks(SutProvider<AcceptOrgUserCommand> sutProvider, User user,
private static void SetupCommonAcceptOrgUserMocks(SutProvider<AcceptOrgUserCommand> sutProvider, User user,
Organization org,
OrganizationUser orgUser, OrganizationUserUserDetails adminUserDetails)
{
@@ -729,18 +805,12 @@ public class AcceptOrgUserCommandTests
// User is not part of any other orgs
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns(
Task.FromResult<ICollection<OrganizationUser>>(new List<OrganizationUser>())
);
.Returns([]);
// Org they are trying to join does not have single org policy
sutProvider.GetDependency<IPolicyService>()
.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg, OrganizationUserStatusType.Invited)
.Returns(
Task.FromResult<ICollection<OrganizationUserPolicyDetails>>(
new List<OrganizationUserPolicyDetails>()
)
);
.Returns([]);
// User is not part of any organization that applies the single org policy
sutProvider.GetDependency<IPolicyService>()
@@ -750,20 +820,24 @@ public class AcceptOrgUserCommandTests
// Org does not require 2FA
sutProvider.GetDependency<IPolicyService>().GetPoliciesApplicableToUserAsync(user.Id,
PolicyType.TwoFactorAuthentication, OrganizationUserStatusType.Invited)
.Returns(Task.FromResult<ICollection<OrganizationUserPolicyDetails>>(
new List<OrganizationUserPolicyDetails>()));
.Returns([]);
// Provide at least 1 admin to test email functionality
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByMinimumRoleAsync(orgUser.OrganizationId, OrganizationUserType.Admin)
.Returns(Task.FromResult<IEnumerable<OrganizationUserUserDetails>>(
new List<OrganizationUserUserDetails>() { adminUserDetails }
));
.Returns([adminUserDetails]);
// Return org
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(org.Id)
.Returns(Task.FromResult(org));
.Returns(org);
// Auto-confirm enforcement query returns valid by default (no restrictions)
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser], user);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(request)
.Returns(Valid(request));
}

View File

@@ -5,6 +5,7 @@ using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoConfirm;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
@@ -12,6 +13,7 @@ using Bit.Core.Billing.Enums;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.AdminConsole.AutoFixture;
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
using Bit.Core.Test.AutoFixture.OrganizationUserFixtures;
@@ -19,6 +21,7 @@ using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
using static Bit.Core.AdminConsole.Utilities.v2.Validation.ValidationResultHelpers;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUsers;
@@ -116,11 +119,11 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true, planType: PlanType.EnterpriseAnnually)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
Guid userId,
User user,
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
{
// Arrange
organizationUser.UserId = userId;
organizationUser.UserId = user.Id;
organizationUser.OrganizationId = organization.Id;
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
@@ -140,12 +143,23 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
.Returns([(userId, true)]);
.Returns([(user.Id, true)]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(userId)
.GetManyByUserAsync(user.Id)
.Returns([organizationUser]);
sutProvider.GetDependency<IUserService>()
.GetUserByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(
new AutomaticUserConfirmationPolicyEnforcementRequest(organization.Id,
[organizationUser],
user)));
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
@@ -319,11 +333,11 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
Guid userId,
User user,
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
{
// Arrange
organizationUser.UserId = userId;
organizationUser.UserId = user.Id;
organizationUser.OrganizationId = organization.Id;
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
@@ -343,12 +357,24 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
.Returns([(userId, true)]);
.Returns([(user.Id, true)]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(userId)
.GetManyByUserAsync(user.Id)
.Returns([organizationUser]);
sutProvider.GetDependency<IUserService>()
.GetUserByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(
new AutomaticUserConfirmationPolicyEnforcementRequest(organization.Id,
[organizationUser],
user)));
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
@@ -362,11 +388,11 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
Guid userId,
User user,
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
{
// Arrange
organizationUser.UserId = userId;
organizationUser.UserId = user.Id;
organizationUser.OrganizationId = organization.Id;
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
@@ -386,16 +412,28 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
.Returns([(userId, false)]);
.Returns([(user.Id, false)]);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<RequireTwoFactorPolicyRequirement>(userId)
.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(new RequireTwoFactorPolicyRequirement([])); // No 2FA policy
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(userId)
.GetManyByUserAsync(user.Id)
.Returns([organizationUser]);
sutProvider.GetDependency<IUserService>()
.GetUserByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(
new AutomaticUserConfirmationPolicyEnforcementRequest(organization.Id,
[organizationUser],
user)));
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
@@ -403,128 +441,17 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
Assert.True(result.IsValid);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_UserInMultipleOrgs_WithSingleOrgPolicyOnThisOrg_ReturnsError(
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
Guid userId,
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
{
// Arrange
organizationUser.UserId = userId;
organizationUser.OrganizationId = organization.Id;
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
{
PerformedBy = Substitute.For<IActingUser>(),
DefaultUserCollectionName = "test-collection",
OrganizationUser = organizationUser,
OrganizationUserId = organizationUser.Id,
Organization = organization,
OrganizationId = organization.Id,
Key = "test-key"
};
var singleOrgPolicyDetails = new PolicyDetails
{
OrganizationId = organization.Id,
PolicyType = PolicyType.SingleOrg
};
sutProvider.GetDependency<IPolicyRepository>()
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
.Returns(autoConfirmPolicy);
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
.Returns([(userId, true)]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(userId)
.Returns([organizationUser, otherOrgUser]);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<SingleOrganizationPolicyRequirement>(userId)
.Returns(new SingleOrganizationPolicyRequirement([singleOrgPolicyDetails]));
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<OrganizationEnforcesSingleOrgPolicy>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_UserInMultipleOrgs_WithSingleOrgPolicyOnOtherOrg_ReturnsError(
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
Guid userId,
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
{
// Arrange
organizationUser.UserId = userId;
organizationUser.OrganizationId = organization.Id;
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
{
PerformedBy = Substitute.For<IActingUser>(),
DefaultUserCollectionName = "test-collection",
OrganizationUser = organizationUser,
OrganizationUserId = organizationUser.Id,
Organization = organization,
OrganizationId = organization.Id,
Key = "test-key"
};
var otherOrgId = Guid.NewGuid(); // Different org
var singleOrgPolicyDetails = new PolicyDetails
{
OrganizationId = otherOrgId,
PolicyType = PolicyType.SingleOrg,
};
sutProvider.GetDependency<IPolicyRepository>()
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
.Returns(autoConfirmPolicy);
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
.Returns([(userId, true)]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(userId)
.Returns([organizationUser, otherOrgUser]);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<SingleOrganizationPolicyRequirement>(userId)
.Returns(new SingleOrganizationPolicyRequirement([singleOrgPolicyDetails]));
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<OtherOrganizationEnforcesSingleOrgPolicy>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_UserInSingleOrg_ReturnsValidResult(
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
Guid userId,
User user,
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
{
// Arrange
organizationUser.UserId = userId;
organizationUser.UserId = user.Id;
organizationUser.OrganizationId = organization.Id;
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
@@ -544,61 +471,22 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
.Returns([(userId, true)]);
.Returns([(user.Id, true)]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(userId)
.GetManyByUserAsync(user.Id)
.Returns([organizationUser]); // Single org
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
sutProvider.GetDependency<IUserService>()
.GetUserByIdAsync(user.Id)
.Returns(user);
// Assert
Assert.True(result.IsValid);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_UserInMultipleOrgs_WithNoSingleOrgPolicy_ReturnsValidResult(
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
Guid userId,
Policy autoConfirmPolicy)
{
// Arrange
organizationUser.UserId = userId;
organizationUser.OrganizationId = organization.Id;
autoConfirmPolicy.Type = PolicyType.AutomaticUserConfirmation;
autoConfirmPolicy.Enabled = true;
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
{
PerformedBy = Substitute.For<IActingUser>(),
DefaultUserCollectionName = "test-collection",
OrganizationUser = organizationUser,
OrganizationUserId = organizationUser.Id,
Organization = organization,
OrganizationId = organization.Id,
Key = "test-key"
};
sutProvider.GetDependency<IPolicyRepository>()
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
.Returns(autoConfirmPolicy);
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
.Returns([(userId, true)]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(userId)
.Returns([organizationUser, otherOrgUser]);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<SingleOrganizationPolicyRequirement>(userId)
.Returns(new SingleOrganizationPolicyRequirement([]));
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(
new AutomaticUserConfirmationPolicyEnforcementRequest(organization.Id,
[organizationUser],
user)));
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
@@ -693,4 +581,59 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
Assert.True(result.IsError);
Assert.IsType<AutomaticallyConfirmUsersPolicyIsNotEnabled>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithNonProviderUser_ReturnsValidResult(
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
User user,
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy)
{
// Arrange
organizationUser.UserId = user.Id;
organizationUser.OrganizationId = organization.Id;
var request = new AutomaticallyConfirmOrganizationUserValidationRequest
{
PerformedBy = Substitute.For<IActingUser>(),
DefaultUserCollectionName = "test-collection",
OrganizationUser = organizationUser,
OrganizationUserId = organizationUser.Id,
Organization = organization,
OrganizationId = organization.Id,
Key = "test-key"
};
sutProvider.GetDependency<IPolicyRepository>()
.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation)
.Returns(autoConfirmPolicy);
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<Guid>>())
.Returns([(user.Id, true)]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([organizationUser]);
sutProvider.GetDependency<IUserService>()
.GetUserByIdAsync(user.Id)
.Returns(user);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(
new AutomaticUserConfirmationPolicyEnforcementRequest(organization.Id,
[organizationUser],
user)));
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
// Assert
Assert.True(result.IsValid);
}
}

View File

@@ -2,7 +2,9 @@
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoConfirm;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
@@ -21,6 +23,7 @@ using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
using static Bit.Core.AdminConsole.Utilities.v2.Validation.ValidationResultHelpers;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers;
@@ -559,4 +562,256 @@ public class ConfirmOrganizationUserCommandTests
.DidNotReceive()
.UpsertDefaultCollectionsAsync(Arg.Any<Guid>(), Arg.Any<IEnumerable<Guid>>(), Arg.Any<string>());
}
[Theory, BitAutoData]
public async Task ConfirmUserAsync_WithAutoConfirmEnabledAndUserBelongsToAnotherOrg_ThrowsBadRequest(
Organization org, OrganizationUser confirmingUser,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser orgUser, User user,
OrganizationUser otherOrgUser, string key, SutProvider<ConfirmOrganizationUserCommand> sutProvider)
{
org.PlanType = PlanType.EnterpriseAnnually;
orgUser.OrganizationId = confirmingUser.OrganizationId = org.Id;
orgUser.UserId = user.Id;
otherOrgUser.UserId = user.Id;
otherOrgUser.OrganizationId = Guid.NewGuid(); // Different org
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync([]).ReturnsForAnyArgs([orgUser]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByManyUsersAsync([])
.ReturnsForAnyArgs([orgUser, otherOrgUser]);
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
sutProvider.GetDependency<IUserRepository>().GetManyAsync([]).ReturnsForAnyArgs([user]);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser.Id, [orgUser, otherOrgUser], user),
new UserCannotBelongToAnotherOrganization()));
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.ConfirmUserAsync(orgUser.OrganizationId, orgUser.Id, key, confirmingUser.Id));
Assert.Equal(new UserCannotBelongToAnotherOrganization().Message, exception.Message);
}
[Theory, BitAutoData]
public async Task ConfirmUserAsync_WithAutoConfirmEnabledForOtherOrg_ThrowsBadRequest(
Organization org, OrganizationUser confirmingUser,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser orgUser, User user,
OrganizationUser otherOrgUser, string key, SutProvider<ConfirmOrganizationUserCommand> sutProvider)
{
// Arrange
org.PlanType = PlanType.EnterpriseAnnually;
orgUser.OrganizationId = confirmingUser.OrganizationId = org.Id;
orgUser.UserId = user.Id;
otherOrgUser.UserId = user.Id;
otherOrgUser.OrganizationId = Guid.NewGuid();
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync([]).ReturnsForAnyArgs([orgUser]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByManyUsersAsync([])
.ReturnsForAnyArgs([orgUser, otherOrgUser]);
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
sutProvider.GetDependency<IUserRepository>().GetManyAsync([]).ReturnsForAnyArgs([user]);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser, otherOrgUser], user),
new OtherOrganizationDoesNotAllowOtherMembership()));
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.ConfirmUserAsync(orgUser.OrganizationId, orgUser.Id, key, confirmingUser.Id));
Assert.Equal(new OtherOrganizationDoesNotAllowOtherMembership().Message, exception.Message);
}
[Theory, BitAutoData]
public async Task ConfirmUserAsync_WithAutoConfirmEnabledAndUserIsProvider_ThrowsBadRequest(
Organization org, OrganizationUser confirmingUser,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser orgUser, User user,
string key, SutProvider<ConfirmOrganizationUserCommand> sutProvider)
{
// Arrange
org.PlanType = PlanType.EnterpriseAnnually;
orgUser.OrganizationId = confirmingUser.OrganizationId = org.Id;
orgUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync([]).ReturnsForAnyArgs([orgUser]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByManyUsersAsync([])
.ReturnsForAnyArgs([orgUser]);
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
sutProvider.GetDependency<IUserRepository>().GetManyAsync([]).ReturnsForAnyArgs([user]);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser], user),
new ProviderUsersCannotJoin()));
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.ConfirmUserAsync(orgUser.OrganizationId, orgUser.Id, key, confirmingUser.Id));
Assert.Equal(new ProviderUsersCannotJoin().Message, exception.Message);
}
[Theory, BitAutoData]
public async Task ConfirmUserAsync_WithAutoConfirmNotApplicable_Succeeds(
Organization org, OrganizationUser confirmingUser,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser orgUser, User user,
string key, SutProvider<ConfirmOrganizationUserCommand> sutProvider)
{
// Arrange
org.PlanType = PlanType.EnterpriseAnnually;
orgUser.OrganizationId = confirmingUser.OrganizationId = org.Id;
orgUser.UserId = user.Id;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync([]).ReturnsForAnyArgs([orgUser]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByManyUsersAsync([])
.ReturnsForAnyArgs([orgUser]);
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
sutProvider.GetDependency<IUserRepository>().GetManyAsync([]).ReturnsForAnyArgs([user]);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser], user)));
// Act
await sutProvider.Sut.ConfirmUserAsync(orgUser.OrganizationId, orgUser.Id, key, confirmingUser.Id);
// Assert
await sutProvider.GetDependency<IEventService>()
.Received(1).LogOrganizationUserEventAsync(orgUser, EventType.OrganizationUser_Confirmed);
await sutProvider.GetDependency<IMailService>()
.Received(1).SendOrganizationConfirmedEmailAsync(org.DisplayName(), user.Email, orgUser.AccessSecretsManager);
}
[Theory, BitAutoData]
public async Task ConfirmUserAsync_WithAutoConfirmValidationBeforeSingleOrgPolicy_ChecksAutoConfirmFirst(
Organization org, OrganizationUser confirmingUser,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser orgUser, User user,
OrganizationUser otherOrgUser,
[OrganizationUserPolicyDetails(PolicyType.SingleOrg)] OrganizationUserPolicyDetails singleOrgPolicy,
string key, SutProvider<ConfirmOrganizationUserCommand> sutProvider)
{
// Arrange - Setup conditions that would fail BOTH auto-confirm AND single org policy
org.PlanType = PlanType.EnterpriseAnnually;
orgUser.OrganizationId = confirmingUser.OrganizationId = org.Id;
orgUser.UserId = user.Id;
otherOrgUser.UserId = user.Id;
otherOrgUser.OrganizationId = Guid.NewGuid();
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync([]).ReturnsForAnyArgs([orgUser]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByManyUsersAsync([])
.ReturnsForAnyArgs([orgUser, otherOrgUser]);
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
sutProvider.GetDependency<IUserRepository>().GetManyAsync([]).ReturnsForAnyArgs([user]);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);
singleOrgPolicy.OrganizationId = org.Id;
sutProvider.GetDependency<IPolicyService>()
.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg)
.Returns([singleOrgPolicy]);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser, otherOrgUser], user),
new UserCannotBelongToAnotherOrganization()));
// Act & Assert
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.ConfirmUserAsync(orgUser.OrganizationId, orgUser.Id, key, confirmingUser.Id));
Assert.Equal(new UserCannotBelongToAnotherOrganization().Message, exception.Message);
Assert.NotEqual("Cannot confirm this member to the organization until they leave or remove all other organizations.",
exception.Message);
}
[Theory, BitAutoData]
public async Task ConfirmUsersAsync_WithAutoConfirmEnabled_MixedResults(
Organization org, OrganizationUser confirmingUser,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser orgUser1,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser orgUser2,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser orgUser3,
OrganizationUser otherOrgUser, User user1, User user2, User user3,
string key, SutProvider<ConfirmOrganizationUserCommand> sutProvider)
{
// Arrange
org.PlanType = PlanType.EnterpriseAnnually;
orgUser1.OrganizationId = orgUser2.OrganizationId = orgUser3.OrganizationId = confirmingUser.OrganizationId = org.Id;
orgUser1.UserId = user1.Id;
orgUser2.UserId = user2.Id;
orgUser3.UserId = user3.Id;
otherOrgUser.UserId = user3.Id;
otherOrgUser.OrganizationId = Guid.NewGuid();
var orgUsers = new[] { orgUser1, orgUser2, orgUser3 };
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyAsync([]).ReturnsForAnyArgs(orgUsers);
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
sutProvider.GetDependency<IUserRepository>()
.GetManyAsync([]).ReturnsForAnyArgs([user1, user2, user3]);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByManyUsersAsync([])
.ReturnsForAnyArgs([orgUser1, orgUser2, orgUser3, otherOrgUser]);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Is<AutomaticUserConfirmationPolicyEnforcementRequest>(r => r.User.Id == user1.Id))
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser1], user1)));
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Is<AutomaticUserConfirmationPolicyEnforcementRequest>(r => r.User.Id == user2.Id))
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser2], user2)));
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Is<AutomaticUserConfirmationPolicyEnforcementRequest>(r => r.User.Id == user3.Id))
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser3, otherOrgUser], user3),
new OtherOrganizationDoesNotAllowOtherMembership()));
var keys = orgUsers.ToDictionary(ou => ou.Id, _ => key);
// Act
var result = await sutProvider.Sut.ConfirmUsersAsync(confirmingUser.OrganizationId, keys, confirmingUser.Id);
// Assert
Assert.Equal(3, result.Count);
Assert.Empty(result[0].Item2);
Assert.Empty(result[1].Item2);
Assert.Equal(new OtherOrganizationDoesNotAllowOtherMembership().Message, result[2].Item2);
}
}

View File

@@ -0,0 +1,306 @@
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoConfirm;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Entities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoConfirm;
[SutProviderCustomize]
public class AutomaticUserConfirmationPolicyEnforcementValidatorTests
{
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyEnabledAndUserIsProviderMember_ReturnsProviderUsersCannotJoinError(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
OrganizationUser organizationUser,
ProviderUser providerUser,
User user)
{
// Arrange
organizationUser.UserId = providerUser.UserId = user.Id;
var policyDetails = new PolicyDetails
{
OrganizationId = organizationUser.OrganizationId,
PolicyType = PolicyType.AutomaticUserConfirmation
};
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser.OrganizationId,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([policyDetails]));
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([providerUser]);
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<ProviderUsersCannotJoin>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyEnabledOnOtherOrganization_ReturnsOtherOrganizationDoesNotAllowOtherMembershipError(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
OrganizationUser organizationUser,
OrganizationUser otherOrganizationUser,
User user)
{
// Arrange
organizationUser.UserId = user.Id;
otherOrganizationUser.UserId = user.Id;
var otherOrgId = Guid.NewGuid();
var policyDetails = new PolicyDetails
{
OrganizationId = otherOrgId, // Different from organizationUser.OrganizationId
PolicyType = PolicyType.AutomaticUserConfirmation
};
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser.OrganizationId,
[organizationUser, otherOrganizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([policyDetails]));
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([]);
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<OtherOrganizationDoesNotAllowOtherMembership>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyDisabledUserIsAMemberOfAnotherOrgReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
User user)
{
// Arrange
organizationUser.UserId = user.Id;
otherOrgUser.UserId = user.Id;
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser.OrganizationId,
[organizationUser, otherOrgUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([]);
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsValid);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyEnabledUserIsAMemberOfAnotherOrg_ReturnsCannotBeMemberOfAnotherOrgError(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
User user)
{
// Arrange
organizationUser.UserId = user.Id;
otherOrgUser.UserId = user.Id;
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser.OrganizationId,
[organizationUser, otherOrgUser],
user);
var policyDetails = new PolicyDetails
{
OrganizationId = organizationUser.OrganizationId,
PolicyType = PolicyType.AutomaticUserConfirmation
};
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([policyDetails]));
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([]);
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<UserCannotBelongToAnotherOrganization>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyEnabledAndChecksConditionsInCorrectOrder_ReturnsFirstFailure(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
ProviderUser providerUser,
User user)
{
// Arrange
var policyDetails = new PolicyDetails
{
OrganizationId = organizationUser.OrganizationId,
PolicyType = PolicyType.AutomaticUserConfirmation,
OrganizationUserId = organizationUser.Id
};
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser.OrganizationId,
[organizationUser, otherOrgUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([policyDetails]));
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([providerUser]);
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<CurrentOrganizationUserIsNotPresentInRequest>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyIsEnabledNoOtherOrganizationsAndNotAProvider_ReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
OrganizationUser organizationUser,
User user)
{
// Arrange
organizationUser.UserId = user.Id;
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser.OrganizationId,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([
new PolicyDetails
{
OrganizationUserId = organizationUser.Id,
OrganizationId = organizationUser.OrganizationId,
PolicyType = PolicyType.AutomaticUserConfirmation,
}
]));
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([]);
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsValid);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyDisabledForCurrentAndOtherOrg_ReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
User user)
{
// Arrange
otherOrgUser.UserId = organizationUser.UserId = user.Id;
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser.OrganizationId,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([]);
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsValid);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyDisabledForCurrentAndOtherOrgAndIsProvider_ReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
ProviderUser providerUser,
User user)
{
// Arrange
providerUser.UserId = otherOrgUser.UserId = organizationUser.UserId = user.Id;
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser.OrganizationId,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(user.Id)
.Returns([providerUser]);
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsValid);
}
}