mirror of
https://github.com/bitwarden/server.git
synced 2026-02-16 05:43:20 +08:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user