mirror of
https://github.com/bitwarden/server.git
synced 2025-04-05 05:00:19 -05:00
[PM-18876] Refine PolicyRequirements API (#5445)
* make the PolicyRequirements API more granular, e.g. replace factory methods with a factory interface * update Send to use the new API
This commit is contained in:
parent
29dc69a77b
commit
224ef1272e
@ -8,21 +8,25 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
|
|||||||
|
|
||||||
public class PolicyRequirementQuery(
|
public class PolicyRequirementQuery(
|
||||||
IPolicyRepository policyRepository,
|
IPolicyRepository policyRepository,
|
||||||
IEnumerable<RequirementFactory<IPolicyRequirement>> factories)
|
IEnumerable<IPolicyRequirementFactory<IPolicyRequirement>> factories)
|
||||||
: IPolicyRequirementQuery
|
: IPolicyRequirementQuery
|
||||||
{
|
{
|
||||||
public async Task<T> GetAsync<T>(Guid userId) where T : IPolicyRequirement
|
public async Task<T> GetAsync<T>(Guid userId) where T : IPolicyRequirement
|
||||||
{
|
{
|
||||||
var factory = factories.OfType<RequirementFactory<T>>().SingleOrDefault();
|
var factory = factories.OfType<IPolicyRequirementFactory<T>>().SingleOrDefault();
|
||||||
if (factory is null)
|
if (factory is null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("No Policy Requirement found for " + typeof(T));
|
throw new NotImplementedException("No Requirement Factory found for " + typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
return factory(await GetPolicyDetails(userId));
|
var policyDetails = await GetPolicyDetails(userId);
|
||||||
|
var filteredPolicies = policyDetails
|
||||||
|
.Where(p => p.PolicyType == factory.PolicyType)
|
||||||
|
.Where(factory.Enforce);
|
||||||
|
var requirement = factory.Create(filteredPolicies);
|
||||||
|
return requirement;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<IEnumerable<PolicyDetails>> GetPolicyDetails(Guid userId) =>
|
private Task<IEnumerable<PolicyDetails>> GetPolicyDetails(Guid userId)
|
||||||
policyRepository.GetPolicyDetailsByUserId(userId);
|
=> policyRepository.GetPolicyDetailsByUserId(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A simple base implementation of <see cref="IPolicyRequirementFactory{T}"/> which will be suitable for most policies.
|
||||||
|
/// It provides sensible defaults to help teams to implement their own Policy Requirements.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public abstract class BasePolicyRequirementFactory<T> : IPolicyRequirementFactory<T> where T : IPolicyRequirement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// User roles that are exempt from policy enforcement.
|
||||||
|
/// Owners and Admins are exempt by default but this may be overridden.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual IEnumerable<OrganizationUserType> ExemptRoles { get; } =
|
||||||
|
[OrganizationUserType.Owner, OrganizationUserType.Admin];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// User statuses that are exempt from policy enforcement.
|
||||||
|
/// Invited and Revoked users are exempt by default, which is appropriate in the majority of cases.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual IEnumerable<OrganizationUserStatusType> ExemptStatuses { get; } =
|
||||||
|
[OrganizationUserStatusType.Invited, OrganizationUserStatusType.Revoked];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a Provider User for the organization is exempt from policy enforcement.
|
||||||
|
/// Provider Users are exempt by default, which is appropriate in the majority of cases.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool ExemptProviders { get; } = true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public abstract PolicyType PolicyType { get; }
|
||||||
|
|
||||||
|
public bool Enforce(PolicyDetails policyDetails)
|
||||||
|
=> !policyDetails.HasRole(ExemptRoles) &&
|
||||||
|
!policyDetails.HasStatus(ExemptStatuses) &&
|
||||||
|
(!policyDetails.IsProvider || !ExemptProviders);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public abstract T Create(IEnumerable<PolicyDetails> policyDetails);
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
|
||||||
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Policy requirements for the Disable Send policy.
|
||||||
|
/// </summary>
|
||||||
|
public class DisableSendPolicyRequirement : IPolicyRequirement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether Send is disabled for the user. If true, the user should not be able to create or edit Sends.
|
||||||
|
/// They may still delete existing Sends.
|
||||||
|
/// </summary>
|
||||||
|
public bool DisableSend { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DisableSendPolicyRequirementFactory : BasePolicyRequirementFactory<DisableSendPolicyRequirement>
|
||||||
|
{
|
||||||
|
public override PolicyType PolicyType => PolicyType.DisableSend;
|
||||||
|
|
||||||
|
public override DisableSendPolicyRequirement Create(IEnumerable<PolicyDetails> policyDetails)
|
||||||
|
{
|
||||||
|
var result = new DisableSendPolicyRequirement { DisableSend = policyDetails.Any() };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +1,11 @@
|
|||||||
#nullable enable
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
|
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the business requirements of how one or more enterprise policies will be enforced against a user.
|
/// An object that represents how a <see cref="PolicyType"/> will be enforced against a user.
|
||||||
/// The implementation of this interface will depend on how the policies are enforced in the relevant domain.
|
/// This acts as a bridge between the <see cref="Policy"/> entity saved to the database and the domain that the policy
|
||||||
|
/// affects. You may represent the impact of the policy in any way that makes sense for the domain.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPolicyRequirement;
|
public interface IPolicyRequirement;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A factory function that takes a sequence of <see cref="PolicyDetails"/> and transforms them into a single
|
|
||||||
/// <see cref="IPolicyRequirement"/> for consumption by the relevant domain. This will receive *all* policy types
|
|
||||||
/// that may be enforced against a user; when implementing this delegate, you must filter out irrelevant policy types
|
|
||||||
/// as well as policies that should not be enforced against a user (e.g. due to the user's role or status).
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// See <see cref="PolicyRequirementHelpers"/> for extension methods to handle common requirements when implementing
|
|
||||||
/// this delegate.
|
|
||||||
/// </remarks>
|
|
||||||
public delegate T RequirementFactory<out T>(IEnumerable<PolicyDetails> policyDetails)
|
|
||||||
where T : IPolicyRequirement;
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
|
||||||
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An interface that defines how to create a single <see cref="IPolicyRequirement"/> from a sequence of
|
||||||
|
/// <see cref="PolicyDetails"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The <see cref="IPolicyRequirement"/> that the factory produces.</typeparam>
|
||||||
|
/// <remarks>
|
||||||
|
/// See <see cref="BasePolicyRequirementFactory{T}"/> for a simple base implementation suitable for most policies.
|
||||||
|
/// </remarks>
|
||||||
|
public interface IPolicyRequirementFactory<out T> where T : IPolicyRequirement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="PolicyType"/> that the requirement relates to.
|
||||||
|
/// </summary>
|
||||||
|
PolicyType PolicyType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A predicate that determines whether a policy should be enforced against the user.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Use this to exempt users based on their role, status or other attributes.</remarks>
|
||||||
|
/// <param name="policyDetails">Policy details for the defined PolicyType.</param>
|
||||||
|
/// <returns>True if the policy should be enforced against the user, false otherwise.</returns>
|
||||||
|
bool Enforce(PolicyDetails policyDetails);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A reducer method that creates a single <see cref="IPolicyRequirement"/> from a set of PolicyDetails.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="policyDetails">
|
||||||
|
/// PolicyDetails for the specified PolicyType, after they have been filtered by the Enforce predicate. That is,
|
||||||
|
/// this is the final interface to be called.
|
||||||
|
/// </param>
|
||||||
|
T Create(IEnumerable<PolicyDetails> policyDetails);
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using Bit.Core.AdminConsole.Enums;
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
@ -7,35 +6,16 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements
|
|||||||
public static class PolicyRequirementHelpers
|
public static class PolicyRequirementHelpers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters the PolicyDetails by PolicyType. This is generally required to only get the PolicyDetails that your
|
/// Returns true if the <see cref="PolicyDetails"/> is for one of the specified roles, false otherwise.
|
||||||
/// IPolicyRequirement relates to.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<PolicyDetails> GetPolicyType(
|
public static bool HasRole(
|
||||||
this IEnumerable<PolicyDetails> policyDetails,
|
this PolicyDetails policyDetails,
|
||||||
PolicyType type)
|
|
||||||
=> policyDetails.Where(x => x.PolicyType == type);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filters the PolicyDetails to remove the specified user roles. This can be used to exempt
|
|
||||||
/// owners and admins from policy enforcement.
|
|
||||||
/// </summary>
|
|
||||||
public static IEnumerable<PolicyDetails> ExemptRoles(
|
|
||||||
this IEnumerable<PolicyDetails> policyDetails,
|
|
||||||
IEnumerable<OrganizationUserType> roles)
|
IEnumerable<OrganizationUserType> roles)
|
||||||
=> policyDetails.Where(x => !roles.Contains(x.OrganizationUserType));
|
=> roles.Contains(policyDetails.OrganizationUserType);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters the PolicyDetails to remove organization users who are also provider users for the organization.
|
/// Returns true if the <see cref="PolicyDetails"/> relates to one of the specified statuses, false otherwise.
|
||||||
/// This can be used to exempt provider users from policy enforcement.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<PolicyDetails> ExemptProviders(this IEnumerable<PolicyDetails> policyDetails)
|
public static bool HasStatus(this PolicyDetails policyDetails, IEnumerable<OrganizationUserStatusType> status)
|
||||||
=> policyDetails.Where(x => !x.IsProvider);
|
=> status.Contains(policyDetails.OrganizationUserStatus);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Filters the PolicyDetails to remove the specified organization user statuses. For example, this can be used
|
|
||||||
/// to exempt users in the invited and revoked statuses from policy enforcement.
|
|
||||||
/// </summary>
|
|
||||||
public static IEnumerable<PolicyDetails> ExemptStatus(
|
|
||||||
this IEnumerable<PolicyDetails> policyDetails, IEnumerable<OrganizationUserStatusType> status)
|
|
||||||
=> policyDetails.Where(x => !status.Contains(x.OrganizationUserStatus));
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
|
||||||
|
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Policy requirements for the Send Options policy.
|
||||||
|
/// </summary>
|
||||||
|
public class SendOptionsPolicyRequirement : IPolicyRequirement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether the user is prohibited from hiding their email from the recipient of a Send.
|
||||||
|
/// </summary>
|
||||||
|
public bool DisableHideEmail { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SendOptionsPolicyRequirementFactory : BasePolicyRequirementFactory<SendOptionsPolicyRequirement>
|
||||||
|
{
|
||||||
|
public override PolicyType PolicyType => PolicyType.SendOptions;
|
||||||
|
|
||||||
|
public override SendOptionsPolicyRequirement Create(IEnumerable<PolicyDetails> policyDetails)
|
||||||
|
{
|
||||||
|
var result = policyDetails
|
||||||
|
.Select(p => p.GetDataModel<SendOptionsPolicyData>())
|
||||||
|
.Aggregate(
|
||||||
|
new SendOptionsPolicyRequirement(),
|
||||||
|
(result, data) => new SendOptionsPolicyRequirement
|
||||||
|
{
|
||||||
|
DisableHideEmail = result.DisableHideEmail || data.DisableHideEmail
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -1,54 +0,0 @@
|
|||||||
using Bit.Core.AdminConsole.Enums;
|
|
||||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
|
|
||||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Policy requirements for the Disable Send and Send Options policies.
|
|
||||||
/// </summary>
|
|
||||||
public class SendPolicyRequirement : IPolicyRequirement
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates whether Send is disabled for the user. If true, the user should not be able to create or edit Sends.
|
|
||||||
/// They may still delete existing Sends.
|
|
||||||
/// </summary>
|
|
||||||
public bool DisableSend { get; init; }
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates whether the user is prohibited from hiding their email from the recipient of a Send.
|
|
||||||
/// </summary>
|
|
||||||
public bool DisableHideEmail { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new SendPolicyRequirement.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="policyDetails">All PolicyDetails relating to the user.</param>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is a <see cref="RequirementFactory{T}"/> for the SendPolicyRequirement.
|
|
||||||
/// </remarks>
|
|
||||||
public static SendPolicyRequirement Create(IEnumerable<PolicyDetails> policyDetails)
|
|
||||||
{
|
|
||||||
var filteredPolicies = policyDetails
|
|
||||||
.ExemptRoles([OrganizationUserType.Owner, OrganizationUserType.Admin])
|
|
||||||
.ExemptStatus([OrganizationUserStatusType.Invited, OrganizationUserStatusType.Revoked])
|
|
||||||
.ExemptProviders()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var result = filteredPolicies
|
|
||||||
.GetPolicyType(PolicyType.SendOptions)
|
|
||||||
.Select(p => p.GetDataModel<SendOptionsPolicyData>())
|
|
||||||
.Aggregate(
|
|
||||||
new SendPolicyRequirement
|
|
||||||
{
|
|
||||||
// Set Disable Send requirement in the initial seed
|
|
||||||
DisableSend = filteredPolicies.GetPolicyType(PolicyType.DisableSend).Any()
|
|
||||||
},
|
|
||||||
(result, data) => new SendPolicyRequirement
|
|
||||||
{
|
|
||||||
DisableSend = result.DisableSend,
|
|
||||||
DisableHideEmail = result.DisableHideEmail || data.DisableHideEmail
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,32 +31,7 @@ public static class PolicyServiceCollectionExtensions
|
|||||||
|
|
||||||
private static void AddPolicyRequirements(this IServiceCollection services)
|
private static void AddPolicyRequirements(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
// Register policy requirement factories here
|
services.AddScoped<IPolicyRequirementFactory<IPolicyRequirement>, DisableSendPolicyRequirementFactory>();
|
||||||
services.AddPolicyRequirement(SendPolicyRequirement.Create);
|
services.AddScoped<IPolicyRequirementFactory<IPolicyRequirement>, SendOptionsPolicyRequirementFactory>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used to register simple policy requirements where its factory method implements CreateRequirement.
|
|
||||||
/// This MUST be used rather than calling AddScoped directly, because it will ensure the factory method has
|
|
||||||
/// the correct type to be injected and then identified by <see cref="PolicyRequirementQuery"/> at runtime.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The specific PolicyRequirement being registered.</typeparam>
|
|
||||||
private static void AddPolicyRequirement<T>(this IServiceCollection serviceCollection, RequirementFactory<T> factory)
|
|
||||||
where T : class, IPolicyRequirement
|
|
||||||
=> serviceCollection.AddPolicyRequirement(_ => factory);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used to register policy requirements where you need to access additional dependencies (usually to return a
|
|
||||||
/// curried factory method).
|
|
||||||
/// This MUST be used rather than calling AddScoped directly, because it will ensure the factory method has
|
|
||||||
/// the correct type to be injected and then identified by <see cref="PolicyRequirementQuery"/> at runtime.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">
|
|
||||||
/// A callback that takes IServiceProvider and returns a RequirementFactory for
|
|
||||||
/// your policy requirement.
|
|
||||||
/// </typeparam>
|
|
||||||
private static void AddPolicyRequirement<T>(this IServiceCollection serviceCollection,
|
|
||||||
Func<IServiceProvider, RequirementFactory<T>> factory)
|
|
||||||
where T : class, IPolicyRequirement
|
|
||||||
=> serviceCollection.AddScoped<RequirementFactory<IPolicyRequirement>>(factory);
|
|
||||||
}
|
}
|
||||||
|
@ -326,14 +326,14 @@ public class SendService : ISendService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sendPolicyRequirement = await _policyRequirementQuery.GetAsync<SendPolicyRequirement>(userId.Value);
|
var disableSendRequirement = await _policyRequirementQuery.GetAsync<DisableSendPolicyRequirement>(userId.Value);
|
||||||
|
if (disableSendRequirement.DisableSend)
|
||||||
if (sendPolicyRequirement.DisableSend)
|
|
||||||
{
|
{
|
||||||
throw new BadRequestException("Due to an Enterprise Policy, you are only able to delete an existing Send.");
|
throw new BadRequestException("Due to an Enterprise Policy, you are only able to delete an existing Send.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendPolicyRequirement.DisableHideEmail && send.HideEmail.GetValueOrDefault())
|
var sendOptionsRequirement = await _policyRequirementQuery.GetAsync<SendOptionsPolicyRequirement>(userId.Value);
|
||||||
|
if (sendOptionsRequirement.DisableHideEmail && send.HideEmail.GetValueOrDefault())
|
||||||
{
|
{
|
||||||
throw new BadRequestException("Due to an Enterprise Policy, you are not allowed to hide your email address from recipients when creating or editing a Send.");
|
throw new BadRequestException("Due to an Enterprise Policy, you are not allowed to hide your email address from recipients when creating or editing a Send.");
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
|
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Intentionally simplified PolicyRequirement that just holds the input PolicyDetails for us to assert against.
|
||||||
|
/// </summary>
|
||||||
|
public class TestPolicyRequirement : IPolicyRequirement
|
||||||
|
{
|
||||||
|
public IEnumerable<PolicyDetails> Policies { get; init; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestPolicyRequirementFactory(Func<PolicyDetails, bool> enforce) : IPolicyRequirementFactory<TestPolicyRequirement>
|
||||||
|
{
|
||||||
|
public PolicyType PolicyType => PolicyType.SingleOrg;
|
||||||
|
|
||||||
|
public bool Enforce(PolicyDetails policyDetails) => enforce(policyDetails);
|
||||||
|
|
||||||
|
public TestPolicyRequirement Create(IEnumerable<PolicyDetails> policyDetails)
|
||||||
|
=> new() { Policies = policyDetails };
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Implementations;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
|
||||||
using Bit.Core.AdminConsole.Repositories;
|
using Bit.Core.AdminConsole.Repositories;
|
||||||
using Bit.Test.Common.AutoFixture.Attributes;
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
using NSubstitute;
|
using NSubstitute;
|
||||||
@ -11,50 +11,72 @@ namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies;
|
|||||||
[SutProviderCustomize]
|
[SutProviderCustomize]
|
||||||
public class PolicyRequirementQueryTests
|
public class PolicyRequirementQueryTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Tests that the query correctly registers, retrieves and instantiates arbitrary IPolicyRequirements
|
|
||||||
/// according to their provided CreateRequirement delegate.
|
|
||||||
/// </summary>
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetAsync_Works(Guid userId, Guid organizationId)
|
public async Task GetAsync_IgnoresOtherPolicyTypes(Guid userId)
|
||||||
{
|
{
|
||||||
|
var thisPolicy = new PolicyDetails { PolicyType = PolicyType.SingleOrg };
|
||||||
|
var otherPolicy = new PolicyDetails { PolicyType = PolicyType.RequireSso };
|
||||||
var policyRepository = Substitute.For<IPolicyRepository>();
|
var policyRepository = Substitute.For<IPolicyRepository>();
|
||||||
var factories = new List<RequirementFactory<IPolicyRequirement>>
|
policyRepository.GetPolicyDetailsByUserId(userId).Returns([otherPolicy, thisPolicy]);
|
||||||
{
|
|
||||||
// In prod this cast is handled when the CreateRequirement delegate is registered in DI
|
|
||||||
(RequirementFactory<TestPolicyRequirement>)TestPolicyRequirement.Create
|
|
||||||
};
|
|
||||||
|
|
||||||
var sut = new PolicyRequirementQuery(policyRepository, factories);
|
var factory = new TestPolicyRequirementFactory(_ => true);
|
||||||
policyRepository.GetPolicyDetailsByUserId(userId).Returns([
|
var sut = new PolicyRequirementQuery(policyRepository, [factory]);
|
||||||
new PolicyDetails
|
|
||||||
{
|
|
||||||
OrganizationId = organizationId
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
var requirement = await sut.GetAsync<TestPolicyRequirement>(userId);
|
var requirement = await sut.GetAsync<TestPolicyRequirement>(userId);
|
||||||
Assert.Equal(organizationId, requirement.OrganizationId);
|
|
||||||
|
Assert.Contains(thisPolicy, requirement.Policies);
|
||||||
|
Assert.DoesNotContain(otherPolicy, requirement.Policies);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task GetAsync_ThrowsIfNoRequirementRegistered(Guid userId)
|
public async Task GetAsync_CallsEnforceCallback(Guid userId)
|
||||||
|
{
|
||||||
|
// Arrange policies
|
||||||
|
var policyRepository = Substitute.For<IPolicyRepository>();
|
||||||
|
var thisPolicy = new PolicyDetails { PolicyType = PolicyType.SingleOrg };
|
||||||
|
var otherPolicy = new PolicyDetails { PolicyType = PolicyType.SingleOrg };
|
||||||
|
policyRepository.GetPolicyDetailsByUserId(userId).Returns([thisPolicy, otherPolicy]);
|
||||||
|
|
||||||
|
// Arrange a substitute Enforce function so that we can inspect the received calls
|
||||||
|
var callback = Substitute.For<Func<PolicyDetails, bool>>();
|
||||||
|
callback(Arg.Any<PolicyDetails>()).Returns(x => x.Arg<PolicyDetails>() == thisPolicy);
|
||||||
|
|
||||||
|
// Arrange the sut
|
||||||
|
var factory = new TestPolicyRequirementFactory(callback);
|
||||||
|
var sut = new PolicyRequirementQuery(policyRepository, [factory]);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var requirement = await sut.GetAsync<TestPolicyRequirement>(userId);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Contains(thisPolicy, requirement.Policies);
|
||||||
|
Assert.DoesNotContain(otherPolicy, requirement.Policies);
|
||||||
|
callback.Received()(Arg.Is(thisPolicy));
|
||||||
|
callback.Received()(Arg.Is(otherPolicy));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetAsync_ThrowsIfNoFactoryRegistered(Guid userId)
|
||||||
{
|
{
|
||||||
var policyRepository = Substitute.For<IPolicyRepository>();
|
var policyRepository = Substitute.For<IPolicyRepository>();
|
||||||
var sut = new PolicyRequirementQuery(policyRepository, []);
|
var sut = new PolicyRequirementQuery(policyRepository, []);
|
||||||
|
|
||||||
var exception = await Assert.ThrowsAsync<NotImplementedException>(()
|
var exception = await Assert.ThrowsAsync<NotImplementedException>(()
|
||||||
=> sut.GetAsync<TestPolicyRequirement>(userId));
|
=> sut.GetAsync<TestPolicyRequirement>(userId));
|
||||||
Assert.Contains("No Policy Requirement found", exception.Message);
|
Assert.Contains("No Requirement Factory found", exception.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
[Theory, BitAutoData]
|
||||||
/// Intentionally simplified PolicyRequirement that just holds the Policy.OrganizationId for us to assert against.
|
public async Task GetAsync_HandlesNoPolicies(Guid userId)
|
||||||
/// </summary>
|
|
||||||
private class TestPolicyRequirement : IPolicyRequirement
|
|
||||||
{
|
{
|
||||||
public Guid OrganizationId { get; init; }
|
var policyRepository = Substitute.For<IPolicyRepository>();
|
||||||
public static TestPolicyRequirement Create(IEnumerable<PolicyDetails> policyDetails)
|
policyRepository.GetPolicyDetailsByUserId(userId).Returns([]);
|
||||||
=> new() { OrganizationId = policyDetails.Single().OrganizationId };
|
|
||||||
|
var factory = new TestPolicyRequirementFactory(x => x.IsProvider);
|
||||||
|
var sut = new PolicyRequirementQuery(policyRepository, [factory]);
|
||||||
|
|
||||||
|
var requirement = await sut.GetAsync<TestPolicyRequirement>(userId);
|
||||||
|
|
||||||
|
Assert.Empty(requirement.Policies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
using AutoFixture.Xunit2;
|
||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Test.AdminConsole.AutoFixture;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
|
public class BasePolicyRequirementFactoryTests
|
||||||
|
{
|
||||||
|
[Theory, AutoData]
|
||||||
|
public void ExemptRoles_DoesNotEnforceAgainstThoseRoles(
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, OrganizationUserType.Owner)] PolicyDetails ownerPolicy,
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, OrganizationUserType.Admin)] PolicyDetails adminPolicy,
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, OrganizationUserType.Custom)] PolicyDetails customPolicy,
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg)] PolicyDetails userPolicy)
|
||||||
|
{
|
||||||
|
var sut = new TestPolicyRequirementFactory(
|
||||||
|
// These exempt roles are intentionally unusual to make sure we're properly testing the sut
|
||||||
|
[OrganizationUserType.User, OrganizationUserType.Custom],
|
||||||
|
[],
|
||||||
|
false);
|
||||||
|
|
||||||
|
Assert.True(sut.Enforce(ownerPolicy));
|
||||||
|
Assert.True(sut.Enforce(adminPolicy));
|
||||||
|
Assert.False(sut.Enforce(customPolicy));
|
||||||
|
Assert.False(sut.Enforce(userPolicy));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, AutoData]
|
||||||
|
public void ExemptStatuses_DoesNotEnforceAgainstThoseStatuses(
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, userStatus: OrganizationUserStatusType.Invited)] PolicyDetails invitedPolicy,
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, userStatus: OrganizationUserStatusType.Accepted)] PolicyDetails acceptedPolicy,
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, userStatus: OrganizationUserStatusType.Confirmed)] PolicyDetails confirmedPolicy,
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, userStatus: OrganizationUserStatusType.Revoked)] PolicyDetails revokedPolicy)
|
||||||
|
{
|
||||||
|
var sut = new TestPolicyRequirementFactory(
|
||||||
|
[],
|
||||||
|
// These exempt statuses are intentionally unusual to make sure we're properly testing the sut
|
||||||
|
[OrganizationUserStatusType.Confirmed, OrganizationUserStatusType.Accepted],
|
||||||
|
false);
|
||||||
|
|
||||||
|
Assert.True(sut.Enforce(invitedPolicy));
|
||||||
|
Assert.True(sut.Enforce(revokedPolicy));
|
||||||
|
Assert.False(sut.Enforce(confirmedPolicy));
|
||||||
|
Assert.False(sut.Enforce(acceptedPolicy));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, AutoData]
|
||||||
|
public void ExemptProviders_DoesNotEnforceAgainstProviders(
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, isProvider: true)] PolicyDetails policy)
|
||||||
|
{
|
||||||
|
var sut = new TestPolicyRequirementFactory(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
true);
|
||||||
|
|
||||||
|
Assert.False(sut.Enforce(policy));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, AutoData]
|
||||||
|
public void NoExemptions_EnforcesAgainstAdminsAndProviders(
|
||||||
|
[PolicyDetails(PolicyType.SingleOrg, OrganizationUserType.Owner, isProvider: true)] PolicyDetails policy)
|
||||||
|
{
|
||||||
|
var sut = new TestPolicyRequirementFactory(
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
false);
|
||||||
|
|
||||||
|
Assert.True(sut.Enforce(policy));
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TestPolicyRequirementFactory(
|
||||||
|
IEnumerable<OrganizationUserType> exemptRoles,
|
||||||
|
IEnumerable<OrganizationUserStatusType> exemptStatuses,
|
||||||
|
bool exemptProviders
|
||||||
|
) : BasePolicyRequirementFactory<TestPolicyRequirement>
|
||||||
|
{
|
||||||
|
public override PolicyType PolicyType => PolicyType.SingleOrg;
|
||||||
|
protected override IEnumerable<OrganizationUserType> ExemptRoles => exemptRoles;
|
||||||
|
protected override IEnumerable<OrganizationUserStatusType> ExemptStatuses => exemptStatuses;
|
||||||
|
|
||||||
|
protected override bool ExemptProviders => exemptProviders;
|
||||||
|
|
||||||
|
public override TestPolicyRequirement Create(IEnumerable<PolicyDetails> policyDetails)
|
||||||
|
=> new() { Policies = policyDetails };
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
using Bit.Core.Test.AdminConsole.AutoFixture;
|
||||||
|
using Bit.Test.Common.AutoFixture;
|
||||||
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
|
[SutProviderCustomize]
|
||||||
|
public class DisableSendPolicyRequirementFactoryTests
|
||||||
|
{
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public void DisableSend_IsFalse_IfNoPolicies(SutProvider<DisableSendPolicyRequirementFactory> sutProvider)
|
||||||
|
{
|
||||||
|
var actual = sutProvider.Sut.Create([]);
|
||||||
|
|
||||||
|
Assert.False(actual.DisableSend);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public void DisableSend_IsTrue_IfAnyDisableSendPolicies(
|
||||||
|
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails[] policies,
|
||||||
|
SutProvider<DisableSendPolicyRequirementFactory> sutProvider
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var actual = sutProvider.Sut.Create(policies);
|
||||||
|
|
||||||
|
Assert.True(actual.DisableSend);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
using Bit.Core.AdminConsole.Enums;
|
||||||
|
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||||
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
using Bit.Core.Test.AdminConsole.AutoFixture;
|
||||||
|
using Bit.Test.Common.AutoFixture;
|
||||||
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||||
|
|
||||||
|
[SutProviderCustomize]
|
||||||
|
public class SendOptionsPolicyRequirementFactoryTests
|
||||||
|
{
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public void DisableHideEmail_IsFalse_IfNoPolicies(SutProvider<SendOptionsPolicyRequirementFactory> sutProvider)
|
||||||
|
{
|
||||||
|
var actual = sutProvider.Sut.Create([]);
|
||||||
|
|
||||||
|
Assert.False(actual.DisableHideEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public void DisableHideEmail_IsFalse_IfNotConfigured(
|
||||||
|
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails[] policies,
|
||||||
|
SutProvider<SendOptionsPolicyRequirementFactory> sutProvider
|
||||||
|
)
|
||||||
|
{
|
||||||
|
policies[0].SetDataModel(new SendOptionsPolicyData { DisableHideEmail = false });
|
||||||
|
policies[1].SetDataModel(new SendOptionsPolicyData { DisableHideEmail = false });
|
||||||
|
|
||||||
|
var actual = sutProvider.Sut.Create(policies);
|
||||||
|
|
||||||
|
Assert.False(actual.DisableHideEmail);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public void DisableHideEmail_IsTrue_IfAnyConfigured(
|
||||||
|
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails[] policies,
|
||||||
|
SutProvider<SendOptionsPolicyRequirementFactory> sutProvider
|
||||||
|
)
|
||||||
|
{
|
||||||
|
policies[0].SetDataModel(new SendOptionsPolicyData { DisableHideEmail = true });
|
||||||
|
policies[1].SetDataModel(new SendOptionsPolicyData { DisableHideEmail = false });
|
||||||
|
|
||||||
|
var actual = sutProvider.Sut.Create(policies);
|
||||||
|
|
||||||
|
Assert.True(actual.DisableHideEmail);
|
||||||
|
}
|
||||||
|
}
|
@ -1,138 +0,0 @@
|
|||||||
using AutoFixture.Xunit2;
|
|
||||||
using Bit.Core.AdminConsole.Enums;
|
|
||||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Test.AdminConsole.AutoFixture;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
|
||||||
|
|
||||||
public class SendPolicyRequirementTests
|
|
||||||
{
|
|
||||||
[Theory, AutoData]
|
|
||||||
public void DisableSend_IsFalse_IfNoDisableSendPolicies(
|
|
||||||
[PolicyDetails(PolicyType.RequireSso)] PolicyDetails otherPolicy1,
|
|
||||||
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails otherPolicy2)
|
|
||||||
{
|
|
||||||
EnableDisableHideEmail(otherPolicy2);
|
|
||||||
|
|
||||||
var actual = SendPolicyRequirement.Create([otherPolicy1, otherPolicy2]);
|
|
||||||
|
|
||||||
Assert.False(actual.DisableSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineAutoData(OrganizationUserType.Owner, false)]
|
|
||||||
[InlineAutoData(OrganizationUserType.Admin, false)]
|
|
||||||
[InlineAutoData(OrganizationUserType.User, true)]
|
|
||||||
[InlineAutoData(OrganizationUserType.Custom, true)]
|
|
||||||
public void DisableSend_TestRoles(
|
|
||||||
OrganizationUserType userType,
|
|
||||||
bool shouldBeEnforced,
|
|
||||||
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails policyDetails)
|
|
||||||
{
|
|
||||||
policyDetails.OrganizationUserType = userType;
|
|
||||||
|
|
||||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
|
||||||
|
|
||||||
Assert.Equal(shouldBeEnforced, actual.DisableSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, AutoData]
|
|
||||||
public void DisableSend_Not_EnforcedAgainstProviders(
|
|
||||||
[PolicyDetails(PolicyType.DisableSend, isProvider: true)] PolicyDetails policyDetails)
|
|
||||||
{
|
|
||||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
|
||||||
|
|
||||||
Assert.False(actual.DisableSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineAutoData(OrganizationUserStatusType.Confirmed, true)]
|
|
||||||
[InlineAutoData(OrganizationUserStatusType.Accepted, true)]
|
|
||||||
[InlineAutoData(OrganizationUserStatusType.Invited, false)]
|
|
||||||
[InlineAutoData(OrganizationUserStatusType.Revoked, false)]
|
|
||||||
public void DisableSend_TestStatuses(
|
|
||||||
OrganizationUserStatusType userStatus,
|
|
||||||
bool shouldBeEnforced,
|
|
||||||
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails policyDetails)
|
|
||||||
{
|
|
||||||
policyDetails.OrganizationUserStatus = userStatus;
|
|
||||||
|
|
||||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
|
||||||
|
|
||||||
Assert.Equal(shouldBeEnforced, actual.DisableSend);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, AutoData]
|
|
||||||
public void DisableHideEmail_IsFalse_IfNoSendOptionsPolicies(
|
|
||||||
[PolicyDetails(PolicyType.RequireSso)] PolicyDetails otherPolicy1,
|
|
||||||
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails otherPolicy2)
|
|
||||||
{
|
|
||||||
var actual = SendPolicyRequirement.Create([otherPolicy1, otherPolicy2]);
|
|
||||||
|
|
||||||
Assert.False(actual.DisableHideEmail);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineAutoData(OrganizationUserType.Owner, false)]
|
|
||||||
[InlineAutoData(OrganizationUserType.Admin, false)]
|
|
||||||
[InlineAutoData(OrganizationUserType.User, true)]
|
|
||||||
[InlineAutoData(OrganizationUserType.Custom, true)]
|
|
||||||
public void DisableHideEmail_TestRoles(
|
|
||||||
OrganizationUserType userType,
|
|
||||||
bool shouldBeEnforced,
|
|
||||||
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
|
|
||||||
{
|
|
||||||
EnableDisableHideEmail(policyDetails);
|
|
||||||
policyDetails.OrganizationUserType = userType;
|
|
||||||
|
|
||||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
|
||||||
|
|
||||||
Assert.Equal(shouldBeEnforced, actual.DisableHideEmail);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, AutoData]
|
|
||||||
public void DisableHideEmail_Not_EnforcedAgainstProviders(
|
|
||||||
[PolicyDetails(PolicyType.SendOptions, isProvider: true)] PolicyDetails policyDetails)
|
|
||||||
{
|
|
||||||
EnableDisableHideEmail(policyDetails);
|
|
||||||
|
|
||||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
|
||||||
|
|
||||||
Assert.False(actual.DisableHideEmail);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[InlineAutoData(OrganizationUserStatusType.Confirmed, true)]
|
|
||||||
[InlineAutoData(OrganizationUserStatusType.Accepted, true)]
|
|
||||||
[InlineAutoData(OrganizationUserStatusType.Invited, false)]
|
|
||||||
[InlineAutoData(OrganizationUserStatusType.Revoked, false)]
|
|
||||||
public void DisableHideEmail_TestStatuses(
|
|
||||||
OrganizationUserStatusType userStatus,
|
|
||||||
bool shouldBeEnforced,
|
|
||||||
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
|
|
||||||
{
|
|
||||||
EnableDisableHideEmail(policyDetails);
|
|
||||||
policyDetails.OrganizationUserStatus = userStatus;
|
|
||||||
|
|
||||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
|
||||||
|
|
||||||
Assert.Equal(shouldBeEnforced, actual.DisableHideEmail);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, AutoData]
|
|
||||||
public void DisableHideEmail_HandlesNullData(
|
|
||||||
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
|
|
||||||
{
|
|
||||||
policyDetails.PolicyData = null;
|
|
||||||
|
|
||||||
var actual = SendPolicyRequirement.Create([policyDetails]);
|
|
||||||
|
|
||||||
Assert.False(actual.DisableHideEmail);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EnableDisableHideEmail(PolicyDetails policyDetails)
|
|
||||||
=> policyDetails.SetDataModel(new SendOptionsPolicyData { DisableHideEmail = true });
|
|
||||||
}
|
|
@ -123,10 +123,12 @@ public class SendServiceTests
|
|||||||
|
|
||||||
// Disable Send policy check - vNext
|
// Disable Send policy check - vNext
|
||||||
private void SaveSendAsync_Setup_vNext(SutProvider<SendService> sutProvider, Send send,
|
private void SaveSendAsync_Setup_vNext(SutProvider<SendService> sutProvider, Send send,
|
||||||
SendPolicyRequirement sendPolicyRequirement)
|
DisableSendPolicyRequirement disableSendPolicyRequirement, SendOptionsPolicyRequirement sendOptionsPolicyRequirement)
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<IPolicyRequirementQuery>().GetAsync<SendPolicyRequirement>(send.UserId!.Value)
|
sutProvider.GetDependency<IPolicyRequirementQuery>().GetAsync<DisableSendPolicyRequirement>(send.UserId!.Value)
|
||||||
.Returns(sendPolicyRequirement);
|
.Returns(disableSendPolicyRequirement);
|
||||||
|
sutProvider.GetDependency<IPolicyRequirementQuery>().GetAsync<SendOptionsPolicyRequirement>(send.UserId!.Value)
|
||||||
|
.Returns(sendOptionsPolicyRequirement);
|
||||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true);
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true);
|
||||||
|
|
||||||
// Should not be called in these tests
|
// Should not be called in these tests
|
||||||
@ -141,7 +143,7 @@ public class SendServiceTests
|
|||||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||||
{
|
{
|
||||||
send.Type = sendType;
|
send.Type = sendType;
|
||||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement { DisableSend = true });
|
SaveSendAsync_Setup_vNext(sutProvider, send, new DisableSendPolicyRequirement { DisableSend = true }, new SendOptionsPolicyRequirement());
|
||||||
|
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveSendAsync(send));
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveSendAsync(send));
|
||||||
Assert.Contains("Due to an Enterprise Policy, you are only able to delete an existing Send.",
|
Assert.Contains("Due to an Enterprise Policy, you are only able to delete an existing Send.",
|
||||||
@ -155,7 +157,7 @@ public class SendServiceTests
|
|||||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||||
{
|
{
|
||||||
send.Type = sendType;
|
send.Type = sendType;
|
||||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement());
|
SaveSendAsync_Setup_vNext(sutProvider, send, new DisableSendPolicyRequirement(), new SendOptionsPolicyRequirement());
|
||||||
|
|
||||||
await sutProvider.Sut.SaveSendAsync(send);
|
await sutProvider.Sut.SaveSendAsync(send);
|
||||||
|
|
||||||
@ -171,7 +173,7 @@ public class SendServiceTests
|
|||||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||||
{
|
{
|
||||||
send.Type = sendType;
|
send.Type = sendType;
|
||||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement { DisableHideEmail = true });
|
SaveSendAsync_Setup_vNext(sutProvider, send, new DisableSendPolicyRequirement(), new SendOptionsPolicyRequirement { DisableHideEmail = true });
|
||||||
send.HideEmail = true;
|
send.HideEmail = true;
|
||||||
|
|
||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveSendAsync(send));
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveSendAsync(send));
|
||||||
@ -185,7 +187,7 @@ public class SendServiceTests
|
|||||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||||
{
|
{
|
||||||
send.Type = sendType;
|
send.Type = sendType;
|
||||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement { DisableHideEmail = true });
|
SaveSendAsync_Setup_vNext(sutProvider, send, new DisableSendPolicyRequirement(), new SendOptionsPolicyRequirement { DisableHideEmail = true });
|
||||||
send.HideEmail = false;
|
send.HideEmail = false;
|
||||||
|
|
||||||
await sutProvider.Sut.SaveSendAsync(send);
|
await sutProvider.Sut.SaveSendAsync(send);
|
||||||
@ -200,7 +202,7 @@ public class SendServiceTests
|
|||||||
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
SutProvider<SendService> sutProvider, [NewUserSendCustomize] Send send)
|
||||||
{
|
{
|
||||||
send.Type = sendType;
|
send.Type = sendType;
|
||||||
SaveSendAsync_Setup_vNext(sutProvider, send, new SendPolicyRequirement());
|
SaveSendAsync_Setup_vNext(sutProvider, send, new DisableSendPolicyRequirement(), new SendOptionsPolicyRequirement());
|
||||||
send.HideEmail = true;
|
send.HideEmail = true;
|
||||||
|
|
||||||
await sutProvider.Sut.SaveSendAsync(send);
|
await sutProvider.Sut.SaveSendAsync(send);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user