diff --git a/bitwarden_license/src/Commercial.Core/Billing/Providers/Services/BusinessUnitConverter.cs b/bitwarden_license/src/Commercial.Core/Billing/Providers/Services/BusinessUnitConverter.cs index 5fa2c9405c45..8a2dd2a4891a 100644 --- a/bitwarden_license/src/Commercial.Core/Billing/Providers/Services/BusinessUnitConverter.cs +++ b/bitwarden_license/src/Commercial.Core/Billing/Providers/Services/BusinessUnitConverter.cs @@ -332,6 +332,11 @@ private async Task SendInviteAsync( Fail("Organization must be on an enterprise plan."); } + if (organization.UseSecretsManager) + { + Fail("Organization is subscribed to Secrets Manager."); + } + var subscription = await subscriberService.GetSubscription(organization); if (subscription is not @@ -418,6 +423,11 @@ void Fail(string scopedError) problems.Add("Organization must be on an enterprise plan."); } + if (organization.UseSecretsManager) + { + problems.Add("Organization is subscribed to Secrets Manager. Please contact Customer Support to convert this organization to a business unit."); + } + var subscription = await subscriberService.GetSubscription(organization); if (subscription is not diff --git a/bitwarden_license/test/Commercial.Core.Test/Billing/Providers/Services/BusinessUnitConverterTests.cs b/bitwarden_license/test/Commercial.Core.Test/Billing/Providers/Services/BusinessUnitConverterTests.cs index 48b971a032a8..d00b67051e2a 100644 --- a/bitwarden_license/test/Commercial.Core.Test/Billing/Providers/Services/BusinessUnitConverterTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/Billing/Providers/Services/BusinessUnitConverterTests.cs @@ -72,6 +72,7 @@ public async Task FinalizeConversion_Succeeds_ReturnsProviderId( string organizationKey) { organization.PlanType = PlanType.EnterpriseAnnually2020; + organization.UseSecretsManager = false; var enterpriseAnnually2020 = MockPlans.Get(PlanType.EnterpriseAnnually2020); @@ -206,6 +207,25 @@ await _organizationUserRepository.DidNotReceiveWithAnyArgs() .GetByOrganizationAsync(Arg.Any(), Arg.Any()); } + [Theory, BitAutoData] + public async Task FinalizeConversion_OrganizationUsesSecretsManager_ThrowsBillingException( + Organization organization, + Guid userId, + string token, + string providerKey, + string organizationKey) + { + organization.PlanType = PlanType.EnterpriseAnnually2020; + organization.UseSecretsManager = true; + + var businessUnitConverter = BuildConverter(); + + await Assert.ThrowsAsync(() => + businessUnitConverter.FinalizeConversion(organization, userId, token, providerKey, organizationKey)); + + await _subscriberService.DidNotReceiveWithAnyArgs().GetSubscription(Arg.Any()); + } + #endregion #region InitiateConversion @@ -216,6 +236,7 @@ public async Task InitiateConversion_Succeeds_ReturnsProviderId( string providerAdminEmail) { organization.PlanType = PlanType.EnterpriseAnnually; + organization.UseSecretsManager = false; _subscriberService.GetSubscription(organization).Returns(new Subscription { @@ -292,6 +313,7 @@ public async Task InitiateConversion_ValidationFails_ReturnsErrors( string providerAdminEmail) { organization.PlanType = PlanType.TeamsMonthly; + organization.UseSecretsManager = true; _subscriberService.GetSubscription(organization).Returns(new Subscription { @@ -324,6 +346,8 @@ public async Task InitiateConversion_ValidationFails_ReturnsErrors( Assert.Contains("Organization must be on an enterprise plan.", problems); + Assert.Contains("Organization is subscribed to Secrets Manager. Please contact Customer Support to convert this organization to a business unit.", problems); + Assert.Contains("Organization must have a valid subscription.", problems); Assert.Contains("Organization is already linked to a provider.", problems); @@ -331,6 +355,45 @@ public async Task InitiateConversion_ValidationFails_ReturnsErrors( Assert.Contains("Provider admin must be a confirmed member of the organization being converted.", problems); } + [Theory, BitAutoData] + public async Task InitiateConversion_OrganizationUsesSecretsManager_ReturnsError( + Organization organization, + string providerAdminEmail) + { + organization.PlanType = PlanType.EnterpriseAnnually; + organization.UseSecretsManager = true; + + _subscriberService.GetSubscription(organization).Returns(new Subscription + { + Status = StripeConstants.SubscriptionStatus.Active + }); + + var user = new User + { + Id = Guid.NewGuid(), + Email = providerAdminEmail + }; + + _userRepository.GetByEmailAsync(providerAdminEmail).Returns(user); + + var organizationUser = new OrganizationUser { Status = OrganizationUserStatusType.Confirmed }; + + _organizationUserRepository.GetByOrganizationAsync(organization.Id, user.Id) + .Returns(organizationUser); + + var businessUnitConverter = BuildConverter(); + + var result = await businessUnitConverter.InitiateConversion(organization, providerAdminEmail); + + Assert.True(result.IsT1); + + var problems = result.AsT1; + + Assert.Contains("Organization is subscribed to Secrets Manager. Please contact Customer Support to convert this organization to a business unit.", problems); + + await _providerRepository.DidNotReceiveWithAnyArgs().CreateAsync(Arg.Any()); + } + #endregion #region ResendConversionInvite diff --git a/src/Admin/AdminConsole/Views/Organizations/Edit.cshtml b/src/Admin/AdminConsole/Views/Organizations/Edit.cshtml index 690ee3d778c1..a736de797657 100644 --- a/src/Admin/AdminConsole/Views/Organizations/Edit.cshtml +++ b/src/Admin/AdminConsole/Views/Organizations/Edit.cshtml @@ -18,7 +18,8 @@ var canConvertToBusinessUnit = AccessControlService.UserHasPermission(Permission.Org_Billing_ConvertToBusinessUnit) && Model.Organization.PlanType.GetProductTier() == ProductTierType.Enterprise && !string.IsNullOrEmpty(Model.Organization.GatewaySubscriptionId) && - Model.Provider is null or { Type: ProviderType.BusinessUnit, Status: ProviderStatusType.Pending }; + Model.Provider is null or { Type: ProviderType.BusinessUnit, Status: ProviderStatusType.Pending } && + !Model.Organization.UseSecretsManager; } @section Scripts {