1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-16 01:51:21 +01:00

[AC-2887] Added Billing Authorization Where Missing (#4525)

* Added missing authorization validation to OrganizationBillingController endpoints

* Moved authorization validation to top of each method

* Resolved broken unit tests and added some new ones
This commit is contained in:
Conner Turnbull 2024-07-17 16:15:28 -04:00 committed by GitHub
parent 88d5a97a86
commit 45ec57f81b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 85 additions and 6 deletions

View File

@ -20,6 +20,11 @@ public class OrganizationBillingController(
[HttpGet("metadata")] [HttpGet("metadata")]
public async Task<IResult> GetMetadataAsync([FromRoute] Guid organizationId) public async Task<IResult> GetMetadataAsync([FromRoute] Guid organizationId)
{ {
if (!await currentContext.ViewBillingHistory(organizationId))
{
return TypedResults.Unauthorized();
}
var metadata = await organizationBillingService.GetMetadata(organizationId); var metadata = await organizationBillingService.GetMetadata(organizationId);
if (metadata == null) if (metadata == null)
@ -35,6 +40,11 @@ public class OrganizationBillingController(
[HttpGet("history")] [HttpGet("history")]
public async Task<IResult> GetHistoryAsync([FromRoute] Guid organizationId) public async Task<IResult> GetHistoryAsync([FromRoute] Guid organizationId)
{ {
if (!await currentContext.ViewBillingHistory(organizationId))
{
return TypedResults.Unauthorized();
}
var organization = await organizationRepository.GetByIdAsync(organizationId); var organization = await organizationRepository.GetByIdAsync(organizationId);
if (organization == null) if (organization == null)

View File

@ -162,13 +162,13 @@ public class OrganizationsController(
[SelfHosted(NotSelfHostedOnly = true)] [SelfHosted(NotSelfHostedOnly = true)]
public async Task PostSmSubscription(Guid id, [FromBody] SecretsManagerSubscriptionUpdateRequestModel model) public async Task PostSmSubscription(Guid id, [FromBody] SecretsManagerSubscriptionUpdateRequestModel model)
{ {
var organization = await organizationRepository.GetByIdAsync(id); if (!await currentContext.EditSubscription(id))
if (organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }
if (!await currentContext.EditSubscription(id)) var organization = await organizationRepository.GetByIdAsync(id);
if (organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }
@ -195,13 +195,13 @@ public class OrganizationsController(
[SelfHosted(NotSelfHostedOnly = true)] [SelfHosted(NotSelfHostedOnly = true)]
public async Task<ProfileOrganizationResponseModel> PostSubscribeSecretsManagerAsync(Guid id, [FromBody] SecretsManagerSubscribeRequestModel model) public async Task<ProfileOrganizationResponseModel> PostSubscribeSecretsManagerAsync(Guid id, [FromBody] SecretsManagerSubscribeRequestModel model)
{ {
var organization = await organizationRepository.GetByIdAsync(id); if (!await currentContext.EditSubscription(id))
if (organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }
if (!await currentContext.EditSubscription(id)) var organization = await organizationRepository.GetByIdAsync(id);
if (organization == null)
{ {
throw new NotFoundException(); throw new NotFoundException();
} }

View File

@ -1,7 +1,11 @@
using Bit.Api.Billing.Controllers; using Bit.Api.Billing.Controllers;
using Bit.Api.Billing.Models.Responses; using Bit.Api.Billing.Models.Responses;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.Billing.Models; using Bit.Core.Billing.Models;
using Bit.Core.Billing.Services; using Bit.Core.Billing.Services;
using Bit.Core.Context;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Http.HttpResults;
@ -14,11 +18,26 @@ namespace Bit.Api.Test.Billing.Controllers;
[SutProviderCustomize] [SutProviderCustomize]
public class OrganizationBillingControllerTests public class OrganizationBillingControllerTests
{ {
[Theory, BitAutoData]
public async Task GetMetadataAsync_Unauthorized_ReturnsUnauthorized(
Guid organizationId,
SutProvider<OrganizationBillingController> sutProvider)
{
sutProvider.GetDependency<ICurrentContext>().ViewBillingHistory(organizationId).Returns(false);
var result = await sutProvider.Sut.GetMetadataAsync(organizationId);
Assert.IsType<UnauthorizedHttpResult>(result);
}
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task GetMetadataAsync_MetadataNull_NotFound( public async Task GetMetadataAsync_MetadataNull_NotFound(
Guid organizationId, Guid organizationId,
SutProvider<OrganizationBillingController> sutProvider) SutProvider<OrganizationBillingController> sutProvider)
{ {
sutProvider.GetDependency<ICurrentContext>().ViewBillingHistory(organizationId).Returns(true);
sutProvider.GetDependency<IOrganizationBillingService>().GetMetadata(organizationId).Returns((OrganizationMetadataDTO)null);
var result = await sutProvider.Sut.GetMetadataAsync(organizationId); var result = await sutProvider.Sut.GetMetadataAsync(organizationId);
Assert.IsType<NotFound>(result); Assert.IsType<NotFound>(result);
@ -29,6 +48,7 @@ public class OrganizationBillingControllerTests
Guid organizationId, Guid organizationId,
SutProvider<OrganizationBillingController> sutProvider) SutProvider<OrganizationBillingController> sutProvider)
{ {
sutProvider.GetDependency<ICurrentContext>().ViewBillingHistory(organizationId).Returns(true);
sutProvider.GetDependency<IOrganizationBillingService>().GetMetadata(organizationId) sutProvider.GetDependency<IOrganizationBillingService>().GetMetadata(organizationId)
.Returns(new OrganizationMetadataDTO(true)); .Returns(new OrganizationMetadataDTO(true));
@ -40,4 +60,53 @@ public class OrganizationBillingControllerTests
Assert.True(organizationMetadataResponse.IsOnSecretsManagerStandalone); Assert.True(organizationMetadataResponse.IsOnSecretsManagerStandalone);
} }
[Theory, BitAutoData]
public async Task GetHistoryAsync_Unauthorized_ReturnsUnauthorized(
Guid organizationId,
SutProvider<OrganizationBillingController> sutProvider)
{
sutProvider.GetDependency<ICurrentContext>().ViewBillingHistory(organizationId).Returns(false);
var result = await sutProvider.Sut.GetHistoryAsync(organizationId);
Assert.IsType<UnauthorizedHttpResult>(result);
}
[Theory, BitAutoData]
public async Task GetHistoryAsync_OrganizationNotFound_ReturnsNotFound(
Guid organizationId,
SutProvider<OrganizationBillingController> sutProvider)
{
sutProvider.GetDependency<ICurrentContext>().ViewBillingHistory(organizationId).Returns(true);
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns((Organization)null);
var result = await sutProvider.Sut.GetHistoryAsync(organizationId);
Assert.IsType<NotFound>(result);
}
[Theory]
[BitAutoData]
public async Task GetHistoryAsync_OK(
Guid organizationId,
Organization organization,
SutProvider<OrganizationBillingController> sutProvider)
{
// Arrange
sutProvider.GetDependency<ICurrentContext>().ViewBillingHistory(organizationId).Returns(true);
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(organization);
// Manually create a BillingHistoryInfo object to avoid requiring AutoFixture to create HttpResponseHeaders
var billingInfo = new BillingHistoryInfo();
sutProvider.GetDependency<IPaymentService>().GetBillingHistoryAsync(organization).Returns(billingInfo);
// Act
var result = await sutProvider.Sut.GetHistoryAsync(organizationId);
// Assert
var okResult = Assert.IsType<Ok<BillingHistoryInfo>>(result);
Assert.Equal(billingInfo, okResult.Value);
}
} }