From 94059a2b06c2b30969714de3c24bf1b96d98fed3 Mon Sep 17 00:00:00 2001 From: Justin Baur <136baur@gmail.com> Date: Thu, 23 Jun 2022 07:50:10 -0400 Subject: [PATCH] Fix OrganizationConnection Update (#2071) * Force CloudOrganizationId to be read only * Fix tests --- .../OrganizationConnectionsController.cs | 8 +++++++ .../OrganizationConnectionsControllerTests.cs | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/Api/Controllers/OrganizationConnectionsController.cs b/src/Api/Controllers/OrganizationConnectionsController.cs index 9f9090d57f..c88a589133 100644 --- a/src/Api/Controllers/OrganizationConnectionsController.cs +++ b/src/Api/Controllers/OrganizationConnectionsController.cs @@ -89,6 +89,12 @@ namespace Bit.Api.Controllers [HttpPut("{organizationConnectionId}")] public async Task UpdateConnection(Guid organizationConnectionId, [FromBody] OrganizationConnectionRequestModel model) { + var existingOrganizationConnection = await _organizationConnectionRepository.GetByIdAsync(organizationConnectionId); + if (existingOrganizationConnection == null) + { + throw new NotFoundException(); + } + if (!await HasPermissionAsync(model?.OrganizationId)) { throw new BadRequestException("Only the owner of an organization can update a connection."); @@ -103,6 +109,8 @@ namespace Bit.Api.Controllers { case OrganizationConnectionType.CloudBillingSync: var typedModel = new OrganizationConnectionRequestModel(model); + // We don't allow overwriting or changing the CloudOrganizationId so save it from the existing connection + typedModel.ParsedConfig.CloudOrganizationId = existingOrganizationConnection.GetConfig().CloudOrganizationId; var connection = await _updateOrganizationConnectionCommand.UpdateAsync(typedModel.ToData(organizationConnectionId)); return new OrganizationConnectionResponseModel(connection, typeof(BillingSyncConfig)); default: diff --git a/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs b/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs index f7fa3fca32..ea36c5be22 100644 --- a/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs +++ b/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs @@ -141,6 +141,10 @@ namespace Bit.Api.Test.Controllers [BitAutoData] public async Task UpdateConnection_RequiresOwnerPermissions(SutProvider sutProvider) { + sutProvider.GetDependency() + .GetByIdAsync(Arg.Any()) + .Returns(new OrganizationConnection()); + var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateConnection(default, null)); Assert.Contains("Only the owner of an organization can update a connection.", exception.Message); @@ -157,6 +161,10 @@ namespace Bit.Api.Test.Controllers sutProvider.GetDependency().OrganizationOwner(typedModel.OrganizationId).Returns(true); + sutProvider.GetDependency() + .GetByIdAsync(existing1.Id) + .Returns(existing1); + sutProvider.GetDependency().GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type).Returns(new[] { existing1, existing2 }); var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateConnection(existing1.Id, typedModel)); @@ -170,6 +178,10 @@ namespace Bit.Api.Test.Controllers OrganizationConnection updated, SutProvider sutProvider) { + existing.SetConfig(new BillingSyncConfig + { + CloudOrganizationId = config.CloudOrganizationId, + }); updated.Config = JsonSerializer.Serialize(config); updated.Id = existing.Id; var model = RequestModelFromEntity(updated); @@ -177,6 +189,9 @@ namespace Bit.Api.Test.Controllers sutProvider.GetDependency().OrganizationOwner(model.OrganizationId).Returns(true); sutProvider.GetDependency().GetByOrganizationIdTypeAsync(model.OrganizationId, model.Type).Returns(new[] { existing }); sutProvider.GetDependency().UpdateAsync(default).ReturnsForAnyArgs(updated); + sutProvider.GetDependency() + .GetByIdAsync(existing.Id) + .Returns(existing); var expected = new OrganizationConnectionResponseModel(updated, typeof(BillingSyncConfig)); var result = await sutProvider.Sut.UpdateConnection(existing.Id, model); @@ -186,6 +201,13 @@ namespace Bit.Api.Test.Controllers .UpdateAsync(Arg.Is(AssertHelper.AssertPropertyEqual(model.ToData(updated.Id)))); } + [Theory] + [BitAutoData] + public async Task UpdateConnection_DoesNotExist_ThrowsNotFound(SutProvider sutProvider) + { + await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateConnection(Guid.NewGuid(), null)); + } + [Theory] [BitAutoData] public async Task GetConnection_RequiresOwnerPermissions(Guid connectionId, SutProvider sutProvider)