1
0
mirror of https://github.com/bitwarden/server synced 2025-12-11 05:43:35 +00:00

Cleaned up implementation of enforcement validator (for the user).

This commit is contained in:
Jared McCannon
2025-12-04 18:46:05 -06:00
parent 0602c3eaf7
commit e12fa708e7
10 changed files with 97 additions and 217 deletions

View File

@@ -270,7 +270,7 @@ public class AcceptOrgUserCommand : IAcceptOrgUserCommand
ICollection<OrganizationUser> allOrgUsers, User user)
{
var error = (await _automaticUserConfirmationPolicyEnforcementValidator.IsCompliantAsync(
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser.Id, allOrgUsers, user)))
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser.OrganizationId, allOrgUsers, user)))
.Match(
error => error.Message,
_ => string.Empty

View File

@@ -20,7 +20,6 @@ public class AutomaticallyConfirmOrganizationUsersValidator(
IPolicyRequirementQuery policyRequirementQuery,
IAutomaticUserConfirmationPolicyEnforcementValidator automaticUserConfirmationPolicyEnforcementValidator,
IUserService userService,
IProviderUserRepository providerUserRepository,
IPolicyRepository policyRepository) : IAutomaticallyConfirmOrganizationUsersValidator
{
public async Task<ValidationResult<AutomaticallyConfirmOrganizationUserValidationRequest>> ValidateAsync(
@@ -71,17 +70,9 @@ public class AutomaticallyConfirmOrganizationUsersValidator(
return Invalid(request, error);
}
if (await OrganizationUserIsProviderAsync(request))
{
return Invalid(request, new ProviderUsersCannotJoin());
}
return Valid(request);
}
private async Task<bool> OrganizationUserIsProviderAsync(AutomaticallyConfirmOrganizationUserValidationRequest request) =>
(await providerUserRepository.GetManyByUserAsync(request.OrganizationUser!.UserId!.Value)).Count != 0;
private async Task<bool> OrganizationHasAutomaticallyConfirmUsersPolicyEnabledAsync(AutomaticallyConfirmOrganizationUserValidationRequest request) =>
await policyRepository.GetByOrganizationIdTypeAsync(request.OrganizationId, PolicyType.AutomaticUserConfirmation) is { Enabled: true }
&& request.Organization is { UseAutomaticUserConfirmation: true };
@@ -112,7 +103,7 @@ public class AutomaticallyConfirmOrganizationUsersValidator(
return (await automaticUserConfirmationPolicyEnforcementValidator.IsCompliantAsync(
new AutomaticUserConfirmationPolicyEnforcementRequest(
request.OrganizationUser,
request.OrganizationId,
allOrganizationUsersForUser.Where(x => x.OrganizationId != request.OrganizationId),
user)))
.Match<Error?>(

View File

@@ -9,7 +9,7 @@ public record UserIsNotAccepted() : BadRequestError("Cannot confirm user that ha
public record OrganizationUserIdIsInvalid() : BadRequestError("Invalid organization user id.");
public record UserDoesNotHaveTwoFactorEnabled() : BadRequestError("User does not have two-step login enabled.");
public record OrganizationEnforcesSingleOrgPolicy() : BadRequestError("Cannot confirm this member to the organization until they leave or remove all other organizations");
public record OtherOrganizationEnforcesSingleOrgPolicy() : BadRequestError("Cannot confirm this member to the organization because they are in another organization which forbids it.");
public record OtherOrganizationDoesNotAllowOtherMembership() : BadRequestError("Cannot confirm this member to the organization because they are in another organization which forbids it.");
public record AutomaticallyConfirmUsersPolicyIsNotEnabled() : BadRequestError("Cannot confirm this member because the Automatically Confirm Users policy is not enabled.");
public record ProviderUsersCannotJoin() : BadRequestError("An organization the user is a part of has enabled Automatic User Confirmation policy and it does not support provider users joining.");
public record CurrentOrganizationUserIsNotPresentInRequest() : BadRequestError("The current organization user does not exist in the request.");

View File

@@ -198,8 +198,8 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
{
var error = (await _automaticUserConfirmationPolicyEnforcementValidator.IsCompliantAsync(
new AutomaticUserConfirmationPolicyEnforcementRequest(
userOrgs.First(x => x.OrganizationId == organizationId),
userOrgs.Where(x => x.OrganizationId != organizationId),
organizationId,
userOrgs,
user)))
.Match(
error => error.Message,

View File

@@ -8,14 +8,15 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoCo
public record AutomaticUserConfirmationPolicyEnforcementRequest
{
/// <summary>
/// Organization user to be validated
/// Organization to be validated
/// </summary>
public Guid OrganizationUserId { get; }
public Guid OrganizationId { get; }
/// <summary>
/// All organization users that match the provided user.
/// </summary>
public IEnumerable<OrganizationUser> AllOrganizationUsers { get; }
/// <summary>
/// User associated with the organization user to be confirmed
/// </summary>
@@ -27,15 +28,15 @@ public record AutomaticUserConfirmationPolicyEnforcementRequest
/// <remarks>
/// This record is used to encapsulate the data required for handling the automatic confirmation policy enforcement.
/// </remarks>
/// <param name="organizationUserId">The organization user id to be validated.</param>
/// <param name="organizationId">The organization to be validated.</param>
/// <param name="organizationUsers">All organization users that match the provided user.</param>
/// <param name="user">The general user associated with the operation.</param>
/// <param name="user">The user entity connecting all org users provided.</param>
public AutomaticUserConfirmationPolicyEnforcementRequest(
Guid organizationUserId,
Guid organizationId,
IEnumerable<OrganizationUser> organizationUsers,
User user)
{
OrganizationUserId = organizationUserId;
OrganizationId = organizationId;
AllOrganizationUsers = organizationUsers;
User = user;
}

View File

@@ -18,23 +18,18 @@ public class AutomaticUserConfirmationPolicyEnforcementValidator(
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(request.User.Id);
var currentOrganizationUser = request.AllOrganizationUsers
.FirstOrDefault(x => x.Id == request.OrganizationUserId);
.FirstOrDefault(x => x.OrganizationId == request.OrganizationId
&& x.UserId == request.User.Id);
if (currentOrganizationUser is null)
{
return Invalid(request, new CurrentOrganizationUserIsNotPresentInRequest());
}
if (automaticUserConfirmationPolicyRequirement.IsEnabled(currentOrganizationUser.OrganizationId)
&& automaticUserConfirmationPolicyRequirement.UserBelongsToOrganizationWithAutomaticUserConfirmationEnabled())
{
return Invalid(request, new OrganizationEnforcesSingleOrgPolicy());
}
if (automaticUserConfirmationPolicyRequirement
.IsEnabledForOrganizationsOtherThan(currentOrganizationUser.OrganizationId))
{
return Invalid(request, new OtherOrganizationEnforcesSingleOrgPolicy());
return Invalid(request, new OtherOrganizationDoesNotAllowOtherMembership());
}
if ((await providerUserRepository.GetManyByUserAsync(request.User.Id)).Count != 0)

View File

@@ -709,7 +709,7 @@ public class AcceptOrgUserCommandTests
// Mock auto-confirm enforcement query to return valid (no auto-confirm restrictions)
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [], user)));
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser], user)));
// Act
var resultOrgUser = await sutProvider.Sut.AcceptOrgUserAsync(orgUser, user, _userService);
@@ -738,7 +738,7 @@ public class AcceptOrgUserCommandTests
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [otherOrgUser], user),
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser, otherOrgUser], user),
new OrganizationEnforcesSingleOrgPolicy()));
// Act & Assert
@@ -833,7 +833,7 @@ public class AcceptOrgUserCommandTests
.Returns(org);
// Auto-confirm enforcement query returns valid by default (no restrictions)
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [], user);
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser], user);
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(request)

View File

@@ -533,14 +533,14 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
.Returns(Task.FromResult(
Invalid<AutomaticUserConfirmationPolicyEnforcementRequest>(
null!,
new OtherOrganizationEnforcesSingleOrgPolicy())));
new OtherOrganizationDoesNotAllowOtherMembership())));
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<OtherOrganizationEnforcesSingleOrgPolicy>(result.AsError);
Assert.IsType<OtherOrganizationDoesNotAllowOtherMembership>(result.AsError);
}
[Theory]
@@ -734,55 +734,6 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
Assert.IsType<AutomaticallyConfirmUsersPolicyIsNotEnabled>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithProviderUser_ReturnsProviderUsersCannotJoinError(
SutProvider<AutomaticallyConfirmOrganizationUsersValidator> sutProvider,
[Organization(useAutomaticUserConfirmation: true)] Organization organization,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
Guid userId,
[Policy(PolicyType.AutomaticUserConfirmation)] Policy autoConfirmPolicy,
Core.AdminConsole.Entities.Provider.ProviderUser providerUser)
{
// 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"
};
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]);
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(userId)
.Returns([providerUser]);
// Act
var result = await sutProvider.Sut.ValidateAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<ProviderUsersCannotJoin>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task ValidateAsync_WithNonProviderUser_ReturnsValidResult(
@@ -819,10 +770,6 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests
.GetManyByUserAsync(userId)
.Returns([organizationUser]);
sutProvider.GetDependency<IProviderUserRepository>()
.GetManyByUserAsync(userId)
.Returns([]);
// Act
var result = await sutProvider.Sut.ValidateAsync(request);

View File

@@ -590,7 +590,7 @@ public class ConfirmOrganizationUserCommandTests
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [otherOrgUser], user),
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser.Id, [orgUser, otherOrgUser], user),
new OrganizationEnforcesSingleOrgPolicy()));
var exception = await Assert.ThrowsAsync<BadRequestException>(
@@ -627,14 +627,14 @@ public class ConfirmOrganizationUserCommandTests
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [otherOrgUser], user),
new OtherOrganizationEnforcesSingleOrgPolicy()));
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 OtherOrganizationEnforcesSingleOrgPolicy().Message, exception.Message);
Assert.Equal(new OtherOrganizationDoesNotAllowOtherMembership().Message, exception.Message);
}
[Theory, BitAutoData]
@@ -663,7 +663,7 @@ public class ConfirmOrganizationUserCommandTests
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [], user),
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser], user),
new ProviderUsersCannotJoin()));
// Act & Assert
@@ -698,7 +698,7 @@ public class ConfirmOrganizationUserCommandTests
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [], user)));
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser], user)));
// Act
await sutProvider.Sut.ConfirmUserAsync(orgUser.OrganizationId, orgUser.Id, key, confirmingUser.Id);
@@ -745,7 +745,7 @@ public class ConfirmOrganizationUserCommandTests
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Any<AutomaticUserConfirmationPolicyEnforcementRequest>())
.Returns(Invalid(
new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [otherOrgUser], user),
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser, otherOrgUser], user),
new OrganizationEnforcesSingleOrgPolicy()));
// Act & Assert
@@ -791,17 +791,17 @@ public class ConfirmOrganizationUserCommandTests
sutProvider.GetDependency<IAutomaticUserConfirmationPolicyEnforcementValidator>()
.IsCompliantAsync(Arg.Is<AutomaticUserConfirmationPolicyEnforcementRequest>(r => r.User.Id == user1.Id))
.Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser1, [], user1)));
.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(orgUser2, [], user2)));
.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(orgUser3, [otherOrgUser], user3),
new OtherOrganizationEnforcesSingleOrgPolicy()));
new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser3, otherOrgUser], user3),
new OtherOrganizationDoesNotAllowOtherMembership()));
var keys = orgUsers.ToDictionary(ou => ou.Id, _ => key);
@@ -812,6 +812,6 @@ public class ConfirmOrganizationUserCommandTests
Assert.Equal(3, result.Count);
Assert.Empty(result[0].Item2);
Assert.Empty(result[1].Item2);
Assert.Equal(new OtherOrganizationEnforcesSingleOrgPolicy().Message, result[2].Item2);
Assert.Equal(new OtherOrganizationDoesNotAllowOtherMembership().Message, result[2].Item2);
}
}

View File

@@ -1,12 +1,12 @@
using Bit.Core.AdminConsole.Enums;
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.Core.Enums;
using Bit.Core.Test.AutoFixture.OrganizationUserFixtures;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
@@ -17,48 +17,25 @@ namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.Enforcement.A
[SutProviderCustomize]
public class AutomaticUserConfirmationPolicyEnforcementValidatorTests
{
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithNoOtherOrganizations_ReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
User user)
{
// Arrange
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser,
[],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsValid);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyEnabledOnSameOrganizationButNoOtherOrgs_ReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser organizationUser,
User user)
{
// Arrange
organizationUser.UserId = user.Id;
var policyDetails = new PolicyDetails
{
OrganizationId = organizationUser.OrganizationId,
PolicyType = PolicyType.AutomaticUserConfirmation,
IsProvider = false
PolicyType = PolicyType.AutomaticUserConfirmation
};
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser,
[],
organizationUser.OrganizationId,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
@@ -74,60 +51,33 @@ public class AutomaticUserConfirmationPolicyEnforcementValidatorTests
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyEnabledOnSameOrgAndUserHasOtherOrgs_ReturnsOrganizationEnforcesSingleOrgPolicyError(
public async Task IsCompliantAsync_WithUserIsAMemberOfAProvider_ReturnsProviderUsersCannotJoinError(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
OrganizationUser organizationUser,
ProviderUser providerUser,
User user)
{
// Arrange
organizationUser.UserId = providerUser.UserId = user.Id;
var policyDetails = new PolicyDetails
{
OrganizationId = organizationUser.OrganizationId,
PolicyType = PolicyType.AutomaticUserConfirmation,
IsProvider = false
PolicyType = PolicyType.AutomaticUserConfirmation
};
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser,
[otherOrgUser], // User has other org memberships
organizationUser.OrganizationId,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([policyDetails]));
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsError);
Assert.IsType<OrganizationEnforcesSingleOrgPolicy>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithUserIsProvider_ReturnsProviderUsersCannotJoinError(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
User user)
{
// Arrange
var policyDetails = new PolicyDetails
{
OrganizationId = organizationUser.OrganizationId,
PolicyType = PolicyType.AutomaticUserConfirmation,
IsProvider = true
};
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
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);
@@ -139,23 +89,24 @@ public class AutomaticUserConfirmationPolicyEnforcementValidatorTests
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithPolicyEnabledOnOtherOrganization_ReturnsOtherOrganizationEnforcesSingleOrgPolicyError(
public async Task IsCompliantAsync_WithPolicyEnabledOnOtherOrganization_ReturnsOtherOrganizationDoesNotAllowOtherMembershipError(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser organizationUser,
User user)
{
// Arrange
organizationUser.UserId = user.Id;
var otherOrgId = Guid.NewGuid();
var policyDetails = new PolicyDetails
{
OrganizationId = otherOrgId, // Different from organizationUser.OrganizationId
PolicyType = PolicyType.AutomaticUserConfirmation,
IsProvider = false
PolicyType = PolicyType.AutomaticUserConfirmation
};
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser,
[],
organizationUser.OrganizationId,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
@@ -167,27 +118,29 @@ public class AutomaticUserConfirmationPolicyEnforcementValidatorTests
// Assert
Assert.True(result.IsError);
Assert.IsType<OtherOrganizationEnforcesSingleOrgPolicy>(result.AsError);
Assert.IsType<OtherOrganizationDoesNotAllowOtherMembership>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithOtherOrganizationsButNoPolicyEnabled_ReturnsValid(
public async Task IsCompliantAsync_UserIsAMemberOfAnotherOrgButNoPolicyDetailForAutoConfirm_ReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
User user)
{
// Arrange
// No policy enabled, so even with other org memberships, it should be valid
organizationUser.UserId = user.Id;
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser,
[otherOrgUser], // User has other organization memberships
organizationUser.OrganizationId,
[organizationUser, otherOrgUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));
.Returns(new AutomaticUserConfirmationPolicyRequirement([])); // no policy details
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
@@ -196,80 +149,73 @@ public class AutomaticUserConfirmationPolicyEnforcementValidatorTests
Assert.True(result.IsValid);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithEmptyOtherOrganizationsAndSingleOrg_ReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
User user)
{
// Arrange
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));
// Act
var result = await sutProvider.Sut.IsCompliantAsync(request);
// Assert
Assert.True(result.IsValid);
Assert.Equal(request, result.Request);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_ChecksConditionsInCorrectOrder_ReturnsFirstFailure(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser organizationUser,
OrganizationUser otherOrgUser,
ProviderUser providerUser,
User user)
{
// Arrange - Set up conditions that would fail multiple checks
var policyDetails = new PolicyDetails
{
OrganizationId = organizationUser.OrganizationId, // Would trigger first check
OrganizationId = organizationUser.OrganizationId,
PolicyType = PolicyType.AutomaticUserConfirmation,
IsProvider = true // Would also trigger second check if first passes
OrganizationUserId = organizationUser.Id
};
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser,
[otherOrgUser], // Would also fail the last check
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 - Should fail on the FIRST check (IsEnabled on same org AND has other orgs)
// Assert - Should fail on the FIRST check Org user does not match request object
Assert.True(result.IsError);
Assert.IsType<OrganizationEnforcesSingleOrgPolicy>(result.AsError);
Assert.IsType<CurrentOrganizationUserIsNotPresentInRequest>(result.AsError);
}
[Theory]
[BitAutoData]
public async Task IsCompliantAsync_WithNullOtherOrganizations_ReturnsValidWhenNoOtherOrgs(
public async Task IsCompliantAsync_WithNoOtherOrganizationsAndNotAProvider_ReturnsValid(
SutProvider<AutomaticUserConfirmationPolicyEnforcementValidator> sutProvider,
[OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser,
OrganizationUser organizationUser,
User user)
{
// Arrange
organizationUser.UserId = user.Id;
var request = new AutomaticUserConfirmationPolicyEnforcementRequest(
organizationUser,
null, // Null other organizations
organizationUser.OrganizationId,
[organizationUser],
user);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));
.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);