From 227b72551470dff5587d4b5d29823412dc90ca07 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Tue, 10 May 2022 12:19:22 +1000 Subject: [PATCH] [EC-152] Hide Subscription/Billing information for Provider-managed organizations (#1970) * Block billing endpoints if org is managed by Provider --- .../Controllers/OrganizationsController.cs | 37 +++++++++++-------- src/Core/Context/CurrentContext.cs | 16 +++++++- src/Core/Context/ICurrentContext.cs | 2 + 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/Api/Controllers/OrganizationsController.cs b/src/Api/Controllers/OrganizationsController.cs index 41d7216e1..41ee259c4 100644 --- a/src/Api/Controllers/OrganizationsController.cs +++ b/src/Api/Controllers/OrganizationsController.cs @@ -83,7 +83,7 @@ namespace Bit.Api.Controllers public async Task GetBilling(string id) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -102,7 +102,7 @@ namespace Bit.Api.Controllers public async Task GetSubscription(string id) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -230,10 +230,6 @@ namespace Bit.Api.Controllers public async Task Put(string id, [FromBody] OrganizationUpdateRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) - { - throw new NotFoundException(); - } var organization = await _organizationRepository.GetByIdAsync(orgIdGuid); if (organization == null) @@ -241,10 +237,19 @@ namespace Bit.Api.Controllers throw new NotFoundException(); } - var updatebilling = !_globalSettings.SelfHosted && (model.BusinessName != organization.BusinessName || + var updateBilling = !_globalSettings.SelfHosted && (model.BusinessName != organization.BusinessName || model.BillingEmail != organization.BillingEmail); - await _organizationService.UpdateAsync(model.ToOrganization(organization, _globalSettings), updatebilling); + var hasRequiredPermissions = updateBilling + ? await _currentContext.ManageBilling(orgIdGuid) + : await _currentContext.OrganizationOwner(orgIdGuid); + + if (!hasRequiredPermissions) + { + throw new NotFoundException(); + } + + await _organizationService.UpdateAsync(model.ToOrganization(organization, _globalSettings), updateBilling); return new OrganizationResponseModel(organization); } @@ -253,7 +258,7 @@ namespace Bit.Api.Controllers public async Task PostPayment(string id, [FromBody] PaymentRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -276,7 +281,7 @@ namespace Bit.Api.Controllers public async Task PostUpgrade(string id, [FromBody] OrganizationUpgradeRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -294,7 +299,7 @@ namespace Bit.Api.Controllers public async Task PostSubscription(string id, [FromBody] OrganizationSubscriptionUpdateRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -307,7 +312,7 @@ namespace Bit.Api.Controllers public async Task PostSeat(string id, [FromBody] OrganizationSeatRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -325,7 +330,7 @@ namespace Bit.Api.Controllers public async Task PostStorage(string id, [FromBody] StorageRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -343,7 +348,7 @@ namespace Bit.Api.Controllers public async Task PostVerifyBank(string id, [FromBody] OrganizationVerifyBankRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -356,7 +361,7 @@ namespace Bit.Api.Controllers public async Task PostCancel(string id) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } @@ -369,7 +374,7 @@ namespace Bit.Api.Controllers public async Task PostReinstate(string id) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await _currentContext.ManageBilling(orgIdGuid)) { throw new NotFoundException(); } diff --git a/src/Core/Context/CurrentContext.cs b/src/Core/Context/CurrentContext.cs index 0eac65f9e..0f943dd69 100644 --- a/src/Core/Context/CurrentContext.cs +++ b/src/Core/Context/CurrentContext.cs @@ -261,7 +261,7 @@ namespace Bit.Core.Context if (Providers.Any()) { - return (await GetProviderOrganizations()).Any(po => po.OrganizationId == orgId); + return await ProviderUserForOrgAsync(orgId); } return false; @@ -360,6 +360,15 @@ namespace Bit.Core.Context && (o.Permissions?.ManageResetPassword ?? false)) ?? false); } + public async Task ManageBilling(Guid orgId) + { + var orgManagedByProvider = ProviderIdForOrg(orgId) != null; + + return orgManagedByProvider + ? await ProviderUserForOrgAsync(orgId) + : await OrganizationOwner(orgId); + } + public bool ProviderProviderAdmin(Guid providerId) { return Providers?.Any(o => o.Id == providerId && o.Type == ProviderUserType.ProviderAdmin) ?? false; @@ -390,6 +399,11 @@ namespace Bit.Core.Context return Providers?.Any(o => o.Id == providerId) ?? false; } + public async Task ProviderUserForOrgAsync(Guid orgId) + { + return (await GetProviderOrganizations()).Any(po => po.OrganizationId == orgId); + } + public async Task ProviderIdForOrg(Guid orgId) { if (Organizations?.Any(org => org.Id == orgId) ?? false) diff --git a/src/Core/Context/ICurrentContext.cs b/src/Core/Context/ICurrentContext.cs index ff06ced15..d94c7232b 100644 --- a/src/Core/Context/ICurrentContext.cs +++ b/src/Core/Context/ICurrentContext.cs @@ -51,6 +51,8 @@ namespace Bit.Core.Context Task ManageSso(Guid orgId); Task ManageUsers(Guid orgId); Task ManageResetPassword(Guid orgId); + Task ManageBilling(Guid orgId); + Task ProviderUserForOrgAsync(Guid orgId); bool ProviderProviderAdmin(Guid providerId); bool ProviderUser(Guid providerId); bool ProviderManageUsers(Guid providerId);