diff --git a/src/Api/AdminConsole/Controllers/OrganizationsController.cs b/src/Api/AdminConsole/Controllers/OrganizationsController.cs index 4aa4bdf475c3..f73347629b75 100644 --- a/src/Api/AdminConsole/Controllers/OrganizationsController.cs +++ b/src/Api/AdminConsole/Controllers/OrganizationsController.cs @@ -407,17 +407,14 @@ public async Task ApiKey(string id, [FromBody] Organization throw new UnauthorizedAccessException(); } - if (model.Type != OrganizationApiKeyType.Scim - && !await _userService.VerifySecretAsync(user, model.Secret)) + if (!await _userService.VerifySecretAsync(user, model.Secret)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); } - else - { - var response = new ApiKeyResponseModel(organizationApiKey); - return response; - } + + var response = new ApiKeyResponseModel(organizationApiKey); + return response; } [HttpGet("{id}/api-key-information/{type?}")] @@ -460,18 +457,15 @@ public async Task RotateApiKey(string id, [FromBody] Organi throw new UnauthorizedAccessException(); } - if (model.Type != OrganizationApiKeyType.Scim - && !await _userService.VerifySecretAsync(user, model.Secret)) + if (!await _userService.VerifySecretAsync(user, model.Secret)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); } - else - { - await _rotateOrganizationApiKeyCommand.RotateApiKeyAsync(organizationApiKey); - var response = new ApiKeyResponseModel(organizationApiKey); - return response; - } + + await _rotateOrganizationApiKeyCommand.RotateApiKeyAsync(organizationApiKey); + var response = new ApiKeyResponseModel(organizationApiKey); + return response; } private async Task HasApiKeyAccessAsync(Guid orgId, OrganizationApiKeyType? type) diff --git a/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs b/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs index cc09e9e0a055..3c43f0a80b8b 100644 --- a/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs +++ b/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs @@ -1,5 +1,6 @@ using System.Security.Claims; using Bit.Api.AdminConsole.Controllers; +using Bit.Api.AdminConsole.Models.Request.Organizations; using Bit.Api.Auth.Models.Request.Accounts; using Bit.Api.Models.Request.Organizations; using Bit.Core; @@ -8,6 +9,7 @@ using Bit.Core.AdminConsole.Enums.Provider; using Bit.Core.AdminConsole.Models.Business; using Bit.Core.AdminConsole.Models.Data.Organizations.Policies; +using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.Organizations.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.Policies; @@ -257,4 +259,113 @@ await sutProvider.GetDependency() s.LimitItemDeletion == model.LimitItemDeletion && s.AllowAdminAccessToAllCollectionItems == model.AllowAdminAccessToAllCollectionItems)); } + + [Theory, BitAutoData] + public async Task ApiKey_ScimType_InvalidSecret_ThrowsBadRequest( + SutProvider sutProvider, + Organization organization, + OrganizationApiKey organizationApiKey, + User user) + { + organization.PlanType = PlanType.EnterpriseAnnually; + var model = new OrganizationApiKeyRequestModel + { + Type = OrganizationApiKeyType.Scim, + MasterPasswordHash = "invalid-hash" + }; + + sutProvider.GetDependency().ManageScim(organization.Id).Returns(true); + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency() + .GetOrganizationApiKeyAsync(organization.Id, OrganizationApiKeyType.Scim) + .Returns(organizationApiKey); + + var userService = sutProvider.GetDependency(); + userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); + userService.VerifySecretAsync(user, model.Secret).Returns(false); + + await Assert.ThrowsAsync( + () => sutProvider.Sut.ApiKey(organization.Id.ToString(), model)); + } + + [Theory, BitAutoData] + public async Task ApiKey_ScimType_ValidSecret_ReturnsApiKey( + SutProvider sutProvider, + Organization organization, + OrganizationApiKey organizationApiKey, + User user) + { + organization.PlanType = PlanType.EnterpriseAnnually; + var model = new OrganizationApiKeyRequestModel + { + Type = OrganizationApiKeyType.Scim, + MasterPasswordHash = "valid-hash" + }; + + sutProvider.GetDependency().ManageScim(organization.Id).Returns(true); + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency() + .GetOrganizationApiKeyAsync(organization.Id, OrganizationApiKeyType.Scim) + .Returns(organizationApiKey); + var userService = sutProvider.GetDependency(); + userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); + userService.VerifySecretAsync(user, model.Secret).Returns(true); + + var result = await sutProvider.Sut.ApiKey(organization.Id.ToString(), model); + + Assert.Equal(organizationApiKey.ApiKey, result.ApiKey); + } + + [Theory, BitAutoData] + public async Task RotateApiKey_ScimType_InvalidSecret_ThrowsBadRequest( + SutProvider sutProvider, + Organization organization, + OrganizationApiKey organizationApiKey, + User user) + { + var model = new OrganizationApiKeyRequestModel + { + Type = OrganizationApiKeyType.Scim, + MasterPasswordHash = "invalid-hash" + }; + + sutProvider.GetDependency().ManageScim(organization.Id).Returns(true); + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency() + .GetOrganizationApiKeyAsync(organization.Id, OrganizationApiKeyType.Scim) + .Returns(organizationApiKey); + var userService = sutProvider.GetDependency(); + userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); + userService.VerifySecretAsync(user, model.Secret).Returns(false); + + await Assert.ThrowsAsync( + () => sutProvider.Sut.RotateApiKey(organization.Id.ToString(), model)); + } + + [Theory, BitAutoData] + public async Task RotateApiKey_ScimType_ValidSecret_ReturnsApiKey( + SutProvider sutProvider, + Organization organization, + OrganizationApiKey organizationApiKey, + User user) + { + var model = new OrganizationApiKeyRequestModel + { + Type = OrganizationApiKeyType.Scim, + MasterPasswordHash = "valid-hash" + }; + + sutProvider.GetDependency().ManageScim(organization.Id).Returns(true); + sutProvider.GetDependency().GetByIdAsync(organization.Id).Returns(organization); + sutProvider.GetDependency() + .GetOrganizationApiKeyAsync(organization.Id, OrganizationApiKeyType.Scim) + .Returns(organizationApiKey); + var userService = sutProvider.GetDependency(); + userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); + userService.VerifySecretAsync(user, model.Secret).Returns(true); + + var result = await sutProvider.Sut.RotateApiKey(organization.Id.ToString(), model); + + Assert.Equal(organizationApiKey.ApiKey, result.ApiKey); + } }