Implement InitPendingOrganizationValidator for improved organization initialization validation

- Introduced IInitPendingOrganizationValidator interface and its implementation to encapsulate validation logic for organization initialization.
- Refactored InitPendingOrganizationCommand to utilize the new validator for token validation, user email matching, organization state checks, and policy enforcement.
- Enhanced dependency injection in OrganizationServiceCollectionExtensions to include the new validator.
- Added comprehensive unit tests for the validator to ensure robust validation logic and error handling.
This commit is contained in:
Rui Tome
2026-01-30 16:28:53 +00:00
parent fd8044ce2a
commit dc18834aed
5 changed files with 730 additions and 174 deletions

View File

@@ -1,13 +1,7 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
using Bit.Core.Billing.Enums;
using Bit.Core.Entities;
using Bit.Core.Enums;
@@ -161,6 +155,11 @@ public class InitPendingOrganizationCommandTests
var protectedToken = _orgUserInviteTokenDataFactory.Protect(orgUserInviteTokenable);
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(orgUserId).Returns(orgUser);
// Setup validator to accept the token for old InitPendingOrganizationAsync method
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateInviteToken(orgUser, Arg.Any<User>(), protectedToken)
.Returns(true);
return protectedToken;
}
@@ -248,13 +247,14 @@ public class InitPendingOrganizationCommandTests
orgUser.Email = user.Email;
var requestWithInvalidToken = request with { User = user, EmailToken = "invalid-token" };
sutProvider.SetDependency(_orgUserInviteTokenDataFactory, "orgUserInviteTokenDataFactory");
sutProvider.Create();
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(requestWithInvalidToken.OrganizationUserId)
.Returns(orgUser);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateInviteToken(orgUser, user, "invalid-token")
.Returns(false);
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(requestWithInvalidToken);
@@ -274,13 +274,20 @@ public class InitPendingOrganizationCommandTests
orgUser.Email = "different@email.com";
user.Email = "user@email.com";
var token = CreateToken(orgUser, request.OrganizationUserId, sutProvider);
var requestWithUser = request with { User = user, EmailToken = token };
var requestWithUser = request with { User = user, EmailToken = "valid-token" };
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(requestWithUser.OrganizationUserId)
.Returns(orgUser);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateInviteToken(orgUser, user, Arg.Any<string>())
.Returns(true);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateUserEmail(orgUser, user)
.Returns(new EmailMismatchError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(requestWithUser);
@@ -299,13 +306,20 @@ public class InitPendingOrganizationCommandTests
// Arrange
orgUser.Email = user.Email;
var token = CreateToken(orgUser, request.OrganizationUserId, sutProvider);
var requestWithUser = request with { User = user, EmailToken = token };
var requestWithUser = request with { User = user, EmailToken = "valid-token" };
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(requestWithUser.OrganizationUserId)
.Returns(orgUser);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateInviteToken(orgUser, user, Arg.Any<string>())
.Returns(true);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateUserEmail(orgUser, user)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(requestWithUser.OrganizationId)
.Returns((Organization)null);
@@ -330,17 +344,28 @@ public class InitPendingOrganizationCommandTests
orgUser.Email = user.Email;
orgUser.OrganizationId = Guid.NewGuid(); // Different from request
var token = CreateToken(orgUser, request.OrganizationUserId, sutProvider);
var requestWithUser = request with { User = user, EmailToken = token };
var requestWithUser = request with { User = user, EmailToken = "valid-token" };
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(requestWithUser.OrganizationUserId)
.Returns(orgUser);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateInviteToken(orgUser, user, Arg.Any<string>())
.Returns(true);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateUserEmail(orgUser, user)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(requestWithUser.OrganizationId)
.Returns(org);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationMatch(orgUser, requestWithUser.OrganizationId)
.Returns(new OrganizationMismatchError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(requestWithUser);
@@ -370,6 +395,14 @@ public class InitPendingOrganizationCommandTests
.GetByIdAsync(updatedRequest.OrganizationId)
.Returns(org);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationMatch(orgUser, updatedRequest.OrganizationId)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationState(org)
.Returns(new OrganizationAlreadyEnabledError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(updatedRequest);
@@ -399,6 +432,14 @@ public class InitPendingOrganizationCommandTests
.GetByIdAsync(updatedRequest.OrganizationId)
.Returns(org);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationMatch(orgUser, updatedRequest.OrganizationId)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationState(org)
.Returns(new OrganizationNotPendingError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(updatedRequest);
@@ -428,6 +469,14 @@ public class InitPendingOrganizationCommandTests
.GetByIdAsync(updatedRequest.OrganizationId)
.Returns(org);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationMatch(orgUser, updatedRequest.OrganizationId)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationState(org)
.Returns(new OrganizationHasKeysError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(updatedRequest);
@@ -457,6 +506,14 @@ public class InitPendingOrganizationCommandTests
.GetByIdAsync(updatedRequest.OrganizationId)
.Returns(org);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationMatch(orgUser, updatedRequest.OrganizationId)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationState(org)
.Returns(new OrganizationHasKeysError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(updatedRequest);
@@ -476,9 +533,9 @@ public class InitPendingOrganizationCommandTests
// Arrange
var updatedRequest = SetupValidOrgAndOrgUser(user, org, orgUser, request, sutProvider);
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg)
.Returns(true);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidatePoliciesAsync(user, updatedRequest.OrganizationId)
.Returns(new SingleOrgPolicyViolationError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(updatedRequest);
@@ -499,33 +556,9 @@ public class InitPendingOrganizationCommandTests
// Arrange
var updatedRequest = SetupValidOrgAndOrgUser(user, org, orgUser, request, sutProvider);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(Arg.Any<string>())
.Returns(false);
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg)
.Returns(false);
// Create a PolicyDetails that requires 2FA for this organization
var policyDetails = new PolicyDetails
{
OrganizationId = updatedRequest.OrganizationId,
OrganizationUserId = updatedRequest.OrganizationUserId,
PolicyType = PolicyType.TwoFactorAuthentication,
OrganizationUserType = OrganizationUserType.Owner,
OrganizationUserStatus = OrganizationUserStatusType.Invited
};
var twoFactorReq = new RequireTwoFactorPolicyRequirement(new[] { policyDetails });
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(twoFactorReq);
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(user)
.Returns(false);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidatePoliciesAsync(user, updatedRequest.OrganizationId)
.Returns(new TwoFactorRequiredError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(updatedRequest);
@@ -549,24 +582,13 @@ public class InitPendingOrganizationCommandTests
org.PlanType = PlanType.Free;
orgUser.Type = OrganizationUserType.Owner;
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(Arg.Any<string>())
.Returns(false);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidatePoliciesAsync(user, updatedRequest.OrganizationId)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg)
.Returns(false);
// Create a RequireTwoFactorPolicyRequirement with no policies (2FA not required)
var twoFactorReq = new RequireTwoFactorPolicyRequirement(Enumerable.Empty<PolicyDetails>());
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(twoFactorReq);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetCountByFreeOrganizationAdminUserAsync(user.Id)
.Returns(1);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateBusinessRulesAsync(user, org, orgUser)
.Returns(new FreeOrgAdminLimitError());
// Act
var result = await sutProvider.Sut.InitPendingOrganizationVNextAsync(updatedRequest);
@@ -585,25 +607,14 @@ public class InitPendingOrganizationCommandTests
{
var updatedRequest = SetupValidOrgAndOrgUser(user, org, orgUser, request, sutProvider);
// Setup policy checks to pass
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(Arg.Any<string>())
.Returns(false);
// Setup validator to pass all policy and business rule checks
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidatePoliciesAsync(user, updatedRequest.OrganizationId)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg)
.Returns(false);
// Create a RequireTwoFactorPolicyRequirement with no policies (2FA not required)
var twoFactorReq = new RequireTwoFactorPolicyRequirement(Enumerable.Empty<PolicyDetails>());
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(twoFactorReq);
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetCountByFreeOrganizationAdminUserAsync(user.Id)
.Returns(0);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateBusinessRulesAsync(user, org, orgUser)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
// Setup repositories to return update delegates
sutProvider.GetDependency<IOrganizationRepository>()
@@ -649,6 +660,15 @@ public class InitPendingOrganizationCommandTests
.GetByIdAsync(updatedRequest.OrganizationId)
.Returns(org);
// Setup validator for organization match and state
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationMatch(orgUser, updatedRequest.OrganizationId)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateOrganizationState(org)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
return updatedRequest;
}
@@ -660,13 +680,20 @@ public class InitPendingOrganizationCommandTests
{
orgUser.Email = user.Email;
var token = CreateToken(orgUser, request.OrganizationUserId, sutProvider);
var updatedRequest = request with { User = user, EmailToken = token };
var updatedRequest = request with { User = user, EmailToken = "valid-token" };
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetByIdAsync(updatedRequest.OrganizationUserId)
.Returns(orgUser);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateInviteToken(orgUser, user, Arg.Any<string>())
.Returns(true);
sutProvider.GetDependency<IInitPendingOrganizationValidator>()
.ValidateUserEmail(orgUser, user)
.Returns((Bit.Core.AdminConsole.Utilities.v2.Error)null);
return updatedRequest;
}

View File

@@ -0,0 +1,435 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
using Bit.Core.Billing.Enums;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Tokens;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Fakes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations;
[SutProviderCustomize]
public class InitPendingOrganizationValidatorTests
{
private readonly IOrgUserInviteTokenableFactory _orgUserInviteTokenableFactory = Substitute.For<IOrgUserInviteTokenableFactory>();
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory = new FakeDataProtectorTokenFactory<OrgUserInviteTokenable>();
[Theory, BitAutoData]
public void ValidateInviteToken_ValidToken_ReturnsTrue(
User user,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
orgUser.Email = user.Email;
sutProvider.SetDependency(_orgUserInviteTokenDataFactory, "orgUserInviteTokenDataFactory");
sutProvider.Create();
_orgUserInviteTokenableFactory.CreateToken(orgUser).Returns(new OrgUserInviteTokenable(orgUser)
{
ExpirationDate = DateTime.UtcNow.Add(TimeSpan.FromDays(5))
});
var orgUserInviteTokenable = _orgUserInviteTokenableFactory.CreateToken(orgUser);
var protectedToken = _orgUserInviteTokenDataFactory.Protect(orgUserInviteTokenable);
// Act
var result = sutProvider.Sut.ValidateInviteToken(orgUser, user, protectedToken);
// Assert
Assert.True(result);
}
[Theory, BitAutoData]
public void ValidateInviteToken_InvalidToken_ReturnsFalse(
User user,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
sutProvider.SetDependency(_orgUserInviteTokenDataFactory, "orgUserInviteTokenDataFactory");
sutProvider.Create();
// Act
var result = sutProvider.Sut.ValidateInviteToken(orgUser, user, "invalid-token");
// Assert
Assert.False(result);
}
[Theory, BitAutoData]
public void ValidateUserEmail_MatchingEmail_ReturnsNull(
User user,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
orgUser.Email = user.Email;
// Act
var result = sutProvider.Sut.ValidateUserEmail(orgUser, user);
// Assert
Assert.Null(result);
}
[Theory, BitAutoData]
public void ValidateUserEmail_MismatchedEmail_ReturnsError(
User user,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
orgUser.Email = "different@example.com";
user.Email = "user@example.com";
// Act
var result = sutProvider.Sut.ValidateUserEmail(orgUser, user);
// Assert
Assert.NotNull(result);
Assert.IsType<EmailMismatchError>(result);
}
[Theory, BitAutoData]
public void ValidateUserEmail_NullOrgUserEmail_ReturnsError(
User user,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
orgUser.Email = null;
// Act
var result = sutProvider.Sut.ValidateUserEmail(orgUser, user);
// Assert
Assert.NotNull(result);
Assert.IsType<EmailMismatchError>(result);
}
[Theory, BitAutoData]
public void ValidateOrganizationState_ValidState_ReturnsNull(
Organization org,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
org.Enabled = false;
org.Status = OrganizationStatusType.Pending;
org.PublicKey = null;
org.PrivateKey = null;
// Act
var result = sutProvider.Sut.ValidateOrganizationState(org);
// Assert
Assert.Null(result);
}
[Theory, BitAutoData]
public void ValidateOrganizationState_OrgEnabled_ReturnsError(
Organization org,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
org.Enabled = true;
org.Status = OrganizationStatusType.Pending;
org.PublicKey = null;
org.PrivateKey = null;
// Act
var result = sutProvider.Sut.ValidateOrganizationState(org);
// Assert
Assert.NotNull(result);
Assert.IsType<OrganizationAlreadyEnabledError>(result);
}
[Theory, BitAutoData]
public void ValidateOrganizationState_OrgNotPending_ReturnsError(
Organization org,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
org.Enabled = false;
org.Status = OrganizationStatusType.Created;
org.PublicKey = null;
org.PrivateKey = null;
// Act
var result = sutProvider.Sut.ValidateOrganizationState(org);
// Assert
Assert.NotNull(result);
Assert.IsType<OrganizationNotPendingError>(result);
}
[Theory, BitAutoData]
public void ValidateOrganizationState_OrgHasKeys_ReturnsError(
Organization org,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
org.Enabled = false;
org.Status = OrganizationStatusType.Pending;
org.PublicKey = "existing-public-key";
org.PrivateKey = "existing-private-key";
// Act
var result = sutProvider.Sut.ValidateOrganizationState(org);
// Assert
Assert.NotNull(result);
Assert.IsType<OrganizationHasKeysError>(result);
}
[Theory, BitAutoData]
public void ValidateOrganizationMatch_Matching_ReturnsNull(
OrganizationUser orgUser,
Guid organizationId,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
orgUser.OrganizationId = organizationId;
// Act
var result = sutProvider.Sut.ValidateOrganizationMatch(orgUser, organizationId);
// Assert
Assert.Null(result);
}
[Theory, BitAutoData]
public void ValidateOrganizationMatch_NotMatching_ReturnsError(
OrganizationUser orgUser,
Guid organizationId,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
orgUser.OrganizationId = Guid.NewGuid();
// Act
var result = sutProvider.Sut.ValidateOrganizationMatch(orgUser, organizationId);
// Assert
Assert.NotNull(result);
Assert.IsType<OrganizationMismatchError>(result);
}
[Theory, BitAutoData]
public async Task ValidatePoliciesAsync_AllPoliciesPass_ReturnsNull(
User user,
Guid organizationId,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(Arg.Any<string>())
.Returns(false);
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg)
.Returns(false);
var twoFactorReq = new RequireTwoFactorPolicyRequirement(Enumerable.Empty<PolicyDetails>());
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(twoFactorReq);
// Act
var result = await sutProvider.Sut.ValidatePoliciesAsync(user, organizationId);
// Assert
Assert.Null(result);
}
[Theory, BitAutoData]
public async Task ValidatePoliciesAsync_SingleOrgPolicyViolation_ReturnsError(
User user,
Guid organizationId,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(Arg.Any<string>())
.Returns(false);
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg)
.Returns(true);
// Act
var result = await sutProvider.Sut.ValidatePoliciesAsync(user, organizationId);
// Assert
Assert.NotNull(result);
Assert.IsType<SingleOrgPolicyViolationError>(result);
}
[Theory, BitAutoData]
public async Task ValidatePoliciesAsync_TwoFactorRequired_UserDoesNotHave2FA_ReturnsError(
User user,
Guid organizationId,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(Arg.Any<string>())
.Returns(false);
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg)
.Returns(false);
var policyDetails = new PolicyDetails
{
OrganizationId = organizationId,
PolicyType = PolicyType.TwoFactorAuthentication,
OrganizationUserType = OrganizationUserType.Owner,
OrganizationUserStatus = OrganizationUserStatusType.Invited
};
var twoFactorReq = new RequireTwoFactorPolicyRequirement(new[] { policyDetails });
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(twoFactorReq);
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(user)
.Returns(false);
// Act
var result = await sutProvider.Sut.ValidatePoliciesAsync(user, organizationId);
// Assert
Assert.NotNull(result);
Assert.IsType<TwoFactorRequiredError>(result);
}
[Theory, BitAutoData]
public async Task ValidateBusinessRulesAsync_PaidOrg_ReturnsNull(
User user,
Organization org,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
org.PlanType = PlanType.EnterpriseAnnually;
orgUser.Type = OrganizationUserType.Owner;
// Act
var result = await sutProvider.Sut.ValidateBusinessRulesAsync(user, org, orgUser);
// Assert
Assert.Null(result);
}
[Theory, BitAutoData]
public async Task ValidateBusinessRulesAsync_FreeOrgNonAdmin_ReturnsNull(
User user,
Organization org,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
org.PlanType = PlanType.Free;
orgUser.Type = OrganizationUserType.User;
// Act
var result = await sutProvider.Sut.ValidateBusinessRulesAsync(user, org, orgUser);
// Assert
Assert.Null(result);
}
[Theory, BitAutoData]
public async Task ValidateBusinessRulesAsync_FreeOrgAdminNoExisting_ReturnsNull(
User user,
Organization org,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
org.PlanType = PlanType.Free;
orgUser.Type = OrganizationUserType.Owner;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetCountByFreeOrganizationAdminUserAsync(user.Id)
.Returns(0);
// Act
var result = await sutProvider.Sut.ValidateBusinessRulesAsync(user, org, orgUser);
// Assert
Assert.Null(result);
}
[Theory, BitAutoData]
public async Task ValidateBusinessRulesAsync_FreeOrgAdminLimitExceeded_ReturnsError(
User user,
Organization org,
OrganizationUser orgUser,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
org.PlanType = PlanType.Free;
orgUser.Type = OrganizationUserType.Owner;
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetCountByFreeOrganizationAdminUserAsync(user.Id)
.Returns(1);
// Act
var result = await sutProvider.Sut.ValidateBusinessRulesAsync(user, org, orgUser);
// Assert
Assert.NotNull(result);
Assert.IsType<FreeOrgAdminLimitError>(result);
}
[Theory, BitAutoData]
public async Task ValidatePoliciesAsync_AutoConfirmPolicyViolation_ReturnsError(
User user,
Guid organizationId,
SutProvider<InitPendingOrganizationValidator> sutProvider)
{
// Arrange
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);
var policyDetails = new PolicyDetails
{
OrganizationId = organizationId,
PolicyType = PolicyType.AutomaticUserConfirmation,
OrganizationUserType = OrganizationUserType.Owner,
OrganizationUserStatus = OrganizationUserStatusType.Invited
};
var autoConfirmReq = new AutomaticUserConfirmationPolicyRequirement(new[] { policyDetails });
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(autoConfirmReq);
// Act
var result = await sutProvider.Sut.ValidatePoliciesAsync(user, organizationId);
// Assert
Assert.NotNull(result);
Assert.IsType<SingleOrgPolicyViolationError>(result);
}
}