1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-01 08:02:49 -05:00

Add disable send policy (#1130)

* Add Disable Send policy

* Test DisableSend policy

* PR Review

* Update tests for using CurrentContext

This required making an interface for CurrentContext and mocking out
the members used. The interface can be expanded as needed for tests.

I moved CurrentContext to a folder, which changes the namespace
and causes a lot of file touches, but most are just adding a reference

* Fix failing test

* Update exemption to include all exempt users

* Move all CurrentContext usages to ICurrentContext

* PR review. Match messaging with Web
This commit is contained in:
Matt Gibson
2021-02-04 12:54:21 -06:00
committed by GitHub
parent 19e7ce8519
commit edd4bc2623
60 changed files with 437 additions and 99 deletions

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using AutoFixture;
using AutoFixture.Kernel;
using Bit.Core.Context;
namespace Bit.Core.Test.AutoFixture.CurrentContextFixtures
{
internal class CurrentContext : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new CurrentContextBuilder());
}
}
internal class CurrentContextBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!(request is Type typeRequest))
{
return new NoSpecimen();
}
if (typeof(ICurrentContext) != typeRequest)
{
return new NoSpecimen();
}
var obj = new Fixture().WithAutoNSubstitutions().Create<ICurrentContext>();
obj.Organizations = context.Create<List<CurrentContentOrganization>>();
return obj;
}
}
}

View File

@ -0,0 +1,65 @@
using System;
using AutoFixture;
using Bit.Core.Models.Table;
using Bit.Core.Test.AutoFixture.Attributes;
namespace Bit.Core.Test.AutoFixture.SendFixtures
{
internal class OrganizationSend : ICustomization
{
public Guid? OrganizationId { get; set; }
public void Customize(IFixture fixture)
{
fixture.Customize<Send>(composer => composer
.With(s => s.OrganizationId, OrganizationId ?? Guid.NewGuid())
.Without(s => s.UserId));
}
}
internal class UserSend : ICustomization
{
public Guid? UserId { get; set; }
public void Customize(IFixture fixture)
{
fixture.Customize<Send>(composer => composer
.With(s => s.UserId, UserId ?? Guid.NewGuid())
.Without(s => s.OrganizationId));
}
}
internal class UserSendAutoDataAttribute : CustomAutoDataAttribute
{
public UserSendAutoDataAttribute(string userId = null) : base(new SutProviderCustomization(),
new UserSend { UserId = userId == null ? (Guid?)null : new Guid(userId) })
{ }
}
internal class InlineUserSendAutoDataAttribute : InlineCustomAutoDataAttribute
{
public InlineUserSendAutoDataAttribute(params object[] values) : base(new[] { typeof(CurrentContextFixtures.CurrentContext),
typeof(SutProviderCustomization), typeof(UserSend) }, values)
{ }
}
internal class InlineKnownUserSendAutoDataAttribute : InlineCustomAutoDataAttribute
{
public InlineKnownUserSendAutoDataAttribute(string userId, params object[] values) : base(new ICustomization[]
{ new CurrentContextFixtures.CurrentContext(), new SutProviderCustomization(),
new UserSend { UserId = new Guid(userId) } }, values)
{ }
}
internal class OrganizationSendAutoDataAttribute : CustomAutoDataAttribute
{
public OrganizationSendAutoDataAttribute(string organizationId = null) : base(new CurrentContextFixtures.CurrentContext(),
new SutProviderCustomization(),
new OrganizationSend { OrganizationId = organizationId == null ? (Guid?)null : new Guid(organizationId) })
{ }
}
internal class InlineOrganizationSendAutoDataAttribute : InlineCustomAutoDataAttribute
{
public InlineOrganizationSendAutoDataAttribute(params object[] values) : base(new[] { typeof(CurrentContextFixtures.CurrentContext),
typeof(SutProviderCustomization), typeof(OrganizationSend) }, values)
{ }
}
}

View File

@ -16,10 +16,12 @@ namespace Bit.Core.Test.AutoFixture
public TSut Sut { get; private set; }
public Type SutType => typeof(TSut);
public SutProvider()
public SutProvider() : this(new Fixture()) { }
public SutProvider(IFixture fixture)
{
_dependencies = new Dictionary<Type, Dictionary<string, object>>();
_fixture = new Fixture().WithAutoNSubstitutions();
_fixture = (fixture ?? new Fixture()).WithAutoNSubstitutions();
_constructorParameterRelay = new ConstructorParameterRelay<TSut>(this, _fixture);
_fixture.Customizations.Add(_constructorParameterRelay);
}

View File

@ -6,6 +6,8 @@ namespace Bit.Core.Test.AutoFixture
{
public class SutProviderCustomization : ICustomization, ISpecimenBuilder
{
private IFixture _fixture = null;
public object Create(object request, ISpecimenContext context)
{
if (context == null)
@ -21,11 +23,12 @@ namespace Bit.Core.Test.AutoFixture
return new NoSpecimen();
}
return ((ISutProvider)Activator.CreateInstance(typeRequest)).Create();
return ((ISutProvider)Activator.CreateInstance(typeRequest, _fixture)).Create();
}
public void Customize(IFixture fixture)
{
_fixture = fixture;
fixture.Customizations.Add(this);
}
}

View File

@ -1,4 +1,5 @@
using System;
using Bit.Core.Context;
using Bit.Core.Repositories;
using Bit.Core.Services;
using NSubstitute;

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.AutoFixture;
using Bit.Core.Test.AutoFixture.SendFixtures;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Services
{
public class SendServiceTests
{
private void SaveSendAsync_Setup(SendType sendType, bool canManagePolicies,
SutProvider<SendService> sutProvider, Send send, List<Policy> policies)
{
send.Id = default;
send.Type = sendType;
policies.First().Type = PolicyType.DisableSend;
policies.First().Enabled = true;
sutProvider.GetDependency<IPolicyRepository>().GetManyByUserIdAsync(send.UserId.Value).Returns(policies);
sutProvider.GetDependency<ICurrentContext>().ManagePolicies(Arg.Any<Guid>()).Returns(canManagePolicies);
}
[Theory]
[InlineUserSendAutoData(SendType.File)]
[InlineUserSendAutoData(SendType.Text)]
public async void SaveSendAsync_DisableSend_CantManagePolicies_throws(SendType sendType,
SutProvider<SendService> sutProvider, Send send, List<Policy> policies)
{
SaveSendAsync_Setup(sendType, canManagePolicies: false, sutProvider, send, policies);
await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SaveSendAsync(send));
}
[Theory]
[InlineUserSendAutoData(SendType.File)]
[InlineUserSendAutoData(SendType.Text)]
public async void SaveSendAsync_DisableSend_DisabledPolicy_CantManagePolicies_success(SendType sendType,
SutProvider<SendService> sutProvider, Send send, List<Policy> policies)
{
SaveSendAsync_Setup(sendType, canManagePolicies: false, sutProvider, send, policies);
foreach (var policy in policies.Where(p => p.Type == PolicyType.DisableSend))
{
policy.Enabled = false;
}
await sutProvider.Sut.SaveSendAsync(send);
await sutProvider.GetDependency<ISendRepository>().Received(1).CreateAsync(send);
}
[Theory]
[InlineUserSendAutoData(SendType.File)]
[InlineUserSendAutoData(SendType.Text)]
public async void SaveSendAsync_DisableSend_CanManagePolicies_success(SendType sendType,
SutProvider<SendService> sutProvider, Send send, List<Policy> policies)
{
SaveSendAsync_Setup(sendType, canManagePolicies: true, sutProvider, send, policies);
await sutProvider.Sut.SaveSendAsync(send);
await sutProvider.GetDependency<ISendRepository>().Received(1).CreateAsync(send);
}
}
}

View File

@ -9,6 +9,7 @@ using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
using Bit.Core.Context;
namespace Bit.Core.Test.Services
{