1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-28 13:15:12 +01:00
bitwarden-server/test/Api.Test/SecretsManager/Controllers/CountsControllerTests.cs
Maciej Zieniuk 77f8cc58e8
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>
2024-08-08 15:12:52 +02:00

213 lines
9.8 KiB
C#

#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);
}
}