Skip to content

Commit

Permalink
[AC-1638] Disallow Secrets Manager for MSP-managed organizations (#3297)
Browse files Browse the repository at this point in the history
* Block MSPs from creating orgs with SM

* Block MSPs from adding SM to a managed org

* Prevent manually adding SM to an MSP-managed org

* Revert "Prevent manually adding SM to an MSP-managed org"

This change is no longer required

This reverts commit 51b0862.

* Block provider from adding org with SM

* Update error message when adding existing org with SM to provider

* Update check to match client

* Revert "Update check to match client"

This reverts commit f195c1c.
  • Loading branch information
eliykat authored Oct 12, 2023
1 parent 79648b3 commit 53f5eee
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,12 @@ public async Task AddOrganization(Guid providerId, Guid organizationId, string k
var organization = await _organizationRepository.GetByIdAsync(organizationId);
ThrowOnInvalidPlanType(organization.PlanType);

if (organization.UseSecretsManager)
{
throw new BadRequestException(
"The organization is subscribed to Secrets Manager. Please contact Customer Support to manage the subscription.");
}

var providerOrganization = new ProviderOrganization
{
ProviderId = providerId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,23 @@ public async Task AddOrganization_OrganizationAlreadyBelongsToAProvider_Throws(P
Assert.Equal("Organization already belongs to a provider.", exception.Message);
}

[Theory, BitAutoData]
public async Task AddOrganization_OrganizationHasSecretsManager_Throws(Provider provider, Organization organization, string key,
SutProvider<ProviderService> sutProvider)
{
organization.PlanType = PlanType.EnterpriseAnnually;
organization.UseSecretsManager = true;

sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
var providerOrganizationRepository = sutProvider.GetDependency<IProviderOrganizationRepository>();
providerOrganizationRepository.GetByOrganizationId(organization.Id).ReturnsNull();
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);

var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.AddOrganization(provider.Id, organization.Id, key));
Assert.Equal("The organization is subscribed to Secrets Manager. Please contact Customer Support to manage the subscription.", exception.Message);
}

[Theory, BitAutoData]
public async Task AddOrganization_Success(Provider provider, Organization organization, string key,
SutProvider<ProviderService> sutProvider)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Enums.Provider;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities;

Expand All @@ -12,17 +14,21 @@ public class AddSecretsManagerSubscriptionCommand : IAddSecretsManagerSubscripti
{
private readonly IPaymentService _paymentService;
private readonly IOrganizationService _organizationService;
private readonly IProviderRepository _providerRepository;

public AddSecretsManagerSubscriptionCommand(
IPaymentService paymentService,
IOrganizationService organizationService)
IOrganizationService organizationService,
IProviderRepository providerRepository)
{
_paymentService = paymentService;
_organizationService = organizationService;
_providerRepository = providerRepository;
}
public async Task SignUpAsync(Organization organization, int additionalSmSeats,
int additionalServiceAccounts)
{
ValidateOrganization(organization);
await ValidateOrganization(organization);

var plan = StaticStore.GetSecretsManagerPlan(organization.PlanType);
var signup = SetOrganizationUpgrade(organization, additionalSmSeats, additionalServiceAccounts);
Expand Down Expand Up @@ -55,7 +61,7 @@ private static OrganizationUpgrade SetOrganizationUpgrade(Organization organizat
return signup;
}

private static void ValidateOrganization(Organization organization)
private async Task ValidateOrganization(Organization organization)
{
if (organization == null)
{
Expand Down Expand Up @@ -83,5 +89,12 @@ private static void ValidateOrganization(Organization organization)
{
throw new BadRequestException("No subscription found.");
}

var provider = await _providerRepository.GetByOrganizationIdAsync(organization.Id);
if (provider is { Type: ProviderType.Msp })
{
throw new BadRequestException(
"Organizations with a Managed Service Provider do not support Secrets Manager.");
}
}
}
5 changes: 5 additions & 0 deletions src/Core/Services/Implementations/OrganizationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,11 @@ public async Task<Tuple<Organization, OrganizationUser>> SignUpAsync(Organizatio
var secretsManagerPlan = StaticStore.SecretManagerPlans.FirstOrDefault(p => p.Type == signup.Plan);
if (signup.UseSecretsManager)
{
if (provider)
{
throw new BadRequestException(
"Organizations with a Managed Service Provider do not support Secrets Manager.");
}
ValidateSecretsManagerPlan(secretsManagerPlan, signup);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using Bit.Core.Entities;
using Bit.Core.Entities.Provider;
using Bit.Core.Enums;
using Bit.Core.Enums.Provider;
using Bit.Core.Exceptions;
using Bit.Core.Models.Business;
using Bit.Core.Models.StaticStore;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
Expand Down Expand Up @@ -127,6 +130,25 @@ public async Task SignUpAsync_ThrowsException_WhenOrganizationAlreadyHasSecretsM
await VerifyDependencyNotCalledAsync(sutProvider);
}

[Theory]
[BitAutoData]
public async Task SignUpAsync_ThrowsException_WhenOrganizationIsManagedByMSP(
SutProvider<AddSecretsManagerSubscriptionCommand> sutProvider,
Organization organization,
Provider provider)
{
organization.UseSecretsManager = false;
organization.SecretsManagerBeta = false;
provider.Type = ProviderType.Msp;
sutProvider.GetDependency<IProviderRepository>().GetByOrganizationIdAsync(organization.Id).Returns(provider);

var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SignUpAsync(organization, 10, 10));

Assert.Contains("Organizations with a Managed Service Provider do not support Secrets Manager.", exception.Message);
await VerifyDependencyNotCalledAsync(sutProvider);
}

private static async Task VerifyDependencyNotCalledAsync(SutProvider<AddSecretsManagerSubscriptionCommand> sutProvider)
{
await sutProvider.GetDependency<IPaymentService>().DidNotReceive()
Expand Down
16 changes: 16 additions & 0 deletions test/Core.Test/Services/OrganizationServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,22 @@ await sutProvider.GetDependency<IPaymentService>().Received(1).PurchaseOrganizat
);
}

[Theory]
[BitAutoData(PlanType.EnterpriseAnnually)]
public async Task SignUp_SM_Throws_WhenManagedByMSP(PlanType planType, OrganizationSignup signup, SutProvider<OrganizationService> sutProvider)
{
signup.Plan = planType;
signup.UseSecretsManager = true;
signup.AdditionalSeats = 15;
signup.AdditionalSmSeats = 10;
signup.AdditionalServiceAccounts = 20;
signup.PaymentMethodType = PaymentMethodType.Card;
signup.PremiumAccessAddon = false;

var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SignUpAsync(signup, true));
Assert.Contains("Organizations with a Managed Service Provider do not support Secrets Manager.", exception.Message);
}

[Theory]
[BitAutoData]
public async Task SignUpAsync_SecretManager_AdditionalServiceAccounts_NotAllowedByPlan_ShouldThrowException(OrganizationSignup signup, SutProvider<OrganizationService> sutProvider)
Expand Down

0 comments on commit 53f5eee

Please sign in to comment.