mirror of
https://github.com/bitwarden/server.git
synced 2025-12-10 00:42:07 -06:00
[PM-26377] Correcting Auto Confirm Handler Provider Check (#6681)
* Fixed bug where providers weren't being checked correctly in auto confirm handler.
This commit is contained in:
parent
80ee31b4fe
commit
18a8829476
@ -4,6 +4,7 @@ using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
|||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
using Bit.Core.Repositories;
|
using Bit.Core.Repositories;
|
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||||
@ -17,26 +18,13 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
|||||||
/// <li>All organization users are compliant with the Single organization policy</li>
|
/// <li>All organization users are compliant with the Single organization policy</li>
|
||||||
/// <li>No provider users exist</li>
|
/// <li>No provider users exist</li>
|
||||||
/// </ul>
|
/// </ul>
|
||||||
///
|
|
||||||
/// This class also performs side effects when the policy is being enabled or disabled. They are:
|
|
||||||
/// <ul>
|
|
||||||
/// <li>Sets the UseAutomaticUserConfirmation organization feature to match the policy update</li>
|
|
||||||
/// </ul>
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AutomaticUserConfirmationPolicyEventHandler(
|
public class AutomaticUserConfirmationPolicyEventHandler(
|
||||||
IOrganizationUserRepository organizationUserRepository,
|
IOrganizationUserRepository organizationUserRepository,
|
||||||
IProviderUserRepository providerUserRepository,
|
IProviderUserRepository providerUserRepository)
|
||||||
IPolicyRepository policyRepository,
|
: IPolicyValidator, IPolicyValidationEvent, IEnforceDependentPoliciesEvent
|
||||||
IOrganizationRepository organizationRepository,
|
|
||||||
TimeProvider timeProvider)
|
|
||||||
: IPolicyValidator, IPolicyValidationEvent, IOnPolicyPreUpdateEvent, IEnforceDependentPoliciesEvent
|
|
||||||
{
|
{
|
||||||
public PolicyType Type => PolicyType.AutomaticUserConfirmation;
|
public PolicyType Type => PolicyType.AutomaticUserConfirmation;
|
||||||
public async Task ExecutePreUpsertSideEffectAsync(SavePolicyModel policyRequest, Policy? currentPolicy) =>
|
|
||||||
await OnSaveSideEffectsAsync(policyRequest.PolicyUpdate, currentPolicy);
|
|
||||||
|
|
||||||
private const string _singleOrgPolicyNotEnabledErrorMessage =
|
|
||||||
"The Single organization policy must be enabled before enabling the Automatically confirm invited users policy.";
|
|
||||||
|
|
||||||
private const string _usersNotCompliantWithSingleOrgErrorMessage =
|
private const string _usersNotCompliantWithSingleOrgErrorMessage =
|
||||||
"All organization users must be compliant with the Single organization policy before enabling the Automatically confirm invited users policy. Please remove users who are members of multiple organizations.";
|
"All organization users must be compliant with the Single organization policy before enabling the Automatically confirm invited users policy. Please remove users who are members of multiple organizations.";
|
||||||
@ -61,27 +49,20 @@ public class AutomaticUserConfirmationPolicyEventHandler(
|
|||||||
public async Task<string> ValidateAsync(SavePolicyModel savePolicyModel, Policy? currentPolicy) =>
|
public async Task<string> ValidateAsync(SavePolicyModel savePolicyModel, Policy? currentPolicy) =>
|
||||||
await ValidateAsync(savePolicyModel.PolicyUpdate, currentPolicy);
|
await ValidateAsync(savePolicyModel.PolicyUpdate, currentPolicy);
|
||||||
|
|
||||||
public async Task OnSaveSideEffectsAsync(PolicyUpdate policyUpdate, Policy? currentPolicy)
|
public Task OnSaveSideEffectsAsync(PolicyUpdate policyUpdate, Policy? currentPolicy) =>
|
||||||
{
|
Task.CompletedTask;
|
||||||
var organization = await organizationRepository.GetByIdAsync(policyUpdate.OrganizationId);
|
|
||||||
|
|
||||||
if (organization is not null)
|
|
||||||
{
|
|
||||||
organization.UseAutomaticUserConfirmation = policyUpdate.Enabled;
|
|
||||||
organization.RevisionDate = timeProvider.GetUtcNow().UtcDateTime;
|
|
||||||
await organizationRepository.UpsertAsync(organization);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> ValidateEnablingPolicyAsync(Guid organizationId)
|
private async Task<string> ValidateEnablingPolicyAsync(Guid organizationId)
|
||||||
{
|
{
|
||||||
var singleOrgValidationError = await ValidateSingleOrgPolicyComplianceAsync(organizationId);
|
var organizationUsers = await organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId);
|
||||||
|
|
||||||
|
var singleOrgValidationError = await ValidateUserComplianceWithSingleOrgAsync(organizationId, organizationUsers);
|
||||||
if (!string.IsNullOrWhiteSpace(singleOrgValidationError))
|
if (!string.IsNullOrWhiteSpace(singleOrgValidationError))
|
||||||
{
|
{
|
||||||
return singleOrgValidationError;
|
return singleOrgValidationError;
|
||||||
}
|
}
|
||||||
|
|
||||||
var providerValidationError = await ValidateNoProviderUsersAsync(organizationId);
|
var providerValidationError = await ValidateNoProviderUsersAsync(organizationUsers);
|
||||||
if (!string.IsNullOrWhiteSpace(providerValidationError))
|
if (!string.IsNullOrWhiteSpace(providerValidationError))
|
||||||
{
|
{
|
||||||
return providerValidationError;
|
return providerValidationError;
|
||||||
@ -90,42 +71,24 @@ public class AutomaticUserConfirmationPolicyEventHandler(
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> ValidateSingleOrgPolicyComplianceAsync(Guid organizationId)
|
private async Task<string> ValidateUserComplianceWithSingleOrgAsync(Guid organizationId,
|
||||||
|
ICollection<OrganizationUserUserDetails> organizationUsers)
|
||||||
{
|
{
|
||||||
var singleOrgPolicy = await policyRepository.GetByOrganizationIdTypeAsync(organizationId, PolicyType.SingleOrg);
|
|
||||||
if (singleOrgPolicy is not { Enabled: true })
|
|
||||||
{
|
|
||||||
return _singleOrgPolicyNotEnabledErrorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await ValidateUserComplianceWithSingleOrgAsync(organizationId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> ValidateUserComplianceWithSingleOrgAsync(Guid organizationId)
|
|
||||||
{
|
|
||||||
var organizationUsers = (await organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId))
|
|
||||||
.Where(ou => ou.Status != OrganizationUserStatusType.Invited &&
|
|
||||||
ou.Status != OrganizationUserStatusType.Revoked &&
|
|
||||||
ou.UserId.HasValue)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (organizationUsers.Count == 0)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasNonCompliantUser = (await organizationUserRepository.GetManyByManyUsersAsync(
|
var hasNonCompliantUser = (await organizationUserRepository.GetManyByManyUsersAsync(
|
||||||
organizationUsers.Select(ou => ou.UserId!.Value)))
|
organizationUsers.Select(ou => ou.UserId!.Value)))
|
||||||
.Any(uo => uo.OrganizationId != organizationId &&
|
.Any(uo => uo.OrganizationId != organizationId
|
||||||
uo.Status != OrganizationUserStatusType.Invited);
|
&& uo.Status != OrganizationUserStatusType.Invited);
|
||||||
|
|
||||||
return hasNonCompliantUser ? _usersNotCompliantWithSingleOrgErrorMessage : string.Empty;
|
return hasNonCompliantUser ? _usersNotCompliantWithSingleOrgErrorMessage : string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> ValidateNoProviderUsersAsync(Guid organizationId)
|
private async Task<string> ValidateNoProviderUsersAsync(ICollection<OrganizationUserUserDetails> organizationUsers)
|
||||||
{
|
{
|
||||||
var providerUsers = await providerUserRepository.GetManyByOrganizationAsync(organizationId);
|
var userIds = organizationUsers.Where(x => x.UserId is not null)
|
||||||
|
.Select(x => x.UserId!.Value);
|
||||||
|
|
||||||
return providerUsers.Count > 0 ? _providerUsersExistErrorMessage : string.Empty;
|
return (await providerUserRepository.GetManyByManyUsersAsync(userIds)).Count != 0
|
||||||
|
? _providerUsersExistErrorMessage
|
||||||
|
: string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ public interface IProviderUserRepository : IRepository<ProviderUser, Guid>
|
|||||||
Task<int> GetCountByProviderAsync(Guid providerId, string email, bool onlyRegisteredUsers);
|
Task<int> GetCountByProviderAsync(Guid providerId, string email, bool onlyRegisteredUsers);
|
||||||
Task<ICollection<ProviderUser>> GetManyAsync(IEnumerable<Guid> ids);
|
Task<ICollection<ProviderUser>> GetManyAsync(IEnumerable<Guid> ids);
|
||||||
Task<ICollection<ProviderUser>> GetManyByUserAsync(Guid userId);
|
Task<ICollection<ProviderUser>> GetManyByUserAsync(Guid userId);
|
||||||
|
Task<ICollection<ProviderUser>> GetManyByManyUsersAsync(IEnumerable<Guid> userIds);
|
||||||
Task<ProviderUser?> GetByProviderUserAsync(Guid providerId, Guid userId);
|
Task<ProviderUser?> GetByProviderUserAsync(Guid providerId, Guid userId);
|
||||||
Task<ICollection<ProviderUser>> GetManyByProviderAsync(Guid providerId, ProviderUserType? type = null);
|
Task<ICollection<ProviderUser>> GetManyByProviderAsync(Guid providerId, ProviderUserType? type = null);
|
||||||
Task<ICollection<ProviderUserUserDetails>> GetManyDetailsByProviderAsync(Guid providerId, ProviderUserStatusType? status = null);
|
Task<ICollection<ProviderUserUserDetails>> GetManyDetailsByProviderAsync(Guid providerId, ProviderUserStatusType? status = null);
|
||||||
|
|||||||
@ -61,6 +61,18 @@ public class ProviderUserRepository : Repository<ProviderUser, Guid>, IProviderU
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<ProviderUser>> GetManyByManyUsersAsync(IEnumerable<Guid> userIds)
|
||||||
|
{
|
||||||
|
await using var connection = new SqlConnection(ConnectionString);
|
||||||
|
|
||||||
|
var results = await connection.QueryAsync<ProviderUser>(
|
||||||
|
"[dbo].[ProviderUser_ReadManyByManyUserIds]",
|
||||||
|
new { UserIds = userIds.ToGuidIdArrayTVP() },
|
||||||
|
commandType: CommandType.StoredProcedure);
|
||||||
|
|
||||||
|
return results.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ProviderUser?> GetByProviderUserAsync(Guid providerId, Guid userId)
|
public async Task<ProviderUser?> GetByProviderUserAsync(Guid providerId, Guid userId)
|
||||||
{
|
{
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
|
|||||||
@ -96,6 +96,20 @@ public class ProviderUserRepository :
|
|||||||
return await query.ToArrayAsync();
|
return await query.ToArrayAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ICollection<ProviderUser>> GetManyByManyUsersAsync(IEnumerable<Guid> userIds)
|
||||||
|
{
|
||||||
|
await using var scope = ServiceScopeFactory.CreateAsyncScope();
|
||||||
|
|
||||||
|
var dbContext = GetDatabaseContext(scope);
|
||||||
|
|
||||||
|
var query = from pu in dbContext.ProviderUsers
|
||||||
|
where pu.UserId != null && userIds.Contains(pu.UserId.Value)
|
||||||
|
select pu;
|
||||||
|
|
||||||
|
return await query.ToArrayAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ProviderUser> GetByProviderUserAsync(Guid providerId, Guid userId)
|
public async Task<ProviderUser> GetByProviderUserAsync(Guid providerId, Guid userId)
|
||||||
{
|
{
|
||||||
using (var scope = ServiceScopeFactory.CreateScope())
|
using (var scope = ServiceScopeFactory.CreateScope())
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
CREATE PROCEDURE [dbo].[ProviderUser_ReadManyByManyUserIds]
|
||||||
|
@UserIds AS [dbo].[GuidIdArray] READONLY
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
[pu].*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUserView] AS [pu]
|
||||||
|
INNER JOIN
|
||||||
|
@UserIds [u] ON [u].[Id] = [pu].[UserId]
|
||||||
|
END
|
||||||
@ -21,52 +21,23 @@ namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyValidat
|
|||||||
public class AutomaticUserConfirmationPolicyEventHandlerTests
|
public class AutomaticUserConfirmationPolicyEventHandlerTests
|
||||||
{
|
{
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_SingleOrgNotEnabled_ReturnsError(
|
public void RequiredPolicies_IncludesSingleOrg(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns((Policy?)null);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await sutProvider.Sut.ValidateAsync(policyUpdate, null);
|
var requiredPolicies = sutProvider.Sut.RequiredPolicies;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Contains("Single organization policy must be enabled", result, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains(PolicyType.SingleOrg, requiredPolicies);
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task ValidateAsync_EnablingPolicy_SingleOrgPolicyDisabled_ReturnsError(
|
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
|
||||||
[Policy(PolicyType.SingleOrg, false)] Policy singleOrgPolicy,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(policyUpdate, null);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Contains("Single organization policy must be enabled", result, StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_UsersNotCompliantWithSingleOrg_ReturnsError(
|
public async Task ValidateAsync_EnablingPolicy_UsersNotCompliantWithSingleOrg_ReturnsError(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
Guid nonCompliantUserId,
|
Guid nonCompliantUserId,
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var orgUser = new OrganizationUserUserDetails
|
var orgUser = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
@ -85,10 +56,6 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Status = OrganizationUserStatusType.Confirmed
|
Status = OrganizationUserStatusType.Confirmed
|
||||||
};
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns([orgUser]);
|
.Returns([orgUser]);
|
||||||
@ -107,13 +74,10 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_UserWithInvitedStatusInOtherOrg_ValidationPasses(
|
public async Task ValidateAsync_EnablingPolicy_UserWithInvitedStatusInOtherOrg_ValidationPasses(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
Guid userId,
|
Guid userId,
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var orgUser = new OrganizationUserUserDetails
|
var orgUser = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
@ -121,7 +85,6 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Type = OrganizationUserType.User,
|
Type = OrganizationUserType.User,
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
Status = OrganizationUserStatusType.Confirmed,
|
||||||
UserId = userId,
|
UserId = userId,
|
||||||
Email = "test@email.com"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var otherOrgUser = new OrganizationUser
|
var otherOrgUser = new OrganizationUser
|
||||||
@ -133,10 +96,6 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Email = orgUser.Email
|
Email = orgUser.Email
|
||||||
};
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns([orgUser]);
|
.Returns([orgUser]);
|
||||||
@ -146,7 +105,7 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
.Returns([otherOrgUser]);
|
.Returns([otherOrgUser]);
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderUserRepository>()
|
sutProvider.GetDependency<IProviderUserRepository>()
|
||||||
.GetManyByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyByManyUsersAsync(Arg.Any<IEnumerable<Guid>>())
|
||||||
.Returns([]);
|
.Returns([]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@ -159,30 +118,37 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_ProviderUsersExist_ReturnsError(
|
public async Task ValidateAsync_EnablingPolicy_ProviderUsersExist_ReturnsError(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
Guid userId,
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
var orgUser = new OrganizationUserUserDetails
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
OrganizationId = policyUpdate.OrganizationId,
|
||||||
|
Type = OrganizationUserType.User,
|
||||||
|
Status = OrganizationUserStatusType.Confirmed,
|
||||||
|
UserId = userId
|
||||||
|
};
|
||||||
|
|
||||||
var providerUser = new ProviderUser
|
var providerUser = new ProviderUser
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
ProviderId = Guid.NewGuid(),
|
ProviderId = Guid.NewGuid(),
|
||||||
UserId = Guid.NewGuid(),
|
UserId = userId,
|
||||||
Status = ProviderUserStatusType.Confirmed
|
Status = ProviderUserStatusType.Confirmed
|
||||||
};
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
|
.Returns([orgUser]);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
|
.GetManyByManyUsersAsync(Arg.Any<IEnumerable<Guid>>())
|
||||||
.Returns([]);
|
.Returns([]);
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderUserRepository>()
|
sutProvider.GetDependency<IProviderUserRepository>()
|
||||||
.GetManyByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyByManyUsersAsync(Arg.Any<IEnumerable<Guid>>())
|
||||||
.Returns([providerUser]);
|
.Returns([providerUser]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@ -196,26 +162,18 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_AllValidationsPassed_ReturnsEmptyString(
|
public async Task ValidateAsync_EnablingPolicy_AllValidationsPassed_ReturnsEmptyString(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var orgUser = new OrganizationUserUserDetails
|
var orgUser = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
OrganizationId = policyUpdate.OrganizationId,
|
OrganizationId = policyUpdate.OrganizationId,
|
||||||
Type = OrganizationUserType.User,
|
Type = OrganizationUserType.User,
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
Status = OrganizationUserStatusType.Confirmed,
|
||||||
UserId = Guid.NewGuid(),
|
UserId = Guid.NewGuid()
|
||||||
Email = "user@example.com"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns([orgUser]);
|
.Returns([orgUser]);
|
||||||
@ -225,7 +183,7 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
.Returns([]);
|
.Returns([]);
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderUserRepository>()
|
sutProvider.GetDependency<IProviderUserRepository>()
|
||||||
.GetManyByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyByManyUsersAsync(Arg.Any<IEnumerable<Guid>>())
|
||||||
.Returns([]);
|
.Returns([]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@ -249,9 +207,10 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(string.IsNullOrEmpty(result));
|
Assert.True(string.IsNullOrEmpty(result));
|
||||||
await sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
|
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.DidNotReceive()
|
.DidNotReceive()
|
||||||
.GetByOrganizationIdTypeAsync(Arg.Any<Guid>(), Arg.Any<PolicyType>());
|
.GetManyDetailsByOrganizationAsync(Arg.Any<Guid>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
@ -268,21 +227,18 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(string.IsNullOrEmpty(result));
|
Assert.True(string.IsNullOrEmpty(result));
|
||||||
await sutProvider.GetDependency<IPolicyRepository>()
|
await sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.DidNotReceive()
|
.DidNotReceive()
|
||||||
.GetByOrganizationIdTypeAsync(Arg.Any<Guid>(), Arg.Any<PolicyType>());
|
.GetManyDetailsByOrganizationAsync(Arg.Any<Guid>());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_IncludesOwnersAndAdmins_InComplianceCheck(
|
public async Task ValidateAsync_EnablingPolicy_IncludesOwnersAndAdmins_InComplianceCheck(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
Guid nonCompliantOwnerId,
|
Guid nonCompliantOwnerId,
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var ownerUser = new OrganizationUserUserDetails
|
var ownerUser = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
@ -290,7 +246,6 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Type = OrganizationUserType.Owner,
|
Type = OrganizationUserType.Owner,
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
Status = OrganizationUserStatusType.Confirmed,
|
||||||
UserId = nonCompliantOwnerId,
|
UserId = nonCompliantOwnerId,
|
||||||
Email = "owner@example.com"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var otherOrgUser = new OrganizationUser
|
var otherOrgUser = new OrganizationUser
|
||||||
@ -301,10 +256,6 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Status = OrganizationUserStatusType.Confirmed
|
Status = OrganizationUserStatusType.Confirmed
|
||||||
};
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns([ownerUser]);
|
.Returns([ownerUser]);
|
||||||
@ -323,12 +274,9 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_InvitedUsersExcluded_FromComplianceCheck(
|
public async Task ValidateAsync_EnablingPolicy_InvitedUsersExcluded_FromComplianceCheck(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var invitedUser = new OrganizationUserUserDetails
|
var invitedUser = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
@ -339,16 +287,12 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Email = "invited@example.com"
|
Email = "invited@example.com"
|
||||||
};
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns([invitedUser]);
|
.Returns([invitedUser]);
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderUserRepository>()
|
sutProvider.GetDependency<IProviderUserRepository>()
|
||||||
.GetManyByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyByManyUsersAsync(Arg.Any<IEnumerable<Guid>>())
|
||||||
.Returns([]);
|
.Returns([]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@ -359,14 +303,11 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_RevokedUsersExcluded_FromComplianceCheck(
|
public async Task ValidateAsync_EnablingPolicy_RevokedUsersIncluded_InComplianceCheck(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var revokedUser = new OrganizationUserUserDetails
|
var revokedUser = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
@ -374,38 +315,44 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Type = OrganizationUserType.User,
|
Type = OrganizationUserType.User,
|
||||||
Status = OrganizationUserStatusType.Revoked,
|
Status = OrganizationUserStatusType.Revoked,
|
||||||
UserId = Guid.NewGuid(),
|
UserId = Guid.NewGuid(),
|
||||||
Email = "revoked@example.com"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
var additionalOrgUser = new OrganizationUser
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
{
|
||||||
.Returns(singleOrgPolicy);
|
Id = Guid.NewGuid(),
|
||||||
|
OrganizationId = Guid.NewGuid(),
|
||||||
|
Type = OrganizationUserType.User,
|
||||||
|
Status = OrganizationUserStatusType.Revoked,
|
||||||
|
UserId = revokedUser.UserId,
|
||||||
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
var orgUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
||||||
|
|
||||||
|
orgUserRepository
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns([revokedUser]);
|
.Returns([revokedUser]);
|
||||||
|
|
||||||
|
orgUserRepository.GetManyByManyUsersAsync(Arg.Any<IEnumerable<Guid>>())
|
||||||
|
.Returns([additionalOrgUser]);
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderUserRepository>()
|
sutProvider.GetDependency<IProviderUserRepository>()
|
||||||
.GetManyByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyByManyUsersAsync(Arg.Any<IEnumerable<Guid>>())
|
||||||
.Returns([]);
|
.Returns([]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await sutProvider.Sut.ValidateAsync(policyUpdate, null);
|
var result = await sutProvider.Sut.ValidateAsync(policyUpdate, null);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(string.IsNullOrEmpty(result));
|
Assert.Contains("compliant with the Single organization policy", result, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_EnablingPolicy_AcceptedUsersIncluded_InComplianceCheck(
|
public async Task ValidateAsync_EnablingPolicy_AcceptedUsersIncluded_InComplianceCheck(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
Guid nonCompliantUserId,
|
Guid nonCompliantUserId,
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var acceptedUser = new OrganizationUserUserDetails
|
var acceptedUser = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
@ -413,7 +360,6 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Type = OrganizationUserType.User,
|
Type = OrganizationUserType.User,
|
||||||
Status = OrganizationUserStatusType.Accepted,
|
Status = OrganizationUserStatusType.Accepted,
|
||||||
UserId = nonCompliantUserId,
|
UserId = nonCompliantUserId,
|
||||||
Email = "accepted@example.com"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var otherOrgUser = new OrganizationUser
|
var otherOrgUser = new OrganizationUser
|
||||||
@ -424,10 +370,6 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Status = OrganizationUserStatusType.Confirmed
|
Status = OrganizationUserStatusType.Confirmed
|
||||||
};
|
};
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns([acceptedUser]);
|
.Returns([acceptedUser]);
|
||||||
@ -443,186 +385,22 @@ public class AutomaticUserConfirmationPolicyEventHandlerTests
|
|||||||
Assert.Contains("compliant with the Single organization policy", result, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("compliant with the Single organization policy", result, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task ValidateAsync_EnablingPolicy_EmptyOrganization_ReturnsEmptyString(
|
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns([]);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderUserRepository>()
|
|
||||||
.GetManyByOrganizationAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns([]);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
var result = await sutProvider.Sut.ValidateAsync(policyUpdate, null);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.True(string.IsNullOrEmpty(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ValidateAsync_WithSavePolicyModel_CallsValidateWithPolicyUpdate(
|
public async Task ValidateAsync_WithSavePolicyModel_CallsValidateWithPolicyUpdate(
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.SingleOrg)] Policy singleOrgPolicy,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
singleOrgPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRepository>()
|
|
||||||
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, PolicyType.SingleOrg)
|
|
||||||
.Returns(singleOrgPolicy);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
||||||
.Returns([]);
|
.Returns([]);
|
||||||
|
|
||||||
sutProvider.GetDependency<IProviderUserRepository>()
|
|
||||||
.GetManyByOrganizationAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns([]);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, null);
|
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, null);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.True(string.IsNullOrEmpty(result));
|
Assert.True(string.IsNullOrEmpty(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_EnablingPolicy_SetsUseAutomaticUserConfirmationToTrue(
|
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
|
||||||
Organization organization,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
organization.Id = policyUpdate.OrganizationId;
|
|
||||||
organization.UseAutomaticUserConfirmation = false;
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.GetByIdAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns(organization);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, null);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.Received(1)
|
|
||||||
.UpsertAsync(Arg.Is<Organization>(o =>
|
|
||||||
o.Id == organization.Id &&
|
|
||||||
o.UseAutomaticUserConfirmation == true &&
|
|
||||||
o.RevisionDate > DateTime.MinValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_DisablingPolicy_SetsUseAutomaticUserConfirmationToFalse(
|
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation, false)] PolicyUpdate policyUpdate,
|
|
||||||
Organization organization,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
organization.Id = policyUpdate.OrganizationId;
|
|
||||||
organization.UseAutomaticUserConfirmation = true;
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.GetByIdAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns(organization);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, null);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.Received(1)
|
|
||||||
.UpsertAsync(Arg.Is<Organization>(o =>
|
|
||||||
o.Id == organization.Id &&
|
|
||||||
o.UseAutomaticUserConfirmation == false &&
|
|
||||||
o.RevisionDate > DateTime.MinValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_OrganizationNotFound_DoesNotThrowException(
|
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.GetByIdAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns((Organization?)null);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, null);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.DidNotReceive()
|
|
||||||
.UpsertAsync(Arg.Any<Organization>());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task ExecutePreUpsertSideEffectAsync_CallsOnSaveSideEffectsAsync(
|
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
|
||||||
[Policy(PolicyType.AutomaticUserConfirmation)] Policy currentPolicy,
|
|
||||||
Organization organization,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
organization.Id = policyUpdate.OrganizationId;
|
|
||||||
currentPolicy.OrganizationId = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var savePolicyModel = new SavePolicyModel(policyUpdate);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.GetByIdAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns(organization);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, currentPolicy);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.Received(1)
|
|
||||||
.UpsertAsync(Arg.Is<Organization>(o =>
|
|
||||||
o.Id == organization.Id &&
|
|
||||||
o.UseAutomaticUserConfirmation == policyUpdate.Enabled));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_UpdatesRevisionDate(
|
|
||||||
[PolicyUpdate(PolicyType.AutomaticUserConfirmation)] PolicyUpdate policyUpdate,
|
|
||||||
Organization organization,
|
|
||||||
SutProvider<AutomaticUserConfirmationPolicyEventHandler> sutProvider)
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
organization.Id = policyUpdate.OrganizationId;
|
|
||||||
var originalRevisionDate = DateTime.UtcNow.AddDays(-1);
|
|
||||||
organization.RevisionDate = originalRevisionDate;
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.GetByIdAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns(organization);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, null);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
await sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.Received(1)
|
|
||||||
.UpsertAsync(Arg.Is<Organization>(o =>
|
|
||||||
o.Id == organization.Id &&
|
|
||||||
o.RevisionDate > originalRevisionDate));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,6 +89,286 @@ public class ProviderUserRepositoryTests
|
|||||||
Assert.Equal(serializedSsoConfigData, orgWithSsoDetails.SsoConfig);
|
Assert.Equal(serializedSsoConfigData, orgWithSsoDetails.SsoConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, DatabaseData]
|
||||||
|
public async Task GetManyByManyUsersAsync_WithMultipleUsers_ReturnsAllProviderUsers(
|
||||||
|
IUserRepository userRepository,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
|
{
|
||||||
|
var user1 = await userRepository.CreateTestUserAsync();
|
||||||
|
var user2 = await userRepository.CreateTestUserAsync();
|
||||||
|
var user3 = await userRepository.CreateTestUserAsync();
|
||||||
|
|
||||||
|
var provider1 = await providerRepository.CreateAsync(new Provider
|
||||||
|
{
|
||||||
|
Name = "Test Provider 1",
|
||||||
|
Enabled = true,
|
||||||
|
Type = ProviderType.Msp
|
||||||
|
});
|
||||||
|
|
||||||
|
var provider2 = await providerRepository.CreateAsync(new Provider
|
||||||
|
{
|
||||||
|
Name = "Test Provider 2",
|
||||||
|
Enabled = true,
|
||||||
|
Type = ProviderType.Reseller
|
||||||
|
});
|
||||||
|
|
||||||
|
var providerUser1 = await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
ProviderId = provider1.Id,
|
||||||
|
UserId = user1.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ProviderAdmin
|
||||||
|
});
|
||||||
|
|
||||||
|
var providerUser2 = await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
ProviderId = provider1.Id,
|
||||||
|
UserId = user2.Id,
|
||||||
|
Status = ProviderUserStatusType.Invited,
|
||||||
|
Type = ProviderUserType.ServiceUser
|
||||||
|
});
|
||||||
|
|
||||||
|
var providerUser3 = await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
ProviderId = provider2.Id,
|
||||||
|
UserId = user3.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ProviderAdmin
|
||||||
|
});
|
||||||
|
|
||||||
|
var userIds = new[] { user1.Id, user2.Id, user3.Id };
|
||||||
|
|
||||||
|
var results = (await providerUserRepository.GetManyByManyUsersAsync(userIds)).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(3, results.Count);
|
||||||
|
Assert.Contains(results, pu => pu.Id == providerUser1.Id && pu.UserId == user1.Id);
|
||||||
|
Assert.Contains(results, pu => pu.Id == providerUser2.Id && pu.UserId == user2.Id);
|
||||||
|
Assert.Contains(results, pu => pu.Id == providerUser3.Id && pu.UserId == user3.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, DatabaseData]
|
||||||
|
public async Task GetManyByManyUsersAsync_WithSingleUser_ReturnsSingleProviderUser(
|
||||||
|
IUserRepository userRepository,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
|
{
|
||||||
|
var user = await userRepository.CreateTestUserAsync();
|
||||||
|
|
||||||
|
var provider = await providerRepository.CreateAsync(new Provider
|
||||||
|
{
|
||||||
|
Name = "Test Provider",
|
||||||
|
Enabled = true,
|
||||||
|
Type = ProviderType.Msp
|
||||||
|
});
|
||||||
|
|
||||||
|
var providerUser = await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
UserId = user.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ProviderAdmin
|
||||||
|
});
|
||||||
|
|
||||||
|
var results = (await providerUserRepository.GetManyByManyUsersAsync([user.Id])).ToList();
|
||||||
|
|
||||||
|
Assert.Single(results);
|
||||||
|
Assert.Equal(user.Id, results[0].UserId);
|
||||||
|
Assert.Equal(provider.Id, results[0].ProviderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, DatabaseData]
|
||||||
|
public async Task GetManyByManyUsersAsync_WithUserHavingMultipleProviders_ReturnsAllProviderUsers(
|
||||||
|
IUserRepository userRepository,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
|
{
|
||||||
|
var user = await userRepository.CreateTestUserAsync();
|
||||||
|
|
||||||
|
var provider1 = await providerRepository.CreateAsync(new Provider
|
||||||
|
{
|
||||||
|
Name = "Test Provider 1",
|
||||||
|
Enabled = true,
|
||||||
|
Type = ProviderType.Msp
|
||||||
|
});
|
||||||
|
|
||||||
|
var provider2 = await providerRepository.CreateAsync(new Provider
|
||||||
|
{
|
||||||
|
Name = "Test Provider 2",
|
||||||
|
Enabled = true,
|
||||||
|
Type = ProviderType.Reseller
|
||||||
|
});
|
||||||
|
|
||||||
|
var providerUser1 = await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider1.Id,
|
||||||
|
UserId = user.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ProviderAdmin
|
||||||
|
});
|
||||||
|
|
||||||
|
var providerUser2 = await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider2.Id,
|
||||||
|
UserId = user.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ServiceUser
|
||||||
|
});
|
||||||
|
|
||||||
|
var results = (await providerUserRepository.GetManyByManyUsersAsync([user.Id])).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(2, results.Count);
|
||||||
|
Assert.Contains(results, pu => pu.Id == providerUser1.Id);
|
||||||
|
Assert.Contains(results, pu => pu.Id == providerUser2.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, DatabaseData]
|
||||||
|
public async Task GetManyByManyUsersAsync_WithEmptyUserIds_ReturnsEmpty(
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
|
{
|
||||||
|
var results = await providerUserRepository.GetManyByManyUsersAsync(Array.Empty<Guid>());
|
||||||
|
|
||||||
|
Assert.Empty(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, DatabaseData]
|
||||||
|
public async Task GetManyByManyUsersAsync_WithNonExistentUserIds_ReturnsEmpty(
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
|
{
|
||||||
|
var nonExistentUserIds = new[] { Guid.NewGuid(), Guid.NewGuid() };
|
||||||
|
|
||||||
|
var results = await providerUserRepository.GetManyByManyUsersAsync(nonExistentUserIds);
|
||||||
|
|
||||||
|
Assert.Empty(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, DatabaseData]
|
||||||
|
public async Task GetManyByManyUsersAsync_WithMixedExistentAndNonExistentUserIds_ReturnsOnlyExistent(
|
||||||
|
IUserRepository userRepository,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
|
{
|
||||||
|
var existingUser = await userRepository.CreateTestUserAsync();
|
||||||
|
|
||||||
|
var provider = await providerRepository.CreateAsync(new Provider
|
||||||
|
{
|
||||||
|
Name = "Test Provider",
|
||||||
|
Enabled = true,
|
||||||
|
Type = ProviderType.Msp
|
||||||
|
});
|
||||||
|
|
||||||
|
var providerUser = await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
UserId = existingUser.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ProviderAdmin
|
||||||
|
});
|
||||||
|
|
||||||
|
var userIds = new[] { existingUser.Id, Guid.NewGuid(), Guid.NewGuid() };
|
||||||
|
|
||||||
|
var results = (await providerUserRepository.GetManyByManyUsersAsync(userIds)).ToList();
|
||||||
|
|
||||||
|
Assert.Single(results);
|
||||||
|
Assert.Equal(existingUser.Id, results[0].UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, DatabaseData]
|
||||||
|
public async Task GetManyByManyUsersAsync_ReturnsAllStatuses(
|
||||||
|
IUserRepository userRepository,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
|
{
|
||||||
|
var user1 = await userRepository.CreateTestUserAsync();
|
||||||
|
var user2 = await userRepository.CreateTestUserAsync();
|
||||||
|
var user3 = await userRepository.CreateTestUserAsync();
|
||||||
|
|
||||||
|
var provider = await providerRepository.CreateAsync(new Provider
|
||||||
|
{
|
||||||
|
Name = "Test Provider",
|
||||||
|
Enabled = true,
|
||||||
|
Type = ProviderType.Msp
|
||||||
|
});
|
||||||
|
|
||||||
|
await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
UserId = user1.Id,
|
||||||
|
Status = ProviderUserStatusType.Invited,
|
||||||
|
Type = ProviderUserType.ServiceUser
|
||||||
|
});
|
||||||
|
|
||||||
|
await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
UserId = user2.Id,
|
||||||
|
Status = ProviderUserStatusType.Accepted,
|
||||||
|
Type = ProviderUserType.ServiceUser
|
||||||
|
});
|
||||||
|
|
||||||
|
await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
UserId = user3.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ProviderAdmin
|
||||||
|
});
|
||||||
|
|
||||||
|
var userIds = new[] { user1.Id, user2.Id, user3.Id };
|
||||||
|
|
||||||
|
var results = (await providerUserRepository.GetManyByManyUsersAsync(userIds)).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(3, results.Count);
|
||||||
|
Assert.Contains(results, pu => pu.UserId == user1.Id && pu.Status == ProviderUserStatusType.Invited);
|
||||||
|
Assert.Contains(results, pu => pu.UserId == user2.Id && pu.Status == ProviderUserStatusType.Accepted);
|
||||||
|
Assert.Contains(results, pu => pu.UserId == user3.Id && pu.Status == ProviderUserStatusType.Confirmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, DatabaseData]
|
||||||
|
public async Task GetManyByManyUsersAsync_ReturnsAllProviderUserTypes(
|
||||||
|
IUserRepository userRepository,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
|
IProviderUserRepository providerUserRepository)
|
||||||
|
{
|
||||||
|
var user1 = await userRepository.CreateTestUserAsync();
|
||||||
|
var user2 = await userRepository.CreateTestUserAsync();
|
||||||
|
|
||||||
|
var provider = await providerRepository.CreateAsync(new Provider
|
||||||
|
{
|
||||||
|
Name = "Test Provider",
|
||||||
|
Enabled = true,
|
||||||
|
Type = ProviderType.Msp
|
||||||
|
});
|
||||||
|
|
||||||
|
await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
UserId = user1.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ServiceUser
|
||||||
|
});
|
||||||
|
|
||||||
|
await providerUserRepository.CreateAsync(new ProviderUser
|
||||||
|
{
|
||||||
|
ProviderId = provider.Id,
|
||||||
|
UserId = user2.Id,
|
||||||
|
Status = ProviderUserStatusType.Confirmed,
|
||||||
|
Type = ProviderUserType.ProviderAdmin
|
||||||
|
});
|
||||||
|
|
||||||
|
var userIds = new[] { user1.Id, user2.Id };
|
||||||
|
|
||||||
|
var results = (await providerUserRepository.GetManyByManyUsersAsync(userIds)).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(2, results.Count);
|
||||||
|
Assert.Contains(results, pu => pu.UserId == user1.Id && pu.Type == ProviderUserType.ServiceUser);
|
||||||
|
Assert.Contains(results, pu => pu.UserId == user2.Id && pu.Type == ProviderUserType.ProviderAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
private static void AssertProviderOrganizationDetails(
|
private static void AssertProviderOrganizationDetails(
|
||||||
ProviderUserOrganizationDetails actual,
|
ProviderUserOrganizationDetails actual,
|
||||||
Organization expectedOrganization,
|
Organization expectedOrganization,
|
||||||
@ -139,4 +419,6 @@ public class ProviderUserRepositoryTests
|
|||||||
Assert.Equal(expectedProviderUser.Status, actual.Status);
|
Assert.Equal(expectedProviderUser.Status, actual.Status);
|
||||||
Assert.Equal(expectedProviderUser.Type, actual.Type);
|
Assert.Equal(expectedProviderUser.Type, actual.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,13 @@
|
|||||||
|
CREATE OR ALTER PROCEDURE [dbo].[ProviderUser_ReadManyByManyUserIds]
|
||||||
|
@UserIds AS [dbo].[GuidIdArray] READONLY
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
SET NOCOUNT ON
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
[pu].*
|
||||||
|
FROM
|
||||||
|
[dbo].[ProviderUserView] AS [pu]
|
||||||
|
INNER JOIN
|
||||||
|
@UserIds [u] ON [u].[Id] = [pu].[UserId]
|
||||||
|
END
|
||||||
Loading…
x
Reference in New Issue
Block a user