mirror of
https://github.com/bitwarden/server
synced 2026-01-20 09:23:28 +00:00
Merge remote-tracking branch 'origin/main' into xunit-v3-full-upgrade
This commit is contained in:
@@ -2,15 +2,14 @@
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrations.Interfaces;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ReturnsExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
@@ -19,7 +18,7 @@ namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationIntegrationControllerTests
|
||||
{
|
||||
private OrganizationIntegrationRequestModel _webhookRequestModel = new OrganizationIntegrationRequestModel()
|
||||
private readonly OrganizationIntegrationRequestModel _webhookRequestModel = new()
|
||||
{
|
||||
Configuration = null,
|
||||
Type = IntegrationType.Webhook
|
||||
@@ -48,13 +47,13 @@ public class OrganizationIntegrationControllerTests
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
sutProvider.GetDependency<IGetOrganizationIntegrationsQuery>()
|
||||
.GetManyByOrganizationAsync(organizationId)
|
||||
.Returns(integrations);
|
||||
|
||||
var result = await sutProvider.Sut.GetAsync(organizationId);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
await sutProvider.GetDependency<IGetOrganizationIntegrationsQuery>().Received(1)
|
||||
.GetManyByOrganizationAsync(organizationId);
|
||||
|
||||
Assert.Equal(integrations.Count, result.Count);
|
||||
@@ -70,7 +69,7 @@ public class OrganizationIntegrationControllerTests
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
sutProvider.GetDependency<IGetOrganizationIntegrationsQuery>()
|
||||
.GetManyByOrganizationAsync(organizationId)
|
||||
.Returns([]);
|
||||
|
||||
@@ -80,199 +79,133 @@ public class OrganizationIntegrationControllerTests
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task CreateAsync_Webhook_AllParamsProvided_Succeeds(
|
||||
public async Task CreateAsync_AllParamsProvided_Succeeds(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration integration)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<ICreateOrganizationIntegrationCommand>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegration>())
|
||||
.Returns(integration);
|
||||
|
||||
var response = await sutProvider.Sut.CreateAsync(organizationId, _webhookRequestModel);
|
||||
|
||||
await sutProvider.GetDependency<ICreateOrganizationIntegrationCommand>().Received(1)
|
||||
.CreateAsync(Arg.Is<OrganizationIntegration>(i =>
|
||||
i.OrganizationId == organizationId &&
|
||||
i.Type == IntegrationType.Webhook));
|
||||
Assert.IsType<OrganizationIntegrationResponseModel>(response);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task CreateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegration>())
|
||||
.Returns(callInfo => callInfo.Arg<OrganizationIntegration>());
|
||||
var response = await sutProvider.Sut.CreateAsync(organizationId, _webhookRequestModel);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.CreateAsync(Arg.Any<OrganizationIntegration>());
|
||||
Assert.IsType<OrganizationIntegrationResponseModel>(response);
|
||||
Assert.Equal(IntegrationType.Webhook, response.Type);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task CreateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(SutProvider<OrganizationIntegrationController> sutProvider, Guid organizationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.CreateAsync(organizationId, _webhookRequestModel));
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||
await sutProvider.Sut.CreateAsync(organizationId, _webhookRequestModel));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_AllParamsProvided_Succeeds(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
Guid integrationId)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
|
||||
await sutProvider.Sut.DeleteAsync(organizationId, organizationIntegration.Id);
|
||||
await sutProvider.Sut.DeleteAsync(organizationId, integrationId);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.DeleteAsync(organizationIntegration);
|
||||
await sutProvider.GetDependency<IDeleteOrganizationIntegrationCommand>().Received(1)
|
||||
.DeleteAsync(organizationId, integrationId);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
[Obsolete("Obsolete")]
|
||||
public async Task PostDeleteAsync_AllParamsProvided_Succeeds(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
|
||||
await sutProvider.Sut.PostDeleteAsync(organizationId, organizationIntegration.Id);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.DeleteAsync(organizationIntegration);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_IntegrationDoesNotBelongToOrganization_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
{
|
||||
organizationIntegration.OrganizationId = Guid.NewGuid();
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.DeleteAsync(organizationId, Guid.Empty));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_IntegrationDoesNotExist_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId)
|
||||
Guid integrationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.DeleteAsync(organizationId, Guid.Empty));
|
||||
await sutProvider.Sut.PostDeleteAsync(organizationId, integrationId);
|
||||
|
||||
await sutProvider.GetDependency<IDeleteOrganizationIntegrationCommand>().Received(1)
|
||||
.DeleteAsync(organizationId, integrationId);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId)
|
||||
Guid organizationId,
|
||||
Guid integrationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.DeleteAsync(organizationId, Guid.Empty));
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||
await sutProvider.Sut.DeleteAsync(organizationId, integrationId));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_AllParamsProvided_Succeeds(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
Guid integrationId,
|
||||
OrganizationIntegration integration)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.Webhook;
|
||||
integration.OrganizationId = organizationId;
|
||||
integration.Id = integrationId;
|
||||
integration.Type = IntegrationType.Webhook;
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IUpdateOrganizationIntegrationCommand>()
|
||||
.UpdateAsync(organizationId, integrationId, Arg.Any<OrganizationIntegration>())
|
||||
.Returns(integration);
|
||||
|
||||
var response = await sutProvider.Sut.UpdateAsync(organizationId, organizationIntegration.Id, _webhookRequestModel);
|
||||
var response = await sutProvider.Sut.UpdateAsync(organizationId, integrationId, _webhookRequestModel);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.ReplaceAsync(organizationIntegration);
|
||||
await sutProvider.GetDependency<IUpdateOrganizationIntegrationCommand>().Received(1)
|
||||
.UpdateAsync(organizationId, integrationId, Arg.Is<OrganizationIntegration>(i =>
|
||||
i.OrganizationId == organizationId &&
|
||||
i.Type == IntegrationType.Webhook));
|
||||
Assert.IsType<OrganizationIntegrationResponseModel>(response);
|
||||
Assert.Equal(IntegrationType.Webhook, response.Type);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_IntegrationDoesNotBelongToOrganization_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
{
|
||||
organizationIntegration.OrganizationId = Guid.NewGuid();
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.UpdateAsync(organizationId, Guid.Empty, _webhookRequestModel));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_IntegrationDoesNotExist_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.UpdateAsync(organizationId, Guid.Empty, _webhookRequestModel));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationController> sutProvider,
|
||||
Guid organizationId)
|
||||
Guid organizationId,
|
||||
Guid integrationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.UpdateAsync(organizationId, Guid.Empty, _webhookRequestModel));
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||
await sutProvider.Sut.UpdateAsync(organizationId, integrationId, _webhookRequestModel));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Core.AdminConsole.EventIntegrations.OrganizationIntegrationConfigurations.Interfaces;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ReturnsExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
@@ -25,823 +21,191 @@ public class OrganizationIntegrationsConfigurationControllerTests
|
||||
public async Task DeleteAsync_AllParamsProvided_Succeeds(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration)
|
||||
Guid integrationId,
|
||||
Guid configurationId)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegrationConfiguration.OrganizationIntegrationId = organizationIntegration.Id;
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await sutProvider.Sut.DeleteAsync(organizationId, organizationIntegration.Id, organizationIntegrationConfiguration.Id);
|
||||
await sutProvider.Sut.DeleteAsync(organizationId, integrationId, configurationId);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegrationConfiguration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.DeleteAsync(organizationIntegrationConfiguration);
|
||||
await sutProvider.GetDependency<IDeleteOrganizationIntegrationConfigurationCommand>().Received(1)
|
||||
.DeleteAsync(organizationId, integrationId, configurationId);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
[Obsolete("Obsolete")]
|
||||
public async Task PostDeleteAsync_AllParamsProvided_Succeeds(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegrationConfiguration.OrganizationIntegrationId = organizationIntegration.Id;
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await sutProvider.Sut.PostDeleteAsync(organizationId, organizationIntegration.Id, organizationIntegrationConfiguration.Id);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegrationConfiguration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.DeleteAsync(organizationIntegrationConfiguration);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_IntegrationConfigurationDoesNotExist_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.DeleteAsync(organizationId, Guid.Empty, Guid.Empty));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_IntegrationDoesNotExist_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId)
|
||||
Guid integrationId,
|
||||
Guid configurationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.DeleteAsync(organizationId, Guid.Empty, Guid.Empty));
|
||||
}
|
||||
await sutProvider.Sut.PostDeleteAsync(organizationId, integrationId, configurationId);
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_IntegrationDoesNotBelongToOrganization_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.DeleteAsync(organizationId, organizationIntegration.Id, Guid.Empty));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_IntegrationConfigDoesNotBelongToIntegration_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegrationConfiguration.OrganizationIntegrationId = Guid.Empty;
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.DeleteAsync(organizationId, organizationIntegration.Id, Guid.Empty));
|
||||
await sutProvider.GetDependency<IDeleteOrganizationIntegrationConfigurationCommand>().Received(1)
|
||||
.DeleteAsync(organizationId, integrationId, configurationId);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task DeleteAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId)
|
||||
Guid organizationId,
|
||||
Guid integrationId,
|
||||
Guid configurationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.DeleteAsync(organizationId, Guid.Empty, Guid.Empty));
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||
await sutProvider.Sut.DeleteAsync(organizationId, integrationId, configurationId));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetAsync_ConfigurationsExist_Succeeds(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
List<OrganizationIntegrationConfiguration> organizationIntegrationConfigurations)
|
||||
Guid integrationId,
|
||||
List<OrganizationIntegrationConfiguration> configurations)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetManyByIntegrationAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfigurations);
|
||||
sutProvider.GetDependency<IGetOrganizationIntegrationConfigurationsQuery>()
|
||||
.GetManyByIntegrationAsync(organizationId, integrationId)
|
||||
.Returns(configurations);
|
||||
|
||||
var result = await sutProvider.Sut.GetAsync(organizationId, integrationId);
|
||||
|
||||
var result = await sutProvider.Sut.GetAsync(organizationId, organizationIntegration.Id);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(organizationIntegrationConfigurations.Count, result.Count);
|
||||
Assert.Equal(configurations.Count, result.Count);
|
||||
Assert.All(result, r => Assert.IsType<OrganizationIntegrationConfigurationResponseModel>(r));
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.GetManyByIntegrationAsync(organizationIntegration.Id);
|
||||
await sutProvider.GetDependency<IGetOrganizationIntegrationConfigurationsQuery>().Received(1)
|
||||
.GetManyByIntegrationAsync(organizationId, integrationId);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetAsync_NoConfigurationsExist_ReturnsEmptyList(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
Guid integrationId)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetManyByIntegrationAsync(Arg.Any<Guid>())
|
||||
sutProvider.GetDependency<IGetOrganizationIntegrationConfigurationsQuery>()
|
||||
.GetManyByIntegrationAsync(organizationId, integrationId)
|
||||
.Returns([]);
|
||||
|
||||
var result = await sutProvider.Sut.GetAsync(organizationId, organizationIntegration.Id);
|
||||
var result = await sutProvider.Sut.GetAsync(organizationId, integrationId);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Empty(result);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationRepository>().Received(1)
|
||||
.GetByIdAsync(organizationIntegration.Id);
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.GetManyByIntegrationAsync(organizationIntegration.Id);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetAsync_IntegrationDoesNotExist_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.GetAsync(organizationId, Guid.NewGuid()));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetAsync_IntegrationDoesNotBelongToOrganization_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.GetAsync(organizationId, organizationIntegration.Id));
|
||||
await sutProvider.GetDependency<IGetOrganizationIntegrationConfigurationsQuery>().Received(1)
|
||||
.GetManyByIntegrationAsync(organizationId, integrationId);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId)
|
||||
Guid organizationId,
|
||||
Guid integrationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.GetAsync(organizationId, Guid.NewGuid()));
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||
await sutProvider.Sut.GetAsync(organizationId, integrationId));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_AllParamsProvided_Slack_Succeeds(
|
||||
public async Task PostAsync_AllParamsProvided_Succeeds(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
Guid integrationId,
|
||||
OrganizationIntegrationConfiguration configuration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.Slack;
|
||||
var slackConfig = new SlackIntegrationConfiguration(ChannelId: "C123456");
|
||||
model.Configuration = JsonSerializer.Serialize(slackConfig);
|
||||
model.Template = "Template String";
|
||||
model.Filters = null;
|
||||
|
||||
var expected = new OrganizationIntegrationConfigurationResponseModel(organizationIntegrationConfiguration);
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
var createResponse = await sutProvider.Sut.CreateAsync(organizationId, organizationIntegration.Id, model);
|
||||
sutProvider.GetDependency<ICreateOrganizationIntegrationConfigurationCommand>()
|
||||
.CreateAsync(organizationId, integrationId, Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(configuration);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>());
|
||||
var createResponse = await sutProvider.Sut.CreateAsync(organizationId, integrationId, model);
|
||||
|
||||
await sutProvider.GetDependency<ICreateOrganizationIntegrationConfigurationCommand>().Received(1)
|
||||
.CreateAsync(organizationId, integrationId, Arg.Any<OrganizationIntegrationConfiguration>());
|
||||
Assert.IsType<OrganizationIntegrationConfigurationResponseModel>(createResponse);
|
||||
Assert.Equal(expected.Id, createResponse.Id);
|
||||
Assert.Equal(expected.Configuration, createResponse.Configuration);
|
||||
Assert.Equal(expected.EventType, createResponse.EventType);
|
||||
Assert.Equal(expected.Filters, createResponse.Filters);
|
||||
Assert.Equal(expected.Template, createResponse.Template);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_AllParamsProvided_Webhook_Succeeds(
|
||||
public async Task PostAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.Webhook;
|
||||
var webhookConfig = new WebhookIntegrationConfiguration(Uri: new Uri("https://localhost"), Scheme: "Bearer", Token: "AUTH-TOKEN");
|
||||
model.Configuration = JsonSerializer.Serialize(webhookConfig);
|
||||
model.Template = "Template String";
|
||||
model.Filters = null;
|
||||
|
||||
var expected = new OrganizationIntegrationConfigurationResponseModel(organizationIntegrationConfiguration);
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
var createResponse = await sutProvider.Sut.CreateAsync(organizationId, organizationIntegration.Id, model);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>());
|
||||
Assert.IsType<OrganizationIntegrationConfigurationResponseModel>(createResponse);
|
||||
Assert.Equal(expected.Id, createResponse.Id);
|
||||
Assert.Equal(expected.Configuration, createResponse.Configuration);
|
||||
Assert.Equal(expected.EventType, createResponse.EventType);
|
||||
Assert.Equal(expected.Filters, createResponse.Filters);
|
||||
Assert.Equal(expected.Template, createResponse.Template);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_OnlyUrlProvided_Webhook_Succeeds(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.Webhook;
|
||||
var webhookConfig = new WebhookIntegrationConfiguration(Uri: new Uri("https://localhost"));
|
||||
model.Configuration = JsonSerializer.Serialize(webhookConfig);
|
||||
model.Template = "Template String";
|
||||
model.Filters = null;
|
||||
|
||||
var expected = new OrganizationIntegrationConfigurationResponseModel(organizationIntegrationConfiguration);
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
var createResponse = await sutProvider.Sut.CreateAsync(organizationId, organizationIntegration.Id, model);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>());
|
||||
Assert.IsType<OrganizationIntegrationConfigurationResponseModel>(createResponse);
|
||||
Assert.Equal(expected.Id, createResponse.Id);
|
||||
Assert.Equal(expected.Configuration, createResponse.Configuration);
|
||||
Assert.Equal(expected.EventType, createResponse.EventType);
|
||||
Assert.Equal(expected.Filters, createResponse.Filters);
|
||||
Assert.Equal(expected.Template, createResponse.Template);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_IntegrationTypeCloudBillingSync_ThrowsBadRequestException(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.CloudBillingSync;
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(async () => await sutProvider.Sut.CreateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
model));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_IntegrationTypeScim_ThrowsBadRequestException(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.Scim;
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(async () => await sutProvider.Sut.CreateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
model));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_IntegrationDoesNotExist_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.CreateAsync(
|
||||
organizationId,
|
||||
Guid.Empty,
|
||||
new OrganizationIntegrationConfigurationRequestModel()));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_IntegrationDoesNotBelongToOrganization_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.CreateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
new OrganizationIntegrationConfigurationRequestModel()));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_InvalidConfiguration_ThrowsBadRequestException(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.Webhook;
|
||||
model.Configuration = null;
|
||||
model.Template = "Template String";
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(async () => await sutProvider.Sut.CreateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
model));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_InvalidTemplate_ThrowsBadRequestException(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.Webhook;
|
||||
var webhookConfig = new WebhookIntegrationConfiguration(Uri: new Uri("https://localhost"), Scheme: "Bearer", Token: "AUTH-TOKEN");
|
||||
model.Configuration = JsonSerializer.Serialize(webhookConfig);
|
||||
model.Template = null;
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.CreateAsync(Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(async () => await sutProvider.Sut.CreateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
model));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(SutProvider<OrganizationIntegrationConfigurationController> sutProvider, Guid organizationId)
|
||||
Guid integrationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.CreateAsync(organizationId, Guid.Empty, new OrganizationIntegrationConfigurationRequestModel()));
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||
await sutProvider.Sut.CreateAsync(organizationId, integrationId, new OrganizationIntegrationConfigurationRequestModel()));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_AllParamsProvided_Slack_Succeeds(
|
||||
public async Task UpdateAsync_AllParamsProvided_Succeeds(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
Guid integrationId,
|
||||
Guid configurationId,
|
||||
OrganizationIntegrationConfiguration configuration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegrationConfiguration.OrganizationIntegrationId = organizationIntegration.Id;
|
||||
organizationIntegration.Type = IntegrationType.Slack;
|
||||
var slackConfig = new SlackIntegrationConfiguration(ChannelId: "C123456");
|
||||
model.Configuration = JsonSerializer.Serialize(slackConfig);
|
||||
model.Template = "Template String";
|
||||
model.Filters = null;
|
||||
|
||||
var expected = new OrganizationIntegrationConfigurationResponseModel(model.ToOrganizationIntegrationConfiguration(organizationIntegrationConfiguration));
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
var updateResponse = await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
organizationIntegrationConfiguration.Id,
|
||||
model);
|
||||
sutProvider.GetDependency<IUpdateOrganizationIntegrationConfigurationCommand>()
|
||||
.UpdateAsync(organizationId, integrationId, configurationId, Arg.Any<OrganizationIntegrationConfiguration>())
|
||||
.Returns(configuration);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.ReplaceAsync(Arg.Any<OrganizationIntegrationConfiguration>());
|
||||
var updateResponse = await sutProvider.Sut.UpdateAsync(organizationId, integrationId, configurationId, model);
|
||||
|
||||
await sutProvider.GetDependency<IUpdateOrganizationIntegrationConfigurationCommand>().Received(1)
|
||||
.UpdateAsync(organizationId, integrationId, configurationId, Arg.Any<OrganizationIntegrationConfiguration>());
|
||||
Assert.IsType<OrganizationIntegrationConfigurationResponseModel>(updateResponse);
|
||||
Assert.Equal(expected.Id, updateResponse.Id);
|
||||
Assert.Equal(expected.Configuration, updateResponse.Configuration);
|
||||
Assert.Equal(expected.EventType, updateResponse.EventType);
|
||||
Assert.Equal(expected.Filters, updateResponse.Filters);
|
||||
Assert.Equal(expected.Template, updateResponse.Template);
|
||||
}
|
||||
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_AllParamsProvided_Webhook_Succeeds(
|
||||
public async Task UpdateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegrationConfiguration.OrganizationIntegrationId = organizationIntegration.Id;
|
||||
organizationIntegration.Type = IntegrationType.Webhook;
|
||||
var webhookConfig = new WebhookIntegrationConfiguration(Uri: new Uri("https://localhost"), Scheme: "Bearer", Token: "AUTH-TOKEN");
|
||||
model.Configuration = JsonSerializer.Serialize(webhookConfig);
|
||||
model.Template = "Template String";
|
||||
model.Filters = null;
|
||||
|
||||
var expected = new OrganizationIntegrationConfigurationResponseModel(model.ToOrganizationIntegrationConfiguration(organizationIntegrationConfiguration));
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
var updateResponse = await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
organizationIntegrationConfiguration.Id,
|
||||
model);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.ReplaceAsync(Arg.Any<OrganizationIntegrationConfiguration>());
|
||||
Assert.IsType<OrganizationIntegrationConfigurationResponseModel>(updateResponse);
|
||||
Assert.Equal(expected.Id, updateResponse.Id);
|
||||
Assert.Equal(expected.Configuration, updateResponse.Configuration);
|
||||
Assert.Equal(expected.EventType, updateResponse.EventType);
|
||||
Assert.Equal(expected.Filters, updateResponse.Filters);
|
||||
Assert.Equal(expected.Template, updateResponse.Template);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_OnlyUrlProvided_Webhook_Succeeds(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegrationConfiguration.OrganizationIntegrationId = organizationIntegration.Id;
|
||||
organizationIntegration.Type = IntegrationType.Webhook;
|
||||
var webhookConfig = new WebhookIntegrationConfiguration(Uri: new Uri("https://localhost"));
|
||||
model.Configuration = JsonSerializer.Serialize(webhookConfig);
|
||||
model.Template = "Template String";
|
||||
model.Filters = null;
|
||||
|
||||
var expected = new OrganizationIntegrationConfigurationResponseModel(model.ToOrganizationIntegrationConfiguration(organizationIntegrationConfiguration));
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
var updateResponse = await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
organizationIntegrationConfiguration.Id,
|
||||
model);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().Received(1)
|
||||
.ReplaceAsync(Arg.Any<OrganizationIntegrationConfiguration>());
|
||||
Assert.IsType<OrganizationIntegrationConfigurationResponseModel>(updateResponse);
|
||||
Assert.Equal(expected.Id, updateResponse.Id);
|
||||
Assert.Equal(expected.Configuration, updateResponse.Configuration);
|
||||
Assert.Equal(expected.EventType, updateResponse.EventType);
|
||||
Assert.Equal(expected.Filters, updateResponse.Filters);
|
||||
Assert.Equal(expected.Template, updateResponse.Template);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_IntegrationConfigurationDoesNotExist_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegration.Type = IntegrationType.Webhook;
|
||||
var webhookConfig = new WebhookIntegrationConfiguration(Uri: new Uri("https://localhost"), Scheme: "Bearer", Token: "AUTH-TOKEN");
|
||||
model.Configuration = JsonSerializer.Serialize(webhookConfig);
|
||||
model.Template = "Template String";
|
||||
model.Filters = null;
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
Guid.Empty,
|
||||
model));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_IntegrationDoesNotExist_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
Guid.Empty,
|
||||
Guid.Empty,
|
||||
new OrganizationIntegrationConfigurationRequestModel()));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_IntegrationDoesNotBelongToOrganization_ThrowsNotFound(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
Guid.Empty,
|
||||
new OrganizationIntegrationConfigurationRequestModel()));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_InvalidConfiguration_ThrowsBadRequestException(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegrationConfiguration.OrganizationIntegrationId = organizationIntegration.Id;
|
||||
organizationIntegration.Type = IntegrationType.Slack;
|
||||
model.Configuration = null;
|
||||
model.Template = "Template String";
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(async () => await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
organizationIntegrationConfiguration.Id,
|
||||
model));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_InvalidTemplate_ThrowsBadRequestException(
|
||||
SutProvider<OrganizationIntegrationConfigurationController> sutProvider,
|
||||
Guid organizationId,
|
||||
OrganizationIntegration organizationIntegration,
|
||||
OrganizationIntegrationConfiguration organizationIntegrationConfiguration,
|
||||
OrganizationIntegrationConfigurationRequestModel model)
|
||||
{
|
||||
organizationIntegration.OrganizationId = organizationId;
|
||||
organizationIntegrationConfiguration.OrganizationIntegrationId = organizationIntegration.Id;
|
||||
organizationIntegration.Type = IntegrationType.Slack;
|
||||
var slackConfig = new SlackIntegrationConfiguration(ChannelId: "C123456");
|
||||
model.Configuration = JsonSerializer.Serialize(slackConfig);
|
||||
model.Template = null;
|
||||
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegration);
|
||||
sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>()
|
||||
.GetByIdAsync(Arg.Any<Guid>())
|
||||
.Returns(organizationIntegrationConfiguration);
|
||||
|
||||
await Assert.ThrowsAsync<BadRequestException>(async () => await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
organizationIntegration.Id,
|
||||
organizationIntegrationConfiguration.Id,
|
||||
model));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(SutProvider<OrganizationIntegrationConfigurationController> sutProvider, Guid organizationId)
|
||||
Guid integrationId,
|
||||
Guid configurationId)
|
||||
{
|
||||
sutProvider.Sut.Url = Substitute.For<IUrlHelper>();
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(organizationId)
|
||||
.Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () => await sutProvider.Sut.UpdateAsync(
|
||||
organizationId,
|
||||
Guid.Empty,
|
||||
Guid.Empty,
|
||||
new OrganizationIntegrationConfigurationRequestModel()));
|
||||
await Assert.ThrowsAsync<NotFoundException>(async () =>
|
||||
await sutProvider.Sut.UpdateAsync(organizationId, integrationId, configurationId, new OrganizationIntegrationConfigurationRequestModel()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.AccountRecovery;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
@@ -452,60 +453,10 @@ public class OrganizationUsersControllerTests
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutResetPassword_WithFeatureFlagDisabled_CallsLegacyPath(
|
||||
public async Task PutResetPassword_WhenOrganizationUserNotFound_ReturnsNotFound(
|
||||
Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(false);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(orgId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().AdminResetPasswordAsync(Arg.Any<OrganizationUserType>(), orgId, orgUserId, model.NewMasterPasswordHash, model.Key)
|
||||
.Returns(Microsoft.AspNetCore.Identity.IdentityResult.Success);
|
||||
|
||||
var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model);
|
||||
|
||||
Assert.IsType<Ok>(result);
|
||||
await sutProvider.GetDependency<IUserService>().Received(1)
|
||||
.AdminResetPasswordAsync(OrganizationUserType.Owner, orgId, orgUserId, model.NewMasterPasswordHash, model.Key);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutResetPassword_WithFeatureFlagDisabled_WhenOrgUserTypeIsNull_ReturnsNotFound(
|
||||
Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(false);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(orgId).Returns(false);
|
||||
sutProvider.GetDependency<ICurrentContext>().Organizations.Returns(new List<CurrentContextOrganization>());
|
||||
|
||||
var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model);
|
||||
|
||||
Assert.IsType<Microsoft.AspNetCore.Http.HttpResults.NotFound>(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutResetPassword_WithFeatureFlagDisabled_WhenAdminResetPasswordFails_ReturnsBadRequest(
|
||||
Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(false);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(orgId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().AdminResetPasswordAsync(Arg.Any<OrganizationUserType>(), orgId, orgUserId, model.NewMasterPasswordHash, model.Key)
|
||||
.Returns(Microsoft.AspNetCore.Identity.IdentityResult.Failed(new Microsoft.AspNetCore.Identity.IdentityError { Description = "Error 1" }));
|
||||
|
||||
var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model);
|
||||
|
||||
Assert.IsType<BadRequest<ModelStateDictionary>>(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutResetPassword_WithFeatureFlagEnabled_WhenOrganizationUserNotFound_ReturnsNotFound(
|
||||
Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(orgUserId).Returns((OrganizationUser)null);
|
||||
|
||||
var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model);
|
||||
@@ -515,12 +466,11 @@ public class OrganizationUsersControllerTests
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutResetPassword_WithFeatureFlagEnabled_WhenOrganizationIdMismatch_ReturnsNotFound(
|
||||
public async Task PutResetPassword_WhenOrganizationIdMismatch_ReturnsNotFound(
|
||||
Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, OrganizationUser organizationUser,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
organizationUser.OrganizationId = Guid.NewGuid();
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(orgUserId).Returns(organizationUser);
|
||||
|
||||
var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model);
|
||||
@@ -530,12 +480,11 @@ public class OrganizationUsersControllerTests
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutResetPassword_WithFeatureFlagEnabled_WhenAuthorizationFails_ReturnsBadRequest(
|
||||
public async Task PutResetPassword_WhenAuthorizationFails_ReturnsBadRequest(
|
||||
Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, OrganizationUser organizationUser,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
organizationUser.OrganizationId = orgId;
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(orgUserId).Returns(organizationUser);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(
|
||||
@@ -551,12 +500,11 @@ public class OrganizationUsersControllerTests
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutResetPassword_WithFeatureFlagEnabled_WhenRecoverAccountSucceeds_ReturnsOk(
|
||||
public async Task PutResetPassword_WhenRecoverAccountSucceeds_ReturnsOk(
|
||||
Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, OrganizationUser organizationUser,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
organizationUser.OrganizationId = orgId;
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(orgUserId).Returns(organizationUser);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(
|
||||
@@ -577,12 +525,11 @@ public class OrganizationUsersControllerTests
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutResetPassword_WithFeatureFlagEnabled_WhenRecoverAccountFails_ReturnsBadRequest(
|
||||
public async Task PutResetPassword_WhenRecoverAccountFails_ReturnsBadRequest(
|
||||
Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, OrganizationUser organizationUser,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
organizationUser.OrganizationId = orgId;
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(orgUserId).Returns(organizationUser);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(
|
||||
@@ -784,4 +731,68 @@ public class OrganizationUsersControllerTests
|
||||
var problemResult = Assert.IsType<JsonHttpResult<ErrorResponseModel>>(result);
|
||||
Assert.Equal(StatusCodes.Status500InternalServerError, problemResult.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task BulkReinvite_WhenFeatureFlagEnabled_UsesBulkResendOrganizationInvitesCommand(
|
||||
Guid organizationId,
|
||||
OrganizationUserBulkRequestModel bulkRequestModel,
|
||||
List<OrganizationUser> organizationUsers,
|
||||
Guid userId,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageUsers(organizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.IncreaseBulkReinviteLimitForCloud)
|
||||
.Returns(true);
|
||||
|
||||
var expectedResults = organizationUsers.Select(u => Tuple.Create(u, "")).ToList();
|
||||
sutProvider.GetDependency<IBulkResendOrganizationInvitesCommand>()
|
||||
.BulkResendInvitesAsync(organizationId, userId, bulkRequestModel.Ids)
|
||||
.Returns(expectedResults);
|
||||
|
||||
// Act
|
||||
var response = await sutProvider.Sut.BulkReinvite(organizationId, bulkRequestModel);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(organizationUsers.Count, response.Data.Count());
|
||||
|
||||
await sutProvider.GetDependency<IBulkResendOrganizationInvitesCommand>()
|
||||
.Received(1)
|
||||
.BulkResendInvitesAsync(organizationId, userId, bulkRequestModel.Ids);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task BulkReinvite_WhenFeatureFlagDisabled_UsesLegacyOrganizationService(
|
||||
Guid organizationId,
|
||||
OrganizationUserBulkRequestModel bulkRequestModel,
|
||||
List<OrganizationUser> organizationUsers,
|
||||
Guid userId,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<ICurrentContext>().ManageUsers(organizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.IncreaseBulkReinviteLimitForCloud)
|
||||
.Returns(false);
|
||||
|
||||
var expectedResults = organizationUsers.Select(u => Tuple.Create(u, "")).ToList();
|
||||
sutProvider.GetDependency<IOrganizationService>()
|
||||
.ResendInvitesAsync(organizationId, userId, bulkRequestModel.Ids)
|
||||
.Returns(expectedResults);
|
||||
|
||||
// Act
|
||||
var response = await sutProvider.Sut.BulkReinvite(organizationId, bulkRequestModel);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(organizationUsers.Count, response.Data.Count());
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationService>()
|
||||
.Received(1)
|
||||
.ResendInvitesAsync(organizationId, userId, bulkRequestModel.Ids);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@ using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Models.Business;
|
||||
using Bit.Core.AdminConsole.Models.Business.Tokenables;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||
@@ -20,7 +17,6 @@ using Bit.Core.Auth.Entities;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Auth.Services;
|
||||
using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
@@ -30,102 +26,24 @@ using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tokens;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Test.Billing.Mocks;
|
||||
using Bit.Infrastructure.EntityFramework.AdminConsole.Models.Provider;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
|
||||
public class OrganizationsControllerTests : IDisposable
|
||||
[ControllerCustomize(typeof(OrganizationsController))]
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationsControllerTests
|
||||
{
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly ISsoConfigRepository _ssoConfigRepository;
|
||||
private readonly ISsoConfigService _ssoConfigService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IGetOrganizationApiKeyQuery _getOrganizationApiKeyQuery;
|
||||
private readonly IRotateOrganizationApiKeyCommand _rotateOrganizationApiKeyCommand;
|
||||
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
|
||||
private readonly ICreateOrganizationApiKeyCommand _createOrganizationApiKeyCommand;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly IProviderBillingService _providerBillingService;
|
||||
private readonly IDataProtectorTokenFactory<OrgDeleteTokenable> _orgDeleteTokenDataFactory;
|
||||
private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand;
|
||||
private readonly ICloudOrganizationSignUpCommand _cloudOrganizationSignUpCommand;
|
||||
private readonly IOrganizationDeleteCommand _organizationDeleteCommand;
|
||||
private readonly IPolicyRequirementQuery _policyRequirementQuery;
|
||||
private readonly IPricingClient _pricingClient;
|
||||
private readonly IOrganizationUpdateKeysCommand _organizationUpdateKeysCommand;
|
||||
private readonly OrganizationsController _sut;
|
||||
|
||||
public OrganizationsControllerTests()
|
||||
{
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
_globalSettings = Substitute.For<GlobalSettings>();
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_organizationService = Substitute.For<IOrganizationService>();
|
||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
_policyRepository = Substitute.For<IPolicyRepository>();
|
||||
_ssoConfigRepository = Substitute.For<ISsoConfigRepository>();
|
||||
_ssoConfigService = Substitute.For<ISsoConfigService>();
|
||||
_getOrganizationApiKeyQuery = Substitute.For<IGetOrganizationApiKeyQuery>();
|
||||
_rotateOrganizationApiKeyCommand = Substitute.For<IRotateOrganizationApiKeyCommand>();
|
||||
_organizationApiKeyRepository = Substitute.For<IOrganizationApiKeyRepository>();
|
||||
_userService = Substitute.For<IUserService>();
|
||||
_createOrganizationApiKeyCommand = Substitute.For<ICreateOrganizationApiKeyCommand>();
|
||||
_featureService = Substitute.For<IFeatureService>();
|
||||
_providerRepository = Substitute.For<IProviderRepository>();
|
||||
_providerBillingService = Substitute.For<IProviderBillingService>();
|
||||
_orgDeleteTokenDataFactory = Substitute.For<IDataProtectorTokenFactory<OrgDeleteTokenable>>();
|
||||
_removeOrganizationUserCommand = Substitute.For<IRemoveOrganizationUserCommand>();
|
||||
_cloudOrganizationSignUpCommand = Substitute.For<ICloudOrganizationSignUpCommand>();
|
||||
_organizationDeleteCommand = Substitute.For<IOrganizationDeleteCommand>();
|
||||
_policyRequirementQuery = Substitute.For<IPolicyRequirementQuery>();
|
||||
_pricingClient = Substitute.For<IPricingClient>();
|
||||
_organizationUpdateKeysCommand = Substitute.For<IOrganizationUpdateKeysCommand>();
|
||||
|
||||
_sut = new OrganizationsController(
|
||||
_organizationRepository,
|
||||
_organizationUserRepository,
|
||||
_policyRepository,
|
||||
_organizationService,
|
||||
_userService,
|
||||
_currentContext,
|
||||
_ssoConfigRepository,
|
||||
_ssoConfigService,
|
||||
_getOrganizationApiKeyQuery,
|
||||
_rotateOrganizationApiKeyCommand,
|
||||
_createOrganizationApiKeyCommand,
|
||||
_organizationApiKeyRepository,
|
||||
_featureService,
|
||||
_globalSettings,
|
||||
_providerRepository,
|
||||
_providerBillingService,
|
||||
_orgDeleteTokenDataFactory,
|
||||
_removeOrganizationUserCommand,
|
||||
_cloudOrganizationSignUpCommand,
|
||||
_organizationDeleteCommand,
|
||||
_policyRequirementQuery,
|
||||
_pricingClient,
|
||||
_organizationUpdateKeysCommand);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sut?.Dispose();
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
[Theory, BitAutoData]
|
||||
public async Task OrganizationsController_UserCannotLeaveOrganizationThatProvidesKeyConnector(
|
||||
Guid orgId, User user)
|
||||
SutProvider<OrganizationsController> sutProvider,
|
||||
Guid orgId,
|
||||
User user)
|
||||
{
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
@@ -140,21 +58,24 @@ public class OrganizationsControllerTests : IDisposable
|
||||
|
||||
user.UsesKeyConnector = true;
|
||||
|
||||
_currentContext.OrganizationUser(orgId).Returns(true);
|
||||
_ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_userService.GetOrganizationsClaimingUserAsync(user.Id).Returns(new List<Organization> { null });
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => _sut.Leave(orgId));
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(orgId).Returns(true);
|
||||
sutProvider.GetDependency<ISsoConfigRepository>().GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
sutProvider.GetDependency<IUserService>().GetOrganizationsClaimingUserAsync(user.Id).Returns(new List<Organization> { null });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.Leave(orgId));
|
||||
|
||||
Assert.Contains("Your organization's Single Sign-On settings prevent you from leaving.",
|
||||
exception.Message);
|
||||
|
||||
await _removeOrganizationUserCommand.DidNotReceiveWithAnyArgs().UserLeaveAsync(default, default);
|
||||
await sutProvider.GetDependency<IRemoveOrganizationUserCommand>().DidNotReceiveWithAnyArgs().UserLeaveAsync(default, default);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
[Theory, BitAutoData]
|
||||
public async Task OrganizationsController_UserCannotLeaveOrganizationThatManagesUser(
|
||||
Guid orgId, User user)
|
||||
SutProvider<OrganizationsController> sutProvider,
|
||||
Guid orgId,
|
||||
User user)
|
||||
{
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
@@ -166,27 +87,34 @@ public class OrganizationsControllerTests : IDisposable
|
||||
Enabled = true,
|
||||
OrganizationId = orgId,
|
||||
};
|
||||
var foundOrg = new Organization();
|
||||
foundOrg.Id = orgId;
|
||||
var foundOrg = new Organization
|
||||
{
|
||||
Id = orgId
|
||||
};
|
||||
|
||||
_currentContext.OrganizationUser(orgId).Returns(true);
|
||||
_ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_userService.GetOrganizationsClaimingUserAsync(user.Id).Returns(new List<Organization> { { foundOrg } });
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => _sut.Leave(orgId));
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(orgId).Returns(true);
|
||||
sutProvider.GetDependency<ISsoConfigRepository>().GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
sutProvider.GetDependency<IUserService>().GetOrganizationsClaimingUserAsync(user.Id).Returns(new List<Organization> { foundOrg });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.Leave(orgId));
|
||||
|
||||
Assert.Contains("Claimed user account cannot leave claiming organization. Contact your organization administrator for additional details.",
|
||||
exception.Message);
|
||||
|
||||
await _removeOrganizationUserCommand.DidNotReceiveWithAnyArgs().RemoveUserAsync(default, default);
|
||||
await sutProvider.GetDependency<IRemoveOrganizationUserCommand>().DidNotReceiveWithAnyArgs().RemoveUserAsync(default, default);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineAutoData(true, false)]
|
||||
[InlineAutoData(false, true)]
|
||||
[InlineAutoData(false, false)]
|
||||
[BitAutoData(true, false)]
|
||||
[BitAutoData(false, true)]
|
||||
[BitAutoData(false, false)]
|
||||
public async Task OrganizationsController_UserCanLeaveOrganizationThatDoesntProvideKeyConnector(
|
||||
bool keyConnectorEnabled, bool userUsesKeyConnector, Guid orgId, User user)
|
||||
bool keyConnectorEnabled,
|
||||
bool userUsesKeyConnector,
|
||||
SutProvider<OrganizationsController> sutProvider,
|
||||
Guid orgId,
|
||||
User user)
|
||||
{
|
||||
var ssoConfig = new SsoConfig
|
||||
{
|
||||
@@ -203,18 +131,19 @@ public class OrganizationsControllerTests : IDisposable
|
||||
|
||||
user.UsesKeyConnector = userUsesKeyConnector;
|
||||
|
||||
_currentContext.OrganizationUser(orgId).Returns(true);
|
||||
_ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_userService.GetOrganizationsClaimingUserAsync(user.Id).Returns(new List<Organization>());
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(orgId).Returns(true);
|
||||
sutProvider.GetDependency<ISsoConfigRepository>().GetByOrganizationIdAsync(orgId).Returns(ssoConfig);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
sutProvider.GetDependency<IUserService>().GetOrganizationsClaimingUserAsync(user.Id).Returns(new List<Organization>());
|
||||
|
||||
await _sut.Leave(orgId);
|
||||
await sutProvider.Sut.Leave(orgId);
|
||||
|
||||
await _removeOrganizationUserCommand.Received(1).UserLeaveAsync(orgId, user.Id);
|
||||
await sutProvider.GetDependency<IRemoveOrganizationUserCommand>().Received(1).UserLeaveAsync(orgId, user.Id);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
[Theory, BitAutoData]
|
||||
public async Task Delete_OrganizationIsConsolidatedBillingClient_ScalesProvidersSeats(
|
||||
SutProvider<OrganizationsController> sutProvider,
|
||||
Provider provider,
|
||||
Organization organization,
|
||||
User user,
|
||||
@@ -228,87 +157,89 @@ public class OrganizationsControllerTests : IDisposable
|
||||
provider.Type = ProviderType.Msp;
|
||||
provider.Status = ProviderStatusType.Billable;
|
||||
|
||||
_currentContext.OrganizationOwner(organizationId).Returns(true);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(organizationId).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(organization);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
sutProvider.GetDependency<IUserService>().VerifySecretAsync(user, requestModel.Secret).Returns(true);
|
||||
sutProvider.GetDependency<IProviderRepository>().GetByOrganizationIdAsync(organization.Id).Returns(provider);
|
||||
|
||||
_organizationRepository.GetByIdAsync(organizationId).Returns(organization);
|
||||
await sutProvider.Sut.Delete(organizationId.ToString(), requestModel);
|
||||
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
|
||||
_userService.VerifySecretAsync(user, requestModel.Secret).Returns(true);
|
||||
|
||||
_providerRepository.GetByOrganizationIdAsync(organization.Id).Returns(provider);
|
||||
|
||||
await _sut.Delete(organizationId.ToString(), requestModel);
|
||||
|
||||
await _providerBillingService.Received(1)
|
||||
await sutProvider.GetDependency<IProviderBillingService>().Received(1)
|
||||
.ScaleSeats(provider, organization.PlanType, -organization.Seats.Value);
|
||||
|
||||
await _organizationDeleteCommand.Received(1).DeleteAsync(organization);
|
||||
await sutProvider.GetDependency<IOrganizationDeleteCommand>().Received(1).DeleteAsync(organization);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetAutoEnrollStatus_WithPolicyRequirementsEnabled_ReturnsOrganizationAutoEnrollStatus_WithResetPasswordEnabledTrue(
|
||||
SutProvider<OrganizationsController> sutProvider,
|
||||
User user,
|
||||
Organization organization,
|
||||
OrganizationUser organizationUser
|
||||
)
|
||||
OrganizationUser organizationUser)
|
||||
{
|
||||
var policyRequirement = new ResetPasswordPolicyRequirement() { AutoEnrollOrganizations = [organization.Id] };
|
||||
var policyRequirement = new ResetPasswordPolicyRequirement { AutoEnrollOrganizations = [organization.Id] };
|
||||
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_organizationRepository.GetByIdentifierAsync(organization.Id.ToString()).Returns(organization);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true);
|
||||
_organizationUserRepository.GetByOrganizationAsync(organization.Id, user.Id).Returns(organizationUser);
|
||||
_policyRequirementQuery.GetAsync<ResetPasswordPolicyRequirement>(user.Id).Returns(policyRequirement);
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdentifierAsync(organization.Id.ToString()).Returns(organization);
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByOrganizationAsync(organization.Id, user.Id).Returns(organizationUser);
|
||||
sutProvider.GetDependency<IPolicyRequirementQuery>().GetAsync<ResetPasswordPolicyRequirement>(user.Id).Returns(policyRequirement);
|
||||
|
||||
var result = await _sut.GetAutoEnrollStatus(organization.Id.ToString());
|
||||
var result = await sutProvider.Sut.GetAutoEnrollStatus(organization.Id.ToString());
|
||||
|
||||
await _userService.Received(1).GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>());
|
||||
await _organizationRepository.Received(1).GetByIdentifierAsync(organization.Id.ToString());
|
||||
await _policyRequirementQuery.Received(1).GetAsync<ResetPasswordPolicyRequirement>(user.Id);
|
||||
await sutProvider.GetDependency<IUserService>().Received(1).GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>());
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).GetByIdentifierAsync(organization.Id.ToString());
|
||||
await sutProvider.GetDependency<IPolicyRequirementQuery>().Received(1).GetAsync<ResetPasswordPolicyRequirement>(user.Id);
|
||||
|
||||
Assert.True(result.ResetPasswordEnabled);
|
||||
Assert.Equal(result.Id, organization.Id);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
[Theory, BitAutoData]
|
||||
public async Task GetAutoEnrollStatus_WithPolicyRequirementsDisabled_ReturnsOrganizationAutoEnrollStatus_WithResetPasswordEnabledTrue(
|
||||
User user,
|
||||
Organization organization,
|
||||
OrganizationUser organizationUser
|
||||
)
|
||||
SutProvider<OrganizationsController> sutProvider,
|
||||
User user,
|
||||
Organization organization,
|
||||
OrganizationUser organizationUser)
|
||||
{
|
||||
var policy = new Policy
|
||||
{
|
||||
Type = PolicyType.ResetPassword,
|
||||
Enabled = true,
|
||||
Data = "{\"AutoEnrollEnabled\": true}",
|
||||
OrganizationId = organization.Id
|
||||
};
|
||||
|
||||
var policy = new Policy() { Type = PolicyType.ResetPassword, Enabled = true, Data = "{\"AutoEnrollEnabled\": true}", OrganizationId = organization.Id };
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdentifierAsync(organization.Id.ToString()).Returns(organization);
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(false);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>().GetByOrganizationAsync(organization.Id, user.Id).Returns(organizationUser);
|
||||
sutProvider.GetDependency<IPolicyRepository>().GetByOrganizationIdTypeAsync(organization.Id, PolicyType.ResetPassword).Returns(policy);
|
||||
|
||||
_userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).Returns(user);
|
||||
_organizationRepository.GetByIdentifierAsync(organization.Id.ToString()).Returns(organization);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(false);
|
||||
_organizationUserRepository.GetByOrganizationAsync(organization.Id, user.Id).Returns(organizationUser);
|
||||
_policyRepository.GetByOrganizationIdTypeAsync(organization.Id, PolicyType.ResetPassword).Returns(policy);
|
||||
var result = await sutProvider.Sut.GetAutoEnrollStatus(organization.Id.ToString());
|
||||
|
||||
var result = await _sut.GetAutoEnrollStatus(organization.Id.ToString());
|
||||
|
||||
await _userService.Received(1).GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>());
|
||||
await _organizationRepository.Received(1).GetByIdentifierAsync(organization.Id.ToString());
|
||||
await _policyRequirementQuery.Received(0).GetAsync<ResetPasswordPolicyRequirement>(user.Id);
|
||||
await _policyRepository.Received(1).GetByOrganizationIdTypeAsync(organization.Id, PolicyType.ResetPassword);
|
||||
await sutProvider.GetDependency<IUserService>().Received(1).GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>());
|
||||
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).GetByIdentifierAsync(organization.Id.ToString());
|
||||
await sutProvider.GetDependency<IPolicyRequirementQuery>().Received(0).GetAsync<ResetPasswordPolicyRequirement>(user.Id);
|
||||
await sutProvider.GetDependency<IPolicyRepository>().Received(1).GetByOrganizationIdTypeAsync(organization.Id, PolicyType.ResetPassword);
|
||||
|
||||
Assert.True(result.ResetPasswordEnabled);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
[Theory, BitAutoData]
|
||||
public async Task PutCollectionManagement_ValidRequest_Success(
|
||||
SutProvider<OrganizationsController> sutProvider,
|
||||
Organization organization,
|
||||
OrganizationCollectionManagementUpdateRequestModel model)
|
||||
{
|
||||
// Arrange
|
||||
_currentContext.OrganizationOwner(organization.Id).Returns(true);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(organization.Id).Returns(true);
|
||||
|
||||
var plan = StaticStore.GetPlan(PlanType.EnterpriseAnnually);
|
||||
_pricingClient.GetPlan(Arg.Any<PlanType>()).Returns(plan);
|
||||
var plan = MockPlans.Get(PlanType.EnterpriseAnnually);
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlan(Arg.Any<PlanType>()).Returns(plan);
|
||||
|
||||
_organizationService
|
||||
sutProvider.GetDependency<IOrganizationService>()
|
||||
.UpdateCollectionManagementSettingsAsync(
|
||||
organization.Id,
|
||||
Arg.Is<OrganizationCollectionManagementSettings>(s =>
|
||||
@@ -319,10 +250,10 @@ public class OrganizationsControllerTests : IDisposable
|
||||
.Returns(organization);
|
||||
|
||||
// Act
|
||||
await _sut.PutCollectionManagement(organization.Id, model);
|
||||
await sutProvider.Sut.PutCollectionManagement(organization.Id, model);
|
||||
|
||||
// Assert
|
||||
await _organizationService
|
||||
await sutProvider.GetDependency<IOrganizationService>()
|
||||
.Received(1)
|
||||
.UpdateCollectionManagementSettingsAsync(
|
||||
organization.Id,
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
|
||||
using Bit.Core.Enums;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Models.Request.Organizations;
|
||||
|
||||
public class OrganizationIntegrationConfigurationRequestModelTests
|
||||
{
|
||||
[Fact]
|
||||
public void IsValidForType_CloudBillingSyncIntegration_ReturnsFalse()
|
||||
{
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = "{}",
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.CloudBillingSync));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(data: null)]
|
||||
[InlineData(data: "")]
|
||||
[InlineData(data: " ")]
|
||||
public void IsValidForType_EmptyConfiguration_ReturnsFalse(string? config)
|
||||
{
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Slack));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Webhook));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(data: "")]
|
||||
[InlineData(data: " ")]
|
||||
public void IsValidForType_EmptyNonNullConfiguration_ReturnsFalse(string? config)
|
||||
{
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Hec));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Datadog));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Teams));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_NullConfiguration_ReturnsTrue()
|
||||
{
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = null,
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.True(condition: model.IsValidForType(IntegrationType.Hec));
|
||||
Assert.True(condition: model.IsValidForType(IntegrationType.Datadog));
|
||||
Assert.True(condition: model.IsValidForType(IntegrationType.Teams));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(data: null)]
|
||||
[InlineData(data: "")]
|
||||
[InlineData(data: " ")]
|
||||
public void IsValidForType_EmptyTemplate_ReturnsFalse(string? template)
|
||||
{
|
||||
var config = JsonSerializer.Serialize(value: new WebhookIntegrationConfiguration(
|
||||
Uri: new Uri("https://localhost"),
|
||||
Scheme: "Bearer",
|
||||
Token: "AUTH-TOKEN"));
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Template = template
|
||||
};
|
||||
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Slack));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Webhook));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Hec));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Datadog));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Teams));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_InvalidJsonConfiguration_ReturnsFalse()
|
||||
{
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = "{not valid json}",
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Slack));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Webhook));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Hec));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Datadog));
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Teams));
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_InvalidJsonFilters_ReturnsFalse()
|
||||
{
|
||||
var config = JsonSerializer.Serialize(new WebhookIntegrationConfiguration(Uri: new Uri("https://example.com")));
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Filters = "{Not valid json",
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.False(model.IsValidForType(IntegrationType.Webhook));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_ScimIntegration_ReturnsFalse()
|
||||
{
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = "{}",
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.False(condition: model.IsValidForType(IntegrationType.Scim));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_ValidSlackConfiguration_ReturnsTrue()
|
||||
{
|
||||
var config = JsonSerializer.Serialize(value: new SlackIntegrationConfiguration(ChannelId: "C12345"));
|
||||
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.True(condition: model.IsValidForType(IntegrationType.Slack));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_ValidSlackConfigurationWithFilters_ReturnsTrue()
|
||||
{
|
||||
var config = JsonSerializer.Serialize(new SlackIntegrationConfiguration("C12345"));
|
||||
var filters = JsonSerializer.Serialize(new IntegrationFilterGroup()
|
||||
{
|
||||
AndOperator = true,
|
||||
Rules = [
|
||||
new IntegrationFilterRule()
|
||||
{
|
||||
Operation = IntegrationFilterOperation.Equals,
|
||||
Property = "CollectionId",
|
||||
Value = Guid.NewGuid()
|
||||
}
|
||||
],
|
||||
Groups = []
|
||||
});
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Filters = filters,
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.True(model.IsValidForType(IntegrationType.Slack));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_ValidNoAuthWebhookConfiguration_ReturnsTrue()
|
||||
{
|
||||
var config = JsonSerializer.Serialize(value: new WebhookIntegrationConfiguration(Uri: new Uri("https://localhost")));
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.True(condition: model.IsValidForType(IntegrationType.Webhook));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_ValidWebhookConfiguration_ReturnsTrue()
|
||||
{
|
||||
var config = JsonSerializer.Serialize(value: new WebhookIntegrationConfiguration(
|
||||
Uri: new Uri("https://localhost"),
|
||||
Scheme: "Bearer",
|
||||
Token: "AUTH-TOKEN"));
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.True(condition: model.IsValidForType(IntegrationType.Webhook));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_ValidWebhookConfigurationWithFilters_ReturnsTrue()
|
||||
{
|
||||
var config = JsonSerializer.Serialize(new WebhookIntegrationConfiguration(
|
||||
Uri: new Uri("https://example.com"),
|
||||
Scheme: "Bearer",
|
||||
Token: "AUTH-TOKEN"));
|
||||
var filters = JsonSerializer.Serialize(new IntegrationFilterGroup()
|
||||
{
|
||||
AndOperator = true,
|
||||
Rules = [
|
||||
new IntegrationFilterRule()
|
||||
{
|
||||
Operation = IntegrationFilterOperation.Equals,
|
||||
Property = "CollectionId",
|
||||
Value = Guid.NewGuid()
|
||||
}
|
||||
],
|
||||
Groups = []
|
||||
});
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = config,
|
||||
Filters = filters,
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
Assert.True(model.IsValidForType(IntegrationType.Webhook));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IsValidForType_UnknownIntegrationType_ReturnsFalse()
|
||||
{
|
||||
var model = new OrganizationIntegrationConfigurationRequestModel
|
||||
{
|
||||
Configuration = "{}",
|
||||
Template = "template"
|
||||
};
|
||||
|
||||
var unknownType = (IntegrationType)999;
|
||||
|
||||
Assert.False(condition: model.IsValidForType(unknownType));
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,7 @@ public class ProfileOrganizationResponseModelTests
|
||||
UsersGetPremium = organization.UsersGetPremium,
|
||||
UseCustomPermissions = organization.UseCustomPermissions,
|
||||
UseRiskInsights = organization.UseRiskInsights,
|
||||
UsePhishingBlocker = organization.UsePhishingBlocker,
|
||||
UseOrganizationDomains = organization.UseOrganizationDomains,
|
||||
UseAdminSponsoredFamilies = organization.UseAdminSponsoredFamilies,
|
||||
UseAutomaticUserConfirmation = organization.UseAutomaticUserConfirmation,
|
||||
|
||||
@@ -45,6 +45,7 @@ public class ProfileProviderOrganizationResponseModelTests
|
||||
UsersGetPremium = organization.UsersGetPremium,
|
||||
UseCustomPermissions = organization.UseCustomPermissions,
|
||||
UseRiskInsights = organization.UseRiskInsights,
|
||||
UsePhishingBlocker = organization.UsePhishingBlocker,
|
||||
UseOrganizationDomains = organization.UseOrganizationDomains,
|
||||
UseAdminSponsoredFamilies = organization.UseAdminSponsoredFamilies,
|
||||
UseAutomaticUserConfirmation = organization.UseAutomaticUserConfirmation,
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
using Bit.Api.AdminConsole.Public.Controllers;
|
||||
using Bit.Api.AdminConsole.Public.Models.Request;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
@@ -22,7 +19,7 @@ public class PoliciesControllerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Put_WhenPolicyValidatorsRefactorEnabled_UsesVNextSavePolicyCommand(
|
||||
public async Task Put_UsesVNextSavePolicyCommand(
|
||||
Guid organizationId,
|
||||
PolicyType policyType,
|
||||
PolicyUpdateRequestModel model,
|
||||
@@ -33,9 +30,6 @@ public class PoliciesControllerTests
|
||||
policy.Data = null;
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationId.Returns(organizationId);
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||
.SaveAsync(Arg.Any<SavePolicyModel>())
|
||||
.Returns(policy);
|
||||
@@ -52,36 +46,4 @@ public class PoliciesControllerTests
|
||||
m.PolicyUpdate.Enabled == model.Enabled.GetValueOrDefault() &&
|
||||
m.PerformedBy is SystemUser));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Put_WhenPolicyValidatorsRefactorDisabled_UsesLegacySavePolicyCommand(
|
||||
Guid organizationId,
|
||||
PolicyType policyType,
|
||||
PolicyUpdateRequestModel model,
|
||||
Policy policy,
|
||||
SutProvider<PoliciesController> sutProvider)
|
||||
{
|
||||
// Arrange
|
||||
policy.Data = null;
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationId.Returns(organizationId);
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||
.Returns(false);
|
||||
sutProvider.GetDependency<ISavePolicyCommand>()
|
||||
.SaveAsync(Arg.Any<PolicyUpdate>())
|
||||
.Returns(policy);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.Put(policyType, model);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ISavePolicyCommand>()
|
||||
.Received(1)
|
||||
.SaveAsync(Arg.Is<PolicyUpdate>(p =>
|
||||
p.OrganizationId == organizationId &&
|
||||
p.Type == policyType &&
|
||||
p.Enabled == model.Enabled));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Bit.Core;
|
||||
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
||||
using Bit.Core.Billing.Constants;
|
||||
using Bit.Core.Billing.Models.Business;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.KeyManagement.Queries.Interfaces;
|
||||
@@ -30,6 +31,7 @@ public class AccountsControllerTests : IDisposable
|
||||
private readonly IPaymentService _paymentService;
|
||||
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
|
||||
private readonly IUserAccountKeysQuery _userAccountKeysQuery;
|
||||
private readonly ILicensingService _licensingService;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly AccountsController _sut;
|
||||
|
||||
@@ -40,13 +42,15 @@ public class AccountsControllerTests : IDisposable
|
||||
_paymentService = Substitute.For<IPaymentService>();
|
||||
_twoFactorIsEnabledQuery = Substitute.For<ITwoFactorIsEnabledQuery>();
|
||||
_userAccountKeysQuery = Substitute.For<IUserAccountKeysQuery>();
|
||||
_licensingService = Substitute.For<ILicensingService>();
|
||||
_globalSettings = new GlobalSettings { SelfHosted = false };
|
||||
|
||||
_sut = new AccountsController(
|
||||
_userService,
|
||||
_twoFactorIsEnabledQuery,
|
||||
_userAccountKeysQuery,
|
||||
_featureService
|
||||
_featureService,
|
||||
_licensingService
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ using Bit.Core.Models.Data;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Test.Billing.Mocks;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
@@ -24,11 +24,11 @@ namespace Bit.Api.Test.Billing.Controllers;
|
||||
public class OrganizationSponsorshipsControllerTests
|
||||
{
|
||||
public static IEnumerable<object[]> EnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).ProductTier == ProductTierType.Enterprise).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => MockPlans.Get(p).ProductTier == ProductTierType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonEnterprisePlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).ProductTier != ProductTierType.Enterprise).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => MockPlans.Get(p).ProductTier != ProductTierType.Enterprise).Select(p => new object[] { p });
|
||||
public static IEnumerable<object[]> NonFamiliesPlanTypes =>
|
||||
Enum.GetValues<PlanType>().Where(p => StaticStore.GetPlan(p).ProductTier != ProductTierType.Families).Select(p => new object[] { p });
|
||||
Enum.GetValues<PlanType>().Where(p => MockPlans.Get(p).ProductTier != ProductTierType.Families).Select(p => new object[] { p });
|
||||
|
||||
public static IEnumerable<object[]> NonConfirmedOrganizationUsersStatuses =>
|
||||
Enum.GetValues<OrganizationUserStatusType>()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Bit.Api.Billing.Controllers;
|
||||
using Bit.Api.Billing.Models.Requests;
|
||||
using Bit.Api.Billing.Models.Responses;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
@@ -11,13 +10,11 @@ using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.Billing.Providers.Entities;
|
||||
using Bit.Core.Billing.Providers.Repositories;
|
||||
using Bit.Core.Billing.Providers.Services;
|
||||
using Bit.Core.Billing.Services;
|
||||
using Bit.Core.Billing.Tax.Models;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Models.BitStripe;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Test.Billing.Mocks;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@@ -351,7 +348,7 @@ public class ProviderBillingControllerTests
|
||||
|
||||
foreach (var providerPlan in providerPlans)
|
||||
{
|
||||
var plan = StaticStore.GetPlan(providerPlan.PlanType);
|
||||
var plan = MockPlans.Get(providerPlan.PlanType);
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(providerPlan.PlanType).Returns(plan);
|
||||
var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, providerPlan.PlanType);
|
||||
sutProvider.GetDependency<IStripeAdapter>().PriceGetAsync(priceId)
|
||||
@@ -372,7 +369,7 @@ public class ProviderBillingControllerTests
|
||||
Assert.Equal(subscription.Customer!.Discount!.Coupon!.PercentOff, response.DiscountPercentage);
|
||||
Assert.Equal(subscription.CollectionMethod, response.CollectionMethod);
|
||||
|
||||
var teamsPlan = StaticStore.GetPlan(PlanType.TeamsMonthly);
|
||||
var teamsPlan = MockPlans.Get(PlanType.TeamsMonthly);
|
||||
var providerTeamsPlan = response.Plans.FirstOrDefault(plan => plan.PlanName == teamsPlan.Name);
|
||||
Assert.NotNull(providerTeamsPlan);
|
||||
Assert.Equal(50, providerTeamsPlan.SeatMinimum);
|
||||
@@ -381,7 +378,7 @@ public class ProviderBillingControllerTests
|
||||
Assert.Equal(60 * teamsPlan.PasswordManager.ProviderPortalSeatPrice, providerTeamsPlan.Cost);
|
||||
Assert.Equal("Monthly", providerTeamsPlan.Cadence);
|
||||
|
||||
var enterprisePlan = StaticStore.GetPlan(PlanType.EnterpriseMonthly);
|
||||
var enterprisePlan = MockPlans.Get(PlanType.EnterpriseMonthly);
|
||||
var providerEnterprisePlan = response.Plans.FirstOrDefault(plan => plan.PlanName == enterprisePlan.Name);
|
||||
Assert.NotNull(providerEnterprisePlan);
|
||||
Assert.Equal(100, providerEnterprisePlan.SeatMinimum);
|
||||
@@ -498,7 +495,7 @@ public class ProviderBillingControllerTests
|
||||
|
||||
foreach (var providerPlan in providerPlans)
|
||||
{
|
||||
var plan = StaticStore.GetPlan(providerPlan.PlanType);
|
||||
var plan = MockPlans.Get(providerPlan.PlanType);
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(providerPlan.PlanType).Returns(plan);
|
||||
var priceId = ProviderPriceAdapter.GetPriceId(provider, subscription, providerPlan.PlanType);
|
||||
sutProvider.GetDependency<IStripeAdapter>().PriceGetAsync(priceId)
|
||||
@@ -521,49 +518,4 @@ public class ProviderBillingControllerTests
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UpdateTaxInformationAsync
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateTaxInformation_NoCountry_BadRequest(
|
||||
Provider provider,
|
||||
TaxInformationRequestBody requestBody,
|
||||
SutProvider<ProviderBillingController> sutProvider)
|
||||
{
|
||||
ConfigureStableProviderAdminInputs(provider, sutProvider);
|
||||
|
||||
requestBody.Country = null;
|
||||
|
||||
var result = await sutProvider.Sut.UpdateTaxInformationAsync(provider.Id, requestBody);
|
||||
|
||||
Assert.IsType<BadRequest<ErrorResponseModel>>(result);
|
||||
|
||||
var response = (BadRequest<ErrorResponseModel>)result;
|
||||
|
||||
Assert.Equal("Country and postal code are required to update your tax information.", response.Value.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UpdateTaxInformation_Ok(
|
||||
Provider provider,
|
||||
TaxInformationRequestBody requestBody,
|
||||
SutProvider<ProviderBillingController> sutProvider)
|
||||
{
|
||||
ConfigureStableProviderAdminInputs(provider, sutProvider);
|
||||
|
||||
await sutProvider.Sut.UpdateTaxInformationAsync(provider.Id, requestBody);
|
||||
|
||||
await sutProvider.GetDependency<ISubscriberService>().Received(1).UpdateTaxInformation(
|
||||
provider, Arg.Is<TaxInformation>(
|
||||
options =>
|
||||
options.Country == requestBody.Country &&
|
||||
options.PostalCode == requestBody.PostalCode &&
|
||||
options.TaxId == requestBody.TaxId &&
|
||||
options.Line1 == requestBody.Line1 &&
|
||||
options.Line2 == requestBody.Line2 &&
|
||||
options.City == requestBody.City &&
|
||||
options.State == requestBody.State));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Text.Json;
|
||||
using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Api.AdminConsole.Models.Request;
|
||||
using Bit.Api.AdminConsole.Models.Response.Organizations;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
@@ -291,7 +290,7 @@ public class PoliciesControllerTests
|
||||
string token,
|
||||
string email,
|
||||
Organization organization
|
||||
)
|
||||
)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
@@ -302,14 +301,15 @@ public class PoliciesControllerTests
|
||||
var decryptedToken = Substitute.For<OrgUserInviteTokenable>();
|
||||
decryptedToken.Valid.Returns(false);
|
||||
|
||||
var orgUserInviteTokenDataFactory = sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
var orgUserInviteTokenDataFactory =
|
||||
sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
|
||||
orgUserInviteTokenDataFactory.TryUnprotect(token, out Arg.Any<OrgUserInviteTokenable>())
|
||||
.Returns(x =>
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
@@ -325,7 +325,7 @@ public class PoliciesControllerTests
|
||||
string token,
|
||||
string email,
|
||||
Organization organization
|
||||
)
|
||||
)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
@@ -338,14 +338,15 @@ public class PoliciesControllerTests
|
||||
decryptedToken.OrgUserId = organizationUserId;
|
||||
decryptedToken.OrgUserEmail = email;
|
||||
|
||||
var orgUserInviteTokenDataFactory = sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
var orgUserInviteTokenDataFactory =
|
||||
sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
|
||||
orgUserInviteTokenDataFactory.TryUnprotect(token, out Arg.Any<OrgUserInviteTokenable>())
|
||||
.Returns(x =>
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetByIdAsync(organizationUserId)
|
||||
@@ -366,7 +367,7 @@ public class PoliciesControllerTests
|
||||
string email,
|
||||
OrganizationUser orgUser,
|
||||
Organization organization
|
||||
)
|
||||
)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
@@ -379,14 +380,15 @@ public class PoliciesControllerTests
|
||||
decryptedToken.OrgUserId = organizationUserId;
|
||||
decryptedToken.OrgUserEmail = email;
|
||||
|
||||
var orgUserInviteTokenDataFactory = sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
var orgUserInviteTokenDataFactory =
|
||||
sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
|
||||
orgUserInviteTokenDataFactory.TryUnprotect(token, out Arg.Any<OrgUserInviteTokenable>())
|
||||
.Returns(x =>
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
|
||||
orgUser.OrganizationId = Guid.Empty;
|
||||
|
||||
@@ -409,7 +411,7 @@ public class PoliciesControllerTests
|
||||
string email,
|
||||
OrganizationUser orgUser,
|
||||
Organization organization
|
||||
)
|
||||
)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
@@ -422,14 +424,15 @@ public class PoliciesControllerTests
|
||||
decryptedToken.OrgUserId = organizationUserId;
|
||||
decryptedToken.OrgUserEmail = email;
|
||||
|
||||
var orgUserInviteTokenDataFactory = sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
var orgUserInviteTokenDataFactory =
|
||||
sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
|
||||
orgUserInviteTokenDataFactory.TryUnprotect(token, out Arg.Any<OrgUserInviteTokenable>())
|
||||
.Returns(x =>
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
|
||||
orgUser.OrganizationId = orgId;
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
@@ -463,7 +466,7 @@ public class PoliciesControllerTests
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutVNext_WhenPolicyValidatorsRefactorEnabled_UsesVNextSavePolicyCommand(
|
||||
public async Task PutVNext_UsesVNextSavePolicyCommand(
|
||||
SutProvider<PoliciesController> sutProvider, Guid orgId,
|
||||
SavePolicyRequest model, Policy policy, Guid userId)
|
||||
{
|
||||
@@ -478,10 +481,6 @@ public class PoliciesControllerTests
|
||||
.OrganizationOwner(orgId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||
.SaveAsync(Arg.Any<SavePolicyModel>())
|
||||
.Returns(policy);
|
||||
@@ -492,12 +491,11 @@ public class PoliciesControllerTests
|
||||
// Assert
|
||||
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||
.Received(1)
|
||||
.SaveAsync(Arg.Is<SavePolicyModel>(
|
||||
m => m.PolicyUpdate.OrganizationId == orgId &&
|
||||
m.PolicyUpdate.Type == policy.Type &&
|
||||
m.PolicyUpdate.Enabled == model.Policy.Enabled &&
|
||||
m.PerformedBy.UserId == userId &&
|
||||
m.PerformedBy.IsOrganizationOwnerOrProvider == true));
|
||||
.SaveAsync(Arg.Is<SavePolicyModel>(m => m.PolicyUpdate.OrganizationId == orgId &&
|
||||
m.PolicyUpdate.Type == policy.Type &&
|
||||
m.PolicyUpdate.Enabled == model.Policy.Enabled &&
|
||||
m.PerformedBy.UserId == userId &&
|
||||
m.PerformedBy.IsOrganizationOwnerOrProvider == true));
|
||||
|
||||
await sutProvider.GetDependency<ISavePolicyCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
@@ -507,51 +505,4 @@ public class PoliciesControllerTests
|
||||
Assert.Equal(policy.Id, result.Id);
|
||||
Assert.Equal(policy.Type, result.Type);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task PutVNext_WhenPolicyValidatorsRefactorDisabled_UsesSavePolicyCommand(
|
||||
SutProvider<PoliciesController> sutProvider, Guid orgId,
|
||||
SavePolicyRequest model, Policy policy, Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
policy.Data = null;
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.UserId
|
||||
.Returns(userId);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationOwner(orgId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
|
||||
.Returns(false);
|
||||
|
||||
sutProvider.GetDependency<ISavePolicyCommand>()
|
||||
.VNextSaveAsync(Arg.Any<SavePolicyModel>())
|
||||
.Returns(policy);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.PutVNext(orgId, policy.Type, model);
|
||||
|
||||
// Assert
|
||||
await sutProvider.GetDependency<ISavePolicyCommand>()
|
||||
.Received(1)
|
||||
.VNextSaveAsync(Arg.Is<SavePolicyModel>(
|
||||
m => m.PolicyUpdate.OrganizationId == orgId &&
|
||||
m.PolicyUpdate.Type == policy.Type &&
|
||||
m.PolicyUpdate.Enabled == model.Policy.Enabled &&
|
||||
m.PerformedBy.UserId == userId &&
|
||||
m.PerformedBy.IsOrganizationOwnerOrProvider == true));
|
||||
|
||||
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
.SaveAsync(default);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(policy.Id, result.Id);
|
||||
Assert.Equal(policy.Type, result.Type);
|
||||
}
|
||||
}
|
||||
|
||||
292
test/Api.Test/Dirt/HibpControllerTests.cs
Normal file
292
test/Api.Test/Dirt/HibpControllerTests.cs
Normal file
@@ -0,0 +1,292 @@
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Bit.Api.Dirt.Controllers;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using GlobalSettings = Bit.Core.Settings.GlobalSettings;
|
||||
|
||||
namespace Bit.Api.Test.Dirt;
|
||||
|
||||
[ControllerCustomize(typeof(HibpController))]
|
||||
[SutProviderCustomize]
|
||||
public class HibpControllerTests : IDisposable
|
||||
{
|
||||
private readonly HttpClient _originalHttpClient;
|
||||
private readonly FieldInfo _httpClientField;
|
||||
|
||||
public HibpControllerTests()
|
||||
{
|
||||
// Store original HttpClient for restoration
|
||||
_httpClientField = typeof(HibpController).GetField("_httpClient", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
_originalHttpClient = (HttpClient)_httpClientField?.GetValue(null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Restore original HttpClient after tests
|
||||
_httpClientField?.SetValue(null, _originalHttpClient);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Get_WithMissingApiKey_ThrowsBadRequestException(
|
||||
SutProvider<HibpController> sutProvider,
|
||||
string username)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<GlobalSettings>().HibpApiKey = null;
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
async () => await sutProvider.Sut.Get(username));
|
||||
Assert.Equal("HaveIBeenPwned API key not set.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Get_WithValidApiKeyAndNoBreaches_Returns200WithEmptyArray(
|
||||
SutProvider<HibpController> sutProvider,
|
||||
string username,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<GlobalSettings>().HibpApiKey = "test-api-key";
|
||||
var user = new User { Id = userId };
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(Arg.Any<System.Security.Claims.ClaimsPrincipal>())
|
||||
.Returns(userId);
|
||||
|
||||
// Mock HttpClient to return 404 (no breaches found)
|
||||
var mockHttpClient = CreateMockHttpClient(HttpStatusCode.NotFound, "");
|
||||
_httpClientField.SetValue(null, mockHttpClient);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.Get(username);
|
||||
|
||||
// Assert
|
||||
var contentResult = Assert.IsType<ContentResult>(result);
|
||||
Assert.Equal("[]", contentResult.Content);
|
||||
Assert.Equal("application/json", contentResult.ContentType);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Get_WithValidApiKeyAndBreachesFound_Returns200WithBreachData(
|
||||
SutProvider<HibpController> sutProvider,
|
||||
string username,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<GlobalSettings>().HibpApiKey = "test-api-key";
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(Arg.Any<System.Security.Claims.ClaimsPrincipal>())
|
||||
.Returns(userId);
|
||||
|
||||
var breachData = "[{\"Name\":\"Adobe\",\"Title\":\"Adobe\",\"Domain\":\"adobe.com\"}]";
|
||||
var mockHttpClient = CreateMockHttpClient(HttpStatusCode.OK, breachData);
|
||||
_httpClientField.SetValue(null, mockHttpClient);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.Get(username);
|
||||
|
||||
// Assert
|
||||
var contentResult = Assert.IsType<ContentResult>(result);
|
||||
Assert.Equal(breachData, contentResult.Content);
|
||||
Assert.Equal("application/json", contentResult.ContentType);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Get_WithRateLimiting_RetriesWithDelay(
|
||||
SutProvider<HibpController> sutProvider,
|
||||
string username,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<GlobalSettings>().HibpApiKey = "test-api-key";
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(Arg.Any<System.Security.Claims.ClaimsPrincipal>())
|
||||
.Returns(userId);
|
||||
|
||||
// First response is rate limited, second is success
|
||||
var requestCount = 0;
|
||||
var mockHandler = new MockHttpMessageHandler((request, cancellationToken) =>
|
||||
{
|
||||
requestCount++;
|
||||
if (requestCount == 1)
|
||||
{
|
||||
var response = new HttpResponseMessage(HttpStatusCode.TooManyRequests);
|
||||
response.Headers.Add("retry-after", "1");
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound)
|
||||
{
|
||||
Content = new StringContent("")
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var mockHttpClient = new HttpClient(mockHandler);
|
||||
_httpClientField.SetValue(null, mockHttpClient);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.Get(username);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, requestCount); // Verify retry happened
|
||||
var contentResult = Assert.IsType<ContentResult>(result);
|
||||
Assert.Equal("[]", contentResult.Content);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Get_WithServerError_ThrowsBadRequestException(
|
||||
SutProvider<HibpController> sutProvider,
|
||||
string username,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<GlobalSettings>().HibpApiKey = "test-api-key";
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(Arg.Any<System.Security.Claims.ClaimsPrincipal>())
|
||||
.Returns(userId);
|
||||
|
||||
var mockHttpClient = CreateMockHttpClient(HttpStatusCode.InternalServerError, "");
|
||||
_httpClientField.SetValue(null, mockHttpClient);
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
async () => await sutProvider.Sut.Get(username));
|
||||
Assert.Contains("Request failed. Status code:", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Get_WithBadRequest_ThrowsBadRequestException(
|
||||
SutProvider<HibpController> sutProvider,
|
||||
string username,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<GlobalSettings>().HibpApiKey = "test-api-key";
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(Arg.Any<System.Security.Claims.ClaimsPrincipal>())
|
||||
.Returns(userId);
|
||||
|
||||
var mockHttpClient = CreateMockHttpClient(HttpStatusCode.BadRequest, "");
|
||||
_httpClientField.SetValue(null, mockHttpClient);
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
async () => await sutProvider.Sut.Get(username));
|
||||
Assert.Contains("Request failed. Status code:", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task Get_EncodesUsernameCorrectly(
|
||||
SutProvider<HibpController> sutProvider,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
var usernameWithSpecialChars = "test+user@example.com";
|
||||
sutProvider.GetDependency<GlobalSettings>().HibpApiKey = "test-api-key";
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(Arg.Any<System.Security.Claims.ClaimsPrincipal>())
|
||||
.Returns(userId);
|
||||
|
||||
string capturedUrl = null;
|
||||
var mockHandler = new MockHttpMessageHandler((request, cancellationToken) =>
|
||||
{
|
||||
capturedUrl = request.RequestUri.ToString();
|
||||
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound)
|
||||
{
|
||||
Content = new StringContent("")
|
||||
});
|
||||
});
|
||||
|
||||
var mockHttpClient = new HttpClient(mockHandler);
|
||||
_httpClientField.SetValue(null, mockHttpClient);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.Get(usernameWithSpecialChars);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(capturedUrl);
|
||||
// Username should be URL encoded (+ becomes %2B, @ becomes %40)
|
||||
Assert.Contains("test%2Buser%40example.com", capturedUrl);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SendAsync_IncludesRequiredHeaders(
|
||||
SutProvider<HibpController> sutProvider,
|
||||
string username,
|
||||
Guid userId)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<GlobalSettings>().HibpApiKey = "test-api-key";
|
||||
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false;
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(Arg.Any<System.Security.Claims.ClaimsPrincipal>())
|
||||
.Returns(userId);
|
||||
|
||||
HttpRequestMessage capturedRequest = null;
|
||||
var mockHandler = new MockHttpMessageHandler((request, cancellationToken) =>
|
||||
{
|
||||
capturedRequest = request;
|
||||
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound)
|
||||
{
|
||||
Content = new StringContent("")
|
||||
});
|
||||
});
|
||||
|
||||
var mockHttpClient = new HttpClient(mockHandler);
|
||||
_httpClientField.SetValue(null, mockHttpClient);
|
||||
|
||||
// Act
|
||||
await sutProvider.Sut.Get(username);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(capturedRequest);
|
||||
Assert.True(capturedRequest.Headers.Contains("hibp-api-key"));
|
||||
Assert.True(capturedRequest.Headers.Contains("hibp-client-id"));
|
||||
Assert.True(capturedRequest.Headers.Contains("User-Agent"));
|
||||
Assert.Equal("Bitwarden", capturedRequest.Headers.GetValues("User-Agent").First());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to create a mock HttpClient that returns a specific status code and content
|
||||
/// </summary>
|
||||
private HttpClient CreateMockHttpClient(HttpStatusCode statusCode, string content)
|
||||
{
|
||||
var mockHandler = new MockHttpMessageHandler((request, cancellationToken) =>
|
||||
{
|
||||
return Task.FromResult(new HttpResponseMessage(statusCode)
|
||||
{
|
||||
Content = new StringContent(content)
|
||||
});
|
||||
});
|
||||
|
||||
return new HttpClient(mockHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mock HttpMessageHandler for testing HttpClient behavior
|
||||
/// </summary>
|
||||
public class MockHttpMessageHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _sendAsync;
|
||||
|
||||
public MockHttpMessageHandler(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsync)
|
||||
{
|
||||
_sendAsync = sendAsync;
|
||||
}
|
||||
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
return _sendAsync(request, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,9 @@ using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.KeyManagement.Commands.Interfaces;
|
||||
using Bit.Core.KeyManagement.Models.Api.Request;
|
||||
using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.KeyManagement.Queries.Interfaces;
|
||||
using Bit.Core.KeyManagement.UserKey;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
@@ -362,4 +364,39 @@ public class AccountsKeyManagementControllerTests
|
||||
await sutProvider.GetDependency<IUserService>().Received(1)
|
||||
.ConvertToKeyConnectorAsync(Arg.Is(expectedUser));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetKeyConnectorConfirmationDetailsAsync_NoUser_Throws(
|
||||
SutProvider<AccountsKeyManagementController> sutProvider, string orgSsoIdentifier)
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(() =>
|
||||
sutProvider.Sut.GetKeyConnectorConfirmationDetailsAsync(orgSsoIdentifier));
|
||||
|
||||
await sutProvider.GetDependency<IKeyConnectorConfirmationDetailsQuery>().ReceivedWithAnyArgs(0)
|
||||
.Run(Arg.Any<string>(), Arg.Any<Guid>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetKeyConnectorConfirmationDetailsAsync_Success(
|
||||
SutProvider<AccountsKeyManagementController> sutProvider, User expectedUser, string orgSsoIdentifier)
|
||||
{
|
||||
sutProvider.GetDependency<IUserService>().GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(expectedUser);
|
||||
sutProvider.GetDependency<IKeyConnectorConfirmationDetailsQuery>().Run(orgSsoIdentifier, expectedUser.Id)
|
||||
.Returns(
|
||||
new KeyConnectorConfirmationDetails { OrganizationName = "test" }
|
||||
);
|
||||
|
||||
var result = await sutProvider.Sut.GetKeyConnectorConfirmationDetailsAsync(orgSsoIdentifier);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("test", result.OrganizationName);
|
||||
await sutProvider.GetDependency<IKeyConnectorConfirmationDetailsQuery>().Received(1)
|
||||
.Run(orgSsoIdentifier, expectedUser.Id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
|
||||
using Bit.Api.KeyManagement.Models.Requests;
|
||||
using Bit.Core.KeyManagement.Models.Api.Request;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.KeyManagement.Models.Request;
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
using Bit.Api.SecretsManager.Controllers;
|
||||
using Bit.Api.SecretsManager.Models.Request;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Test.SecretsManager.AutoFixture.SecretsFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.SecretsManager.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(SecretVersionsController))]
|
||||
[SutProviderCustomize]
|
||||
[SecretCustomize]
|
||||
public class SecretVersionsControllerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetVersionsBySecretId_SecretNotFound_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Guid secretId)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secretId).Returns((Secret?)null);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetVersionsBySecretIdAsync(secretId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetVersionsBySecretId_NoAccess_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Secret secret)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secret.Id).Returns(secret);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetVersionsBySecretIdAsync(secret.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetVersionsBySecretId_NoReadAccess_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Secret secret,
|
||||
Guid userId)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secret.Id).Returns(secret);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(false);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((false, false));
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetVersionsBySecretIdAsync(secret.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetVersionsBySecretId_Success(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Secret secret,
|
||||
List<SecretVersion> versions,
|
||||
Guid userId)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secret.Id).Returns(secret);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(false);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((true, false));
|
||||
|
||||
foreach (var version in versions)
|
||||
{
|
||||
version.SecretId = secret.Id;
|
||||
}
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetManyBySecretIdAsync(secret.Id).Returns(versions);
|
||||
|
||||
var result = await sutProvider.Sut.GetVersionsBySecretIdAsync(secret.Id);
|
||||
|
||||
Assert.Equal(versions.Count, result.Data.Count());
|
||||
await sutProvider.GetDependency<ISecretVersionRepository>().Received(1)
|
||||
.GetManyBySecretIdAsync(Arg.Is(secret.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetById_VersionNotFound_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Guid versionId)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetByIdAsync(versionId).Returns((SecretVersion?)null);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetByIdAsync(versionId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetById_Success(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
SecretVersion version,
|
||||
Secret secret,
|
||||
Guid userId)
|
||||
{
|
||||
version.SecretId = secret.Id;
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetByIdAsync(version.Id).Returns(version);
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secret.Id).Returns(secret);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(false);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((true, false));
|
||||
|
||||
var result = await sutProvider.Sut.GetByIdAsync(version.Id);
|
||||
|
||||
Assert.Equal(version.Id, result.Id);
|
||||
Assert.Equal(version.SecretId, result.SecretId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RestoreVersion_NoWriteAccess_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Secret secret,
|
||||
SecretVersion version,
|
||||
RestoreSecretVersionRequestModel request,
|
||||
Guid userId)
|
||||
{
|
||||
version.SecretId = secret.Id;
|
||||
request.VersionId = version.Id;
|
||||
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secret.Id).Returns(secret);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(false);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((true, false));
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.RestoreVersionAsync(secret.Id, request));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RestoreVersion_VersionNotFound_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Secret secret,
|
||||
RestoreSecretVersionRequestModel request,
|
||||
Guid userId)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secret.Id).Returns(secret);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((true, true));
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetByIdAsync(request.VersionId).Returns((SecretVersion?)null);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.RestoreVersionAsync(secret.Id, request));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RestoreVersion_VersionBelongsToDifferentSecret_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Secret secret,
|
||||
SecretVersion version,
|
||||
RestoreSecretVersionRequestModel request,
|
||||
Guid userId)
|
||||
{
|
||||
version.SecretId = Guid.NewGuid(); // Different secret
|
||||
request.VersionId = version.Id;
|
||||
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secret.Id).Returns(secret);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((true, true));
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetByIdAsync(request.VersionId).Returns(version);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.RestoreVersionAsync(secret.Id, request));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task RestoreVersion_Success(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
Secret secret,
|
||||
SecretVersion version,
|
||||
RestoreSecretVersionRequestModel request,
|
||||
Guid userId,
|
||||
OrganizationUser organizationUser)
|
||||
{
|
||||
version.SecretId = secret.Id;
|
||||
request.VersionId = version.Id;
|
||||
var versionValue = version.Value;
|
||||
organizationUser.OrganizationId = secret.OrganizationId;
|
||||
organizationUser.UserId = userId;
|
||||
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(secret.Id).Returns(secret);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((true, true));
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetByIdAsync(request.VersionId).Returns(version);
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetByOrganizationAsync(secret.OrganizationId, userId).Returns(organizationUser);
|
||||
sutProvider.GetDependency<ISecretRepository>().UpdateAsync(Arg.Any<Secret>()).Returns(x => x.Arg<Secret>());
|
||||
|
||||
var result = await sutProvider.Sut.RestoreVersionAsync(secret.Id, request);
|
||||
|
||||
await sutProvider.GetDependency<ISecretRepository>().Received(1)
|
||||
.UpdateAsync(Arg.Is<Secret>(s => s.Value == versionValue));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task BulkDelete_EmptyIds_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.BulkDeleteAsync(new List<Guid>()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task BulkDelete_VersionNotFound_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
List<Guid> ids)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetByIdAsync(ids[0]).Returns((SecretVersion?)null);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.BulkDeleteAsync(ids));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task BulkDelete_NoWriteAccess_Throws(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
List<SecretVersion> versions,
|
||||
Secret secret,
|
||||
Guid userId)
|
||||
{
|
||||
var ids = versions.Select(v => v.Id).ToList();
|
||||
foreach (var version in versions)
|
||||
{
|
||||
version.SecretId = secret.Id;
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetByIdAsync(version.Id).Returns(version);
|
||||
}
|
||||
|
||||
sutProvider.GetDependency<ISecretRepository>().GetManyByIds(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns(new List<Secret> { secret });
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(false);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((true, false));
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.BulkDeleteAsync(ids));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task BulkDelete_Success(
|
||||
SutProvider<SecretVersionsController> sutProvider,
|
||||
List<SecretVersion> versions,
|
||||
Secret secret,
|
||||
Guid userId)
|
||||
{
|
||||
var ids = versions.Select(v => v.Id).ToList();
|
||||
foreach (var version in versions)
|
||||
{
|
||||
version.SecretId = secret.Id;
|
||||
}
|
||||
|
||||
sutProvider.GetDependency<ISecretVersionRepository>().GetManyByIdsAsync(ids).Returns(versions);
|
||||
sutProvider.GetDependency<ISecretRepository>().GetManyByIds(Arg.Any<IEnumerable<Guid>>())
|
||||
.Returns(new List<Secret> { secret });
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<ICurrentContext>().IdentityClientType.Returns(IdentityClientType.ServiceAccount);
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(secret.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<ISecretRepository>().AccessToSecretAsync(secret.Id, userId, default)
|
||||
.ReturnsForAnyArgs((true, true));
|
||||
|
||||
await sutProvider.Sut.BulkDeleteAsync(ids);
|
||||
|
||||
await sutProvider.GetDependency<ISecretVersionRepository>().Received(1)
|
||||
.DeleteManyByIdAsync(Arg.Is<IEnumerable<Guid>>(x => x.SequenceEqual(ids)));
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using Bit.Api.SecretsManager.Controllers;
|
||||
using Bit.Api.SecretsManager.Models.Request;
|
||||
using Bit.Api.Test.SecretsManager.Enums;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
@@ -244,6 +245,7 @@ public class SecretsControllerTests
|
||||
{
|
||||
data = SetupSecretUpdateRequest(data);
|
||||
SetControllerUser(sutProvider, new Guid());
|
||||
sutProvider.GetDependency<ICurrentContext>().IdentityClientType.Returns(IdentityClientType.ServiceAccount);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<Secret>(),
|
||||
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Success());
|
||||
@@ -602,6 +604,7 @@ public class SecretsControllerTests
|
||||
{
|
||||
data = SetupSecretUpdateRequest(data, true);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().IdentityClientType.Returns(IdentityClientType.ServiceAccount);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<Secret>(),
|
||||
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).Returns(AuthorizationResult.Success());
|
||||
|
||||
@@ -16,7 +16,7 @@ using Bit.Core.SecretsManager.Models.Data;
|
||||
using Bit.Core.SecretsManager.Queries.ServiceAccounts.Interfaces;
|
||||
using Bit.Core.SecretsManager.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Test.Billing.Mocks;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Bit.Test.Common.Helpers;
|
||||
@@ -121,7 +121,7 @@ public class ServiceAccountsControllerTests
|
||||
{
|
||||
ArrangeCreateServiceAccountAutoScalingTest(newSlotsRequired, sutProvider, data, organization);
|
||||
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(StaticStore.GetPlan(organization.PlanType));
|
||||
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(organization.PlanType).Returns(MockPlans.Get(organization.PlanType));
|
||||
|
||||
await sutProvider.Sut.CreateAsync(organization.Id, data);
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ public class CiphersControllerTests
|
||||
sutProvider.GetDependency<ICipherRepository>().GetByIdAsync(id, userId).ReturnsForAnyArgs(cipherDetails);
|
||||
|
||||
sutProvider.GetDependency<ICollectionCipherRepository>().GetManyByUserIdCipherIdAsync(userId, id).Returns((ICollection<CollectionCipher>)new List<CollectionCipher>());
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(new Dictionary<Guid, OrganizationAbility> { { cipherDetails.OrganizationId.Value, new OrganizationAbility() } });
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(new Dictionary<Guid, OrganizationAbility> { { cipherDetails.OrganizationId.Value, new OrganizationAbility { Id = cipherDetails.OrganizationId.Value } } });
|
||||
var cipherService = sutProvider.GetDependency<ICipherService>();
|
||||
|
||||
await sutProvider.Sut.PutCollections_vNext(id, model);
|
||||
@@ -95,7 +95,7 @@ public class CiphersControllerTests
|
||||
sutProvider.GetDependency<ICipherRepository>().GetByIdAsync(id, userId).ReturnsForAnyArgs(cipherDetails);
|
||||
|
||||
sutProvider.GetDependency<ICollectionCipherRepository>().GetManyByUserIdCipherIdAsync(userId, id).Returns((ICollection<CollectionCipher>)new List<CollectionCipher>());
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(new Dictionary<Guid, OrganizationAbility> { { cipherDetails.OrganizationId.Value, new OrganizationAbility() } });
|
||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync().Returns(new Dictionary<Guid, OrganizationAbility> { { cipherDetails.OrganizationId.Value, new OrganizationAbility { Id = cipherDetails.OrganizationId.Value } } });
|
||||
|
||||
var result = await sutProvider.Sut.PutCollections_vNext(id, model);
|
||||
|
||||
@@ -1790,118 +1790,6 @@ public class CiphersControllerTests
|
||||
);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PutShareMany_ArchivedCipher_ThrowsBadRequestException(
|
||||
Guid organizationId,
|
||||
Guid userId,
|
||||
CipherWithIdRequestModel request,
|
||||
SutProvider<CiphersController> sutProvider)
|
||||
{
|
||||
request.EncryptedFor = userId;
|
||||
request.OrganizationId = organizationId.ToString();
|
||||
request.ArchivedDate = DateTime.UtcNow;
|
||||
var model = new CipherBulkShareRequestModel
|
||||
{
|
||||
Ciphers = [request],
|
||||
CollectionIds = [Guid.NewGuid().ToString()]
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationUser(organizationId)
|
||||
.Returns(Task.FromResult(true));
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(default)
|
||||
.ReturnsForAnyArgs(userId);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.PutShareMany(model)
|
||||
);
|
||||
|
||||
Assert.Equal("Cannot move archived items to an organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PutShareMany_ExistingCipherArchived_ThrowsBadRequestException(
|
||||
Guid organizationId,
|
||||
Guid userId,
|
||||
CipherWithIdRequestModel request,
|
||||
SutProvider<CiphersController> sutProvider)
|
||||
{
|
||||
// Request model does not have ArchivedDate (only the existing cipher does)
|
||||
request.EncryptedFor = userId;
|
||||
request.OrganizationId = organizationId.ToString();
|
||||
request.ArchivedDate = null;
|
||||
|
||||
var model = new CipherBulkShareRequestModel
|
||||
{
|
||||
Ciphers = [request],
|
||||
CollectionIds = [Guid.NewGuid().ToString()]
|
||||
};
|
||||
|
||||
// The existing cipher from the repository IS archived
|
||||
var existingCipher = new CipherDetails
|
||||
{
|
||||
Id = request.Id!.Value,
|
||||
UserId = userId,
|
||||
Type = CipherType.Login,
|
||||
Data = JsonSerializer.Serialize(new CipherLoginData()),
|
||||
ArchivedDate = DateTime.UtcNow
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationUser(organizationId)
|
||||
.Returns(Task.FromResult(true));
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(default)
|
||||
.ReturnsForAnyArgs(userId);
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetManyByUserIdAsync(userId, withOrganizations: false)
|
||||
.Returns(Task.FromResult((ICollection<CipherDetails>)[existingCipher]));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.PutShareMany(model)
|
||||
);
|
||||
|
||||
Assert.Equal("Cannot move archived items to an organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PutShare_ArchivedCipher_ThrowsBadRequestException(
|
||||
Guid cipherId,
|
||||
Guid organizationId,
|
||||
User user,
|
||||
CipherShareRequestModel model,
|
||||
SutProvider<CiphersController> sutProvider)
|
||||
{
|
||||
model.Cipher.OrganizationId = organizationId.ToString();
|
||||
model.Cipher.EncryptedFor = user.Id;
|
||||
|
||||
var cipher = new Cipher
|
||||
{
|
||||
Id = cipherId,
|
||||
UserId = user.Id,
|
||||
ArchivedDate = DateTime.UtcNow.AddDays(-1),
|
||||
Type = CipherType.Login,
|
||||
Data = JsonSerializer.Serialize(new CipherLoginData())
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(user);
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetByIdAsync(cipherId)
|
||||
.Returns(cipher);
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationUser(organizationId)
|
||||
.Returns(Task.FromResult(true));
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.PutShare(cipherId, model)
|
||||
);
|
||||
|
||||
Assert.Equal("Cannot move an archived item to an organization.", exception.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PostPurge_WhenUserNotFound_ThrowsUnauthorizedAccessException(
|
||||
SecretVerificationRequestModel model,
|
||||
@@ -2021,4 +1909,237 @@ public class CiphersControllerTests
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.PostPurge(model, organizationId));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PutShare_WithNullFolderAndFalseFavorite_UpdatesFieldsCorrectly(
|
||||
Guid cipherId,
|
||||
Guid userId,
|
||||
Guid organizationId,
|
||||
Guid folderId,
|
||||
SutProvider<CiphersController> sutProvider)
|
||||
{
|
||||
var user = new User { Id = userId };
|
||||
var userIdKey = userId.ToString().ToUpperInvariant();
|
||||
|
||||
var existingCipher = new Cipher
|
||||
{
|
||||
Id = cipherId,
|
||||
UserId = userId,
|
||||
Type = CipherType.Login,
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
Folders = JsonSerializer.Serialize(new Dictionary<string, object> { { userIdKey, folderId.ToString().ToUpperInvariant() } }),
|
||||
Favorites = JsonSerializer.Serialize(new Dictionary<string, object> { { userIdKey, true } })
|
||||
};
|
||||
|
||||
// Clears folder and favorite when sharing
|
||||
var model = new CipherShareRequestModel
|
||||
{
|
||||
Cipher = new CipherRequestModel
|
||||
{
|
||||
Type = CipherType.Login,
|
||||
OrganizationId = organizationId.ToString(),
|
||||
Name = "SharedCipher",
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
FolderId = null,
|
||||
Favorite = false,
|
||||
EncryptedFor = userId
|
||||
},
|
||||
CollectionIds = [Guid.NewGuid().ToString()]
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(user);
|
||||
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetByIdAsync(cipherId)
|
||||
.Returns(existingCipher);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationUser(organizationId)
|
||||
.Returns(true);
|
||||
|
||||
var sharedCipher = new CipherDetails
|
||||
{
|
||||
Id = cipherId,
|
||||
OrganizationId = organizationId,
|
||||
Type = CipherType.Login,
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
FolderId = null,
|
||||
Favorite = false
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetByIdAsync(cipherId, userId)
|
||||
.Returns(sharedCipher);
|
||||
|
||||
sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.GetOrganizationAbilitiesAsync()
|
||||
.Returns(new Dictionary<Guid, OrganizationAbility>
|
||||
{
|
||||
{ organizationId, new OrganizationAbility { Id = organizationId } }
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PutShare(cipherId, model);
|
||||
|
||||
Assert.Null(result.FolderId);
|
||||
Assert.False(result.Favorite);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PutShare_WithFolderAndFavoriteSet_AddsUserSpecificFields(
|
||||
Guid cipherId,
|
||||
Guid userId,
|
||||
Guid organizationId,
|
||||
Guid folderId,
|
||||
SutProvider<CiphersController> sutProvider)
|
||||
{
|
||||
var user = new User { Id = userId };
|
||||
var userIdKey = userId.ToString().ToUpperInvariant();
|
||||
|
||||
var existingCipher = new Cipher
|
||||
{
|
||||
Id = cipherId,
|
||||
UserId = userId,
|
||||
Type = CipherType.Login,
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
Folders = null,
|
||||
Favorites = null
|
||||
};
|
||||
|
||||
// Sets folder and favorite when sharing
|
||||
var model = new CipherShareRequestModel
|
||||
{
|
||||
Cipher = new CipherRequestModel
|
||||
{
|
||||
Type = CipherType.Login,
|
||||
OrganizationId = organizationId.ToString(),
|
||||
Name = "SharedCipher",
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
FolderId = folderId.ToString(),
|
||||
Favorite = true,
|
||||
EncryptedFor = userId
|
||||
},
|
||||
CollectionIds = [Guid.NewGuid().ToString()]
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(user);
|
||||
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetByIdAsync(cipherId)
|
||||
.Returns(existingCipher);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationUser(organizationId)
|
||||
.Returns(true);
|
||||
|
||||
var sharedCipher = new CipherDetails
|
||||
{
|
||||
Id = cipherId,
|
||||
OrganizationId = organizationId,
|
||||
Type = CipherType.Login,
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
Folders = JsonSerializer.Serialize(new Dictionary<string, object> { { userIdKey, folderId.ToString().ToUpperInvariant() } }),
|
||||
Favorites = JsonSerializer.Serialize(new Dictionary<string, object> { { userIdKey, true } }),
|
||||
FolderId = folderId,
|
||||
Favorite = true
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetByIdAsync(cipherId, userId)
|
||||
.Returns(sharedCipher);
|
||||
|
||||
sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.GetOrganizationAbilitiesAsync()
|
||||
.Returns(new Dictionary<Guid, OrganizationAbility>
|
||||
{
|
||||
{ organizationId, new OrganizationAbility { Id = organizationId } }
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PutShare(cipherId, model);
|
||||
|
||||
Assert.Equal(folderId, result.FolderId);
|
||||
Assert.True(result.Favorite);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task PutShare_UpdateExistingFolderAndFavorite_UpdatesUserSpecificFields(
|
||||
Guid cipherId,
|
||||
Guid userId,
|
||||
Guid organizationId,
|
||||
Guid oldFolderId,
|
||||
Guid newFolderId,
|
||||
SutProvider<CiphersController> sutProvider)
|
||||
{
|
||||
var user = new User { Id = userId };
|
||||
var userIdKey = userId.ToString().ToUpperInvariant();
|
||||
|
||||
// Existing cipher with old folder and not favorited
|
||||
var existingCipher = new Cipher
|
||||
{
|
||||
Id = cipherId,
|
||||
UserId = userId,
|
||||
Type = CipherType.Login,
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
Folders = JsonSerializer.Serialize(new Dictionary<string, object> { { userIdKey, oldFolderId.ToString().ToUpperInvariant() } }),
|
||||
Favorites = null
|
||||
};
|
||||
|
||||
var model = new CipherShareRequestModel
|
||||
{
|
||||
Cipher = new CipherRequestModel
|
||||
{
|
||||
Type = CipherType.Login,
|
||||
OrganizationId = organizationId.ToString(),
|
||||
Name = "SharedCipher",
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
FolderId = newFolderId.ToString(), // Update to new folder
|
||||
Favorite = true, // Add favorite
|
||||
EncryptedFor = userId
|
||||
},
|
||||
CollectionIds = [Guid.NewGuid().ToString()]
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns(user);
|
||||
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetByIdAsync(cipherId)
|
||||
.Returns(existingCipher);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.OrganizationUser(organizationId)
|
||||
.Returns(true);
|
||||
|
||||
var sharedCipher = new CipherDetails
|
||||
{
|
||||
Id = cipherId,
|
||||
OrganizationId = organizationId,
|
||||
Type = CipherType.Login,
|
||||
Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }),
|
||||
Folders = JsonSerializer.Serialize(new Dictionary<string, object> { { userIdKey, newFolderId.ToString().ToUpperInvariant() } }),
|
||||
Favorites = JsonSerializer.Serialize(new Dictionary<string, object> { { userIdKey, true } }),
|
||||
FolderId = newFolderId,
|
||||
Favorite = true
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ICipherRepository>()
|
||||
.GetByIdAsync(cipherId, userId)
|
||||
.Returns(sharedCipher);
|
||||
|
||||
sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.GetOrganizationAbilitiesAsync()
|
||||
.Returns(new Dictionary<Guid, OrganizationAbility>
|
||||
{
|
||||
{ organizationId, new OrganizationAbility { Id = organizationId } }
|
||||
});
|
||||
|
||||
var result = await sutProvider.Sut.PutShare(cipherId, model);
|
||||
|
||||
Assert.Equal(newFolderId, result.FolderId);
|
||||
Assert.True(result.Favorite);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Test.Billing.Mocks;
|
||||
using Bit.Core.Tools.Entities;
|
||||
using Bit.Core.Tools.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Core.Vault.Entities;
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
@@ -335,7 +335,7 @@ public class SyncControllerTests
|
||||
|
||||
if (matchedProviderUserOrgDetails != null)
|
||||
{
|
||||
var providerOrgProductType = StaticStore.GetPlan(matchedProviderUserOrgDetails.PlanType).ProductTier;
|
||||
var providerOrgProductType = MockPlans.Get(matchedProviderUserOrgDetails.PlanType).ProductTier;
|
||||
Assert.Equal(providerOrgProductType, profProviderOrg.ProductTierType);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user