mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 07:36:14 -05:00
SM-1146: Secrets Manager total counts (#4200)
* SM-1146: SM Organization Counts for Projects, Secrets, Machine Accounts * SM-1146: Project total counts * SM-1146: models object renames * SM-1146: Service Account total counts * SM-1146: Unit test coverage for counts controller * SM-1146: Counts controller simplification, UT update * SM-1146: Service Account total counts from Service Account auth user * SM-1146: Integration Tests for total counts controller * SM-1146: Explicitly denying access for Service Accounts * SM-1146: Fix broken ProjectsController integration test * SM-1146: Integration tests for counts controller * SM-1146: Explicitly denying access for Service Accounts cleanup * SM-1146: Test cleanup * SM-1146: PR review comments fix * SM-1146: People, Service Accounts positive count on write access * Update bitwarden_license/src/Commercial.Infrastructure.EntityFramework/SecretsManager/Repositories/ProjectRepository.cs Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
This commit is contained in:
@ -0,0 +1,212 @@
|
||||
#nullable enable
|
||||
using System.Security.Claims;
|
||||
using Bit.Api.SecretsManager.Controllers;
|
||||
using Bit.Api.SecretsManager.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
using Bit.Core.SecretsManager.Queries.Interfaces;
|
||||
using Bit.Core.SecretsManager.Repositories;
|
||||
using Bit.Core.Test.SecretsManager.AutoFixture.ProjectsFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.SecretsManager.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(CountsController))]
|
||||
[SutProviderCustomize]
|
||||
[ProjectCustomize]
|
||||
[JsonDocumentCustomize]
|
||||
public class CountsControllerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByOrganizationAsync_NoAccess_Throws(SutProvider<CountsController> sutProvider,
|
||||
Guid organizationId)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetByOrganizationAsync(organizationId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByOrganizationAsync_ServiceAccountAccess_Throws(SutProvider<CountsController> sutProvider,
|
||||
Guid organizationId, Guid userId)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IAccessClientQuery>()
|
||||
.GetAccessClientAsync(Arg.Any<ClaimsPrincipal>(), organizationId)
|
||||
.Returns((AccessClientType.ServiceAccount, userId));
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetByOrganizationAsync(organizationId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(AccessClientType.NoAccessCheck)]
|
||||
[BitAutoData(AccessClientType.User)]
|
||||
public async Task GetByOrganizationAsync_HasAccess_Success(AccessClientType accessClientType,
|
||||
SutProvider<CountsController> sutProvider, Guid organizationId, Guid userId,
|
||||
OrganizationCountsResponseModel expectedCountsResponseModel)
|
||||
{
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IAccessClientQuery>()
|
||||
.GetAccessClientAsync(Arg.Any<ClaimsPrincipal>(), organizationId).Returns((accessClientType, userId));
|
||||
|
||||
sutProvider.GetDependency<IProjectRepository>()
|
||||
.GetProjectCountByOrganizationIdAsync(organizationId, userId, accessClientType)
|
||||
.Returns(expectedCountsResponseModel.Projects);
|
||||
|
||||
sutProvider.GetDependency<ISecretRepository>()
|
||||
.GetSecretsCountByOrganizationIdAsync(organizationId, userId, accessClientType)
|
||||
.Returns(expectedCountsResponseModel.Secrets);
|
||||
|
||||
sutProvider.GetDependency<IServiceAccountRepository>()
|
||||
.GetServiceAccountCountByOrganizationIdAsync(organizationId, userId, accessClientType)
|
||||
.Returns(expectedCountsResponseModel.ServiceAccounts);
|
||||
|
||||
var response = await sutProvider.Sut.GetByOrganizationAsync(organizationId);
|
||||
|
||||
Assert.Equal(expectedCountsResponseModel.Projects, response.Projects);
|
||||
Assert.Equal(expectedCountsResponseModel.Secrets, response.Secrets);
|
||||
Assert.Equal(expectedCountsResponseModel.ServiceAccounts, response.ServiceAccounts);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByProjectAsync_ProjectNotFound_Throws(SutProvider<CountsController> sutProvider,
|
||||
Guid projectId)
|
||||
{
|
||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(projectId).Returns(default(Project));
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetByProjectAsync(projectId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByProjectAsync_NoAccess_Throws(SutProvider<CountsController> sutProvider, Project project)
|
||||
{
|
||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetByProjectAsync(project.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByProjectAsync_ServiceAccountAccess_Throws(SutProvider<CountsController> sutProvider,
|
||||
Guid userId, Project project)
|
||||
{
|
||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IAccessClientQuery>()
|
||||
.GetAccessClientAsync(Arg.Any<ClaimsPrincipal>(), project.OrganizationId)
|
||||
.Returns((AccessClientType.ServiceAccount, userId));
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetByProjectAsync(project.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(AccessClientType.NoAccessCheck)]
|
||||
[BitAutoData(AccessClientType.User)]
|
||||
public async Task GetByProjectAsync_HasAccess_Success(AccessClientType accessClientType,
|
||||
SutProvider<CountsController> sutProvider, Guid userId, Project project,
|
||||
ProjectCountsResponseModel expectedProjectCountsResponseModel)
|
||||
{
|
||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IAccessClientQuery>()
|
||||
.GetAccessClientAsync(Arg.Any<ClaimsPrincipal>(), project.OrganizationId)
|
||||
.Returns((accessClientType, userId));
|
||||
|
||||
sutProvider.GetDependency<IProjectRepository>()
|
||||
.GetProjectCountsByIdAsync(project.Id, userId, accessClientType)
|
||||
.Returns(new ProjectCounts
|
||||
{
|
||||
Secrets = expectedProjectCountsResponseModel.Secrets,
|
||||
People = expectedProjectCountsResponseModel.People,
|
||||
ServiceAccounts = expectedProjectCountsResponseModel.ServiceAccounts
|
||||
});
|
||||
|
||||
var response = await sutProvider.Sut.GetByProjectAsync(project.Id);
|
||||
|
||||
Assert.Equal(expectedProjectCountsResponseModel.Secrets, response.Secrets);
|
||||
Assert.Equal(expectedProjectCountsResponseModel.People, response.People);
|
||||
Assert.Equal(expectedProjectCountsResponseModel.ServiceAccounts, response.ServiceAccounts);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByServiceAccountAsync_ServiceAccountNotFound_Throws(SutProvider<CountsController> sutProvider,
|
||||
Guid serviceAccountId)
|
||||
{
|
||||
sutProvider.GetDependency<IServiceAccountRepository>().GetByIdAsync(serviceAccountId)
|
||||
.Returns(default(ServiceAccount));
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetByServiceAccountAsync(serviceAccountId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByServiceAccountAsync_NoAccess_Throws(SutProvider<CountsController> sutProvider,
|
||||
ServiceAccount serviceAccount)
|
||||
{
|
||||
sutProvider.GetDependency<IServiceAccountRepository>().GetByIdAsync(serviceAccount.Id)
|
||||
.Returns(serviceAccount);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(serviceAccount.OrganizationId).Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetByServiceAccountAsync(serviceAccount.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByServiceAccountAsync_ServiceAccountAccess_Throws(SutProvider<CountsController> sutProvider,
|
||||
Guid userId, ServiceAccount serviceAccount)
|
||||
{
|
||||
sutProvider.GetDependency<IServiceAccountRepository>().GetByIdAsync(serviceAccount.Id).Returns(serviceAccount);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(serviceAccount.OrganizationId).Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IAccessClientQuery>()
|
||||
.GetAccessClientAsync(Arg.Any<ClaimsPrincipal>(), serviceAccount.OrganizationId)
|
||||
.Returns((AccessClientType.ServiceAccount, userId));
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetByServiceAccountAsync(serviceAccount.Id));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(AccessClientType.NoAccessCheck)]
|
||||
[BitAutoData(AccessClientType.User)]
|
||||
public async Task GetByServiceAccountAsync_HasAccess_Success(AccessClientType accessClientType,
|
||||
SutProvider<CountsController> sutProvider, Guid userId, ServiceAccount serviceAccount,
|
||||
ServiceAccountCountsResponseModel expectedServiceAccountCountsResponseModel)
|
||||
{
|
||||
sutProvider.GetDependency<IServiceAccountRepository>().GetByIdAsync(serviceAccount.Id)
|
||||
.Returns(serviceAccount);
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(serviceAccount.OrganizationId).Returns(true);
|
||||
sutProvider.GetDependency<IAccessClientQuery>()
|
||||
.GetAccessClientAsync(Arg.Any<ClaimsPrincipal>(), serviceAccount.OrganizationId)
|
||||
.Returns((accessClientType, userId));
|
||||
|
||||
sutProvider.GetDependency<IServiceAccountRepository>()
|
||||
.GetServiceAccountCountsByIdAsync(serviceAccount.Id, userId, accessClientType)
|
||||
.Returns(new ServiceAccountCounts
|
||||
{
|
||||
Projects = expectedServiceAccountCountsResponseModel.Projects,
|
||||
People = expectedServiceAccountCountsResponseModel.People,
|
||||
AccessTokens = expectedServiceAccountCountsResponseModel.AccessTokens
|
||||
});
|
||||
|
||||
var response = await sutProvider.Sut.GetByServiceAccountAsync(serviceAccount.Id);
|
||||
|
||||
Assert.Equal(expectedServiceAccountCountsResponseModel.Projects, response.Projects);
|
||||
Assert.Equal(expectedServiceAccountCountsResponseModel.People, response.People);
|
||||
Assert.Equal(expectedServiceAccountCountsResponseModel.AccessTokens, response.AccessTokens);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user