From e12fa708e7236eb821fd25363fc4ba2dd896a7f8 Mon Sep 17 00:00:00 2001 From: Jared McCannon Date: Thu, 4 Dec 2025 18:46:05 -0600 Subject: [PATCH] Cleaned up implementation of enforcement validator (for the user). --- .../OrganizationUsers/AcceptOrgUserCommand.cs | 2 +- ...icallyConfirmOrganizationUsersValidator.cs | 11 +- .../AutoConfirmUser/Errors.cs | 2 +- .../ConfirmOrganizationUserCommand.cs | 4 +- ...serConfirmationPolicyEnforcementRequest.cs | 13 +- ...rConfirmationPolicyEnforcementValidator.cs | 11 +- .../AcceptOrgUserCommandTests.cs | 6 +- ...yConfirmOrganizationUsersValidatorTests.cs | 57 +----- .../ConfirmOrganizationUserCommandTests.cs | 24 +-- ...irmationPolicyEnforcementValidatorTests.cs | 184 +++++++----------- 10 files changed, 97 insertions(+), 217 deletions(-) diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommand.cs index 8b86a9945a..c763cc0cc2 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommand.cs @@ -270,7 +270,7 @@ public class AcceptOrgUserCommand : IAcceptOrgUserCommand ICollection 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 diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUser/AutomaticallyConfirmOrganizationUsersValidator.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUser/AutomaticallyConfirmOrganizationUsersValidator.cs index 3153f2954e..d514006402 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUser/AutomaticallyConfirmOrganizationUsersValidator.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUser/AutomaticallyConfirmOrganizationUsersValidator.cs @@ -20,7 +20,6 @@ public class AutomaticallyConfirmOrganizationUsersValidator( IPolicyRequirementQuery policyRequirementQuery, IAutomaticUserConfirmationPolicyEnforcementValidator automaticUserConfirmationPolicyEnforcementValidator, IUserService userService, - IProviderUserRepository providerUserRepository, IPolicyRepository policyRepository) : IAutomaticallyConfirmOrganizationUsersValidator { public async Task> 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 OrganizationUserIsProviderAsync(AutomaticallyConfirmOrganizationUserValidationRequest request) => - (await providerUserRepository.GetManyByUserAsync(request.OrganizationUser!.UserId!.Value)).Count != 0; - private async Task 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( diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUser/Errors.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUser/Errors.cs index f8109f24b7..fb094ef6cf 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUser/Errors.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUser/Errors.cs @@ -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."); diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommand.cs index d222710fc2..08de59aa4d 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommand.cs @@ -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, diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementRequest.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementRequest.cs index fefc326d17..1475626d27 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementRequest.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementRequest.cs @@ -8,14 +8,15 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoCo public record AutomaticUserConfirmationPolicyEnforcementRequest { /// - /// Organization user to be validated + /// Organization to be validated /// - public Guid OrganizationUserId { get; } + public Guid OrganizationId { get; } /// /// All organization users that match the provided user. /// public IEnumerable AllOrganizationUsers { get; } + /// /// User associated with the organization user to be confirmed /// @@ -27,15 +28,15 @@ public record AutomaticUserConfirmationPolicyEnforcementRequest /// /// This record is used to encapsulate the data required for handling the automatic confirmation policy enforcement. /// - /// The organization user id to be validated. + /// The organization to be validated. /// All organization users that match the provided user. - /// The general user associated with the operation. + /// The user entity connecting all org users provided. public AutomaticUserConfirmationPolicyEnforcementRequest( - Guid organizationUserId, + Guid organizationId, IEnumerable organizationUsers, User user) { - OrganizationUserId = organizationUserId; + OrganizationId = organizationId; AllOrganizationUsers = organizationUsers; User = user; } diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementValidator.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementValidator.cs index 2c2ff0b838..7beecaffb3 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementValidator.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementValidator.cs @@ -18,23 +18,18 @@ public class AutomaticUserConfirmationPolicyEnforcementValidator( .GetAsync(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) diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommandTests.cs index b5e3acd882..e04bc82dba 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommandTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommandTests.cs @@ -709,7 +709,7 @@ public class AcceptOrgUserCommandTests // Mock auto-confirm enforcement query to return valid (no auto-confirm restrictions) sutProvider.GetDependency() .IsCompliantAsync(Arg.Any()) - .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() .IsCompliantAsync(Arg.Any()) .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() .IsCompliantAsync(request) diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUsers/AutomaticallyConfirmOrganizationUsersValidatorTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUsers/AutomaticallyConfirmOrganizationUsersValidatorTests.cs index 4e067d97e0..5172d19de0 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUsers/AutomaticallyConfirmOrganizationUsersValidatorTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AutoConfirmUsers/AutomaticallyConfirmOrganizationUsersValidatorTests.cs @@ -533,14 +533,14 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests .Returns(Task.FromResult( Invalid( null!, - new OtherOrganizationEnforcesSingleOrgPolicy()))); + new OtherOrganizationDoesNotAllowOtherMembership()))); // Act var result = await sutProvider.Sut.ValidateAsync(request); // Assert Assert.True(result.IsError); - Assert.IsType(result.AsError); + Assert.IsType(result.AsError); } [Theory] @@ -734,55 +734,6 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests Assert.IsType(result.AsError); } - [Theory] - [BitAutoData] - public async Task ValidateAsync_WithProviderUser_ReturnsProviderUsersCannotJoinError( - SutProvider 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(), - DefaultUserCollectionName = "test-collection", - OrganizationUser = organizationUser, - OrganizationUserId = organizationUser.Id, - Organization = organization, - OrganizationId = organization.Id, - Key = "test-key" - }; - - sutProvider.GetDependency() - .GetByOrganizationIdTypeAsync(organization.Id, PolicyType.AutomaticUserConfirmation) - .Returns(autoConfirmPolicy); - - sutProvider.GetDependency() - .TwoFactorIsEnabledAsync(Arg.Any>()) - .Returns([(userId, true)]); - - sutProvider.GetDependency() - .GetManyByUserAsync(userId) - .Returns([organizationUser]); - - sutProvider.GetDependency() - .GetManyByUserAsync(userId) - .Returns([providerUser]); - - // Act - var result = await sutProvider.Sut.ValidateAsync(request); - - // Assert - Assert.True(result.IsError); - Assert.IsType(result.AsError); - } - [Theory] [BitAutoData] public async Task ValidateAsync_WithNonProviderUser_ReturnsValidResult( @@ -819,10 +770,6 @@ public class AutomaticallyConfirmOrganizationUsersValidatorTests .GetManyByUserAsync(userId) .Returns([organizationUser]); - sutProvider.GetDependency() - .GetManyByUserAsync(userId) - .Returns([]); - // Act var result = await sutProvider.Sut.ValidateAsync(request); diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommandTests.cs index 38a755b9ad..97e83723a3 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommandTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommandTests.cs @@ -590,7 +590,7 @@ public class ConfirmOrganizationUserCommandTests sutProvider.GetDependency() .IsCompliantAsync(Arg.Any()) .Returns(Invalid( - new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser, [otherOrgUser], user), + new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser.Id, [orgUser, otherOrgUser], user), new OrganizationEnforcesSingleOrgPolicy())); var exception = await Assert.ThrowsAsync( @@ -627,14 +627,14 @@ public class ConfirmOrganizationUserCommandTests sutProvider.GetDependency() .IsCompliantAsync(Arg.Any()) .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( () => 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() .IsCompliantAsync(Arg.Any()) .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() .IsCompliantAsync(Arg.Any()) - .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() .IsCompliantAsync(Arg.Any()) .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() .IsCompliantAsync(Arg.Is(r => r.User.Id == user1.Id)) - .Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser1, [], user1))); + .Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser1], user1))); sutProvider.GetDependency() .IsCompliantAsync(Arg.Is(r => r.User.Id == user2.Id)) - .Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(orgUser2, [], user2))); + .Returns(Valid(new AutomaticUserConfirmationPolicyEnforcementRequest(org.Id, [orgUser2], user2))); sutProvider.GetDependency() .IsCompliantAsync(Arg.Is(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); } } diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementValidatorTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementValidatorTests.cs index 7699230275..d35924671e 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementValidatorTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/Enforcement/AutoConfirm/AutomaticUserConfirmationPolicyEnforcementValidatorTests.cs @@ -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 sutProvider, - [OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser, - User user) - { - // Arrange - var request = new AutomaticUserConfirmationPolicyEnforcementRequest( - organizationUser, - [], - user); - - sutProvider.GetDependency() - .GetAsync(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 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() @@ -74,60 +51,33 @@ public class AutomaticUserConfirmationPolicyEnforcementValidatorTests [Theory] [BitAutoData] - public async Task IsCompliantAsync_WithPolicyEnabledOnSameOrgAndUserHasOtherOrgs_ReturnsOrganizationEnforcesSingleOrgPolicyError( + public async Task IsCompliantAsync_WithUserIsAMemberOfAProvider_ReturnsProviderUsersCannotJoinError( SutProvider 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() .GetAsync(user.Id) .Returns(new AutomaticUserConfirmationPolicyRequirement([policyDetails])); - // Act - var result = await sutProvider.Sut.IsCompliantAsync(request); - - // Assert - Assert.True(result.IsError); - Assert.IsType(result.AsError); - } - - [Theory] - [BitAutoData] - public async Task IsCompliantAsync_WithUserIsProvider_ReturnsProviderUsersCannotJoinError( - SutProvider 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() - .GetAsync(user.Id) - .Returns(new AutomaticUserConfirmationPolicyRequirement([policyDetails])); + sutProvider.GetDependency() + .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 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() @@ -167,27 +118,29 @@ public class AutomaticUserConfirmationPolicyEnforcementValidatorTests // Assert Assert.True(result.IsError); - Assert.IsType(result.AsError); + Assert.IsType(result.AsError); } [Theory] [BitAutoData] - public async Task IsCompliantAsync_WithOtherOrganizationsButNoPolicyEnabled_ReturnsValid( + public async Task IsCompliantAsync_UserIsAMemberOfAnotherOrgButNoPolicyDetailForAutoConfirm_ReturnsValid( SutProvider 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() .GetAsync(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 sutProvider, - [OrganizationUser(OrganizationUserStatusType.Accepted)] OrganizationUser organizationUser, - User user) - { - // Arrange - var request = new AutomaticUserConfirmationPolicyEnforcementRequest( - organizationUser, - [organizationUser], - user); - - sutProvider.GetDependency() - .GetAsync(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 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() .GetAsync(user.Id) .Returns(new AutomaticUserConfirmationPolicyRequirement([policyDetails])); + sutProvider.GetDependency() + .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(result.AsError); + Assert.IsType(result.AsError); } [Theory] [BitAutoData] - public async Task IsCompliantAsync_WithNullOtherOrganizations_ReturnsValidWhenNoOtherOrgs( + public async Task IsCompliantAsync_WithNoOtherOrganizationsAndNotAProvider_ReturnsValid( SutProvider 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() .GetAsync(user.Id) - .Returns(new AutomaticUserConfirmationPolicyRequirement([])); + .Returns(new AutomaticUserConfirmationPolicyRequirement([ + new PolicyDetails + { + OrganizationUserId = organizationUser.Id, + OrganizationId = organizationUser.OrganizationId, + PolicyType = PolicyType.AutomaticUserConfirmation, + } + ])); + + sutProvider.GetDependency() + .GetManyByUserAsync(user.Id) + .Returns([]); // Act var result = await sutProvider.Sut.IsCompliantAsync(request);