mirror of
https://github.com/bitwarden/server.git
synced 2025-07-01 16:12:49 -05:00
[SM-394] Secrets Manager (#2164)
Long lived feature branch for Secrets Manager Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Co-authored-by: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Co-authored-by: CarleyDiaz-Bitwarden <103955722+CarleyDiaz-Bitwarden@users.noreply.github.com> Co-authored-by: Thomas Avery <tavery@bitwarden.com> Co-authored-by: Colton Hurst <colton@coltonhurst.com>
This commit is contained in:
@ -23,6 +23,7 @@
|
||||
<ProjectReference Include="..\..\src\Api\Api.csproj" />
|
||||
<ProjectReference Include="..\..\src\Core\Core.csproj" />
|
||||
<ProjectReference Include="..\Common\Common.csproj" />
|
||||
<ProjectReference Include="..\Core.Test\Core.Test.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
42
test/Api.Test/Controllers/ProjectsControllerTests.cs
Normal file
42
test/Api.Test/Controllers/ProjectsControllerTests.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using Bit.Api.Controllers;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.SecretManagerFeatures.Projects.Interfaces;
|
||||
using Bit.Core.Test.AutoFixture.ProjectsFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(ProjectsController))]
|
||||
[SutProviderCustomize]
|
||||
[ProjectCustomize]
|
||||
[JsonDocumentCustomize]
|
||||
public class ProjectsControllerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BulkDeleteProjects_Success(SutProvider<ProjectsController> sutProvider, List<Project> data)
|
||||
{
|
||||
var ids = data.Select(project => project.Id).ToList();
|
||||
var mockResult = new List<Tuple<Project, string>>();
|
||||
foreach (var project in data)
|
||||
{
|
||||
mockResult.Add(new Tuple<Project, string>(project, ""));
|
||||
}
|
||||
sutProvider.GetDependency<IDeleteProjectCommand>().DeleteProjects(ids).ReturnsForAnyArgs(mockResult);
|
||||
|
||||
var results = await sutProvider.Sut.BulkDeleteProjectsAsync(ids);
|
||||
await sutProvider.GetDependency<IDeleteProjectCommand>().Received(1)
|
||||
.DeleteProjects(Arg.Is(ids));
|
||||
Assert.Equal(data.Count, results.Data.Count());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BulkDeleteProjects_NoGuids_ThrowsArgumentNullException(SutProvider<ProjectsController> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(() => sutProvider.Sut.BulkDeleteProjectsAsync(new List<Guid>()));
|
||||
}
|
||||
}
|
114
test/Api.Test/Controllers/SecretsControllerTests.cs
Normal file
114
test/Api.Test/Controllers/SecretsControllerTests.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using Bit.Api.Controllers;
|
||||
using Bit.Api.SecretManagerFeatures.Models.Request;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretManagerFeatures.Secrets.Interfaces;
|
||||
using Bit.Core.Test.AutoFixture.SecretsFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(SecretsController))]
|
||||
[SutProviderCustomize]
|
||||
[JsonDocumentCustomize]
|
||||
[SecretCustomize]
|
||||
public class SecretsControllerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetSecretsByOrganization_ReturnsEmptyList(SutProvider<SecretsController> sutProvider, Guid id)
|
||||
{
|
||||
var result = await sutProvider.Sut.GetSecretsByOrganizationAsync(id);
|
||||
|
||||
await sutProvider.GetDependency<ISecretRepository>().Received(1)
|
||||
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)));
|
||||
|
||||
Assert.Empty(result.Secrets);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetSecret_NotFound(SutProvider<SecretsController> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetSecretAsync(Guid.NewGuid()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetSecret_Success(SutProvider<SecretsController> sutProvider, Secret resultSecret)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(default).ReturnsForAnyArgs(resultSecret);
|
||||
|
||||
var result = await sutProvider.Sut.GetSecretAsync(resultSecret.Id);
|
||||
|
||||
await sutProvider.GetDependency<ISecretRepository>().Received(1)
|
||||
.GetByIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultSecret.Id)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetSecretsByOrganization_Success(SutProvider<SecretsController> sutProvider, Secret resultSecret)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetManyByOrganizationIdAsync(default).ReturnsForAnyArgs(new List<Secret>() { resultSecret });
|
||||
|
||||
var result = await sutProvider.Sut.GetSecretsByOrganizationAsync(resultSecret.OrganizationId);
|
||||
|
||||
await sutProvider.GetDependency<ISecretRepository>().Received(1)
|
||||
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultSecret.OrganizationId)));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void CreateSecret_Success(SutProvider<SecretsController> sutProvider, SecretCreateRequestModel data, Guid organizationId)
|
||||
{
|
||||
var resultSecret = data.ToSecret(organizationId);
|
||||
|
||||
sutProvider.GetDependency<ICreateSecretCommand>().CreateAsync(default).ReturnsForAnyArgs(resultSecret);
|
||||
|
||||
var result = await sutProvider.Sut.CreateSecretAsync(organizationId, data);
|
||||
await sutProvider.GetDependency<ICreateSecretCommand>().Received(1)
|
||||
.CreateAsync(Arg.Any<Secret>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void UpdateSecret_Success(SutProvider<SecretsController> sutProvider, SecretUpdateRequestModel data, Guid secretId)
|
||||
{
|
||||
var resultSecret = data.ToSecret(secretId);
|
||||
sutProvider.GetDependency<IUpdateSecretCommand>().UpdateAsync(default).ReturnsForAnyArgs(resultSecret);
|
||||
|
||||
var result = await sutProvider.Sut.UpdateSecretAsync(secretId, data);
|
||||
await sutProvider.GetDependency<IUpdateSecretCommand>().Received(1)
|
||||
.UpdateAsync(Arg.Any<Secret>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BulkDeleteSecret_Success(SutProvider<SecretsController> sutProvider, List<Secret> data)
|
||||
{
|
||||
var ids = data.Select(secret => secret.Id).ToList();
|
||||
var mockResult = new List<Tuple<Secret, string>>();
|
||||
foreach (var secret in data)
|
||||
{
|
||||
mockResult.Add(new Tuple<Secret, string>(secret, ""));
|
||||
}
|
||||
sutProvider.GetDependency<IDeleteSecretCommand>().DeleteSecrets(ids).ReturnsForAnyArgs(mockResult);
|
||||
|
||||
var results = await sutProvider.Sut.BulkDeleteAsync(ids);
|
||||
await sutProvider.GetDependency<IDeleteSecretCommand>().Received(1)
|
||||
.DeleteSecrets(Arg.Is(ids));
|
||||
Assert.Equal(data.Count, results.Data.Count());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BulkDeleteSecret_NoGuids_ThrowsArgumentNullException(SutProvider<SecretsController> sutProvider)
|
||||
{
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(() => sutProvider.Sut.BulkDeleteAsync(new List<Guid>()));
|
||||
}
|
||||
}
|
82
test/Api.Test/Controllers/ServiceAccountsControllerTests.cs
Normal file
82
test/Api.Test/Controllers/ServiceAccountsControllerTests.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using Bit.Api.Controllers;
|
||||
using Bit.Api.SecretManagerFeatures.Models.Request;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretManagerFeatures.AccessTokens.Interfaces;
|
||||
using Bit.Core.SecretManagerFeatures.ServiceAccounts.Interfaces;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.Controllers;
|
||||
|
||||
[ControllerCustomize(typeof(ServiceAccountsController))]
|
||||
[SutProviderCustomize]
|
||||
[JsonDocumentCustomize]
|
||||
public class ServiceAccountsControllerTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetServiceAccountsByOrganization_ReturnsEmptyList(SutProvider<ServiceAccountsController> sutProvider, Guid id)
|
||||
{
|
||||
var result = await sutProvider.Sut.GetServiceAccountsByOrganizationAsync(id);
|
||||
|
||||
await sutProvider.GetDependency<IServiceAccountRepository>().Received(1)
|
||||
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)));
|
||||
|
||||
Assert.Empty(result.Data);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetServiceAccountsByOrganization_Success(SutProvider<ServiceAccountsController> sutProvider, ServiceAccount resultServiceAccount)
|
||||
{
|
||||
sutProvider.GetDependency<IServiceAccountRepository>().GetManyByOrganizationIdAsync(default).ReturnsForAnyArgs(new List<ServiceAccount>() { resultServiceAccount });
|
||||
|
||||
var result = await sutProvider.Sut.GetServiceAccountsByOrganizationAsync(resultServiceAccount.OrganizationId);
|
||||
|
||||
await sutProvider.GetDependency<IServiceAccountRepository>().Received(1)
|
||||
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultServiceAccount.OrganizationId)));
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void CreateServiceAccount_Success(SutProvider<ServiceAccountsController> sutProvider, ServiceAccountCreateRequestModel data, Guid organizationId)
|
||||
{
|
||||
var resultServiceAccount = data.ToServiceAccount(organizationId);
|
||||
|
||||
sutProvider.GetDependency<ICreateServiceAccountCommand>().CreateAsync(default).ReturnsForAnyArgs(resultServiceAccount);
|
||||
|
||||
var result = await sutProvider.Sut.CreateServiceAccountAsync(organizationId, data);
|
||||
await sutProvider.GetDependency<ICreateServiceAccountCommand>().Received(1)
|
||||
.CreateAsync(Arg.Any<ServiceAccount>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void UpdateServiceAccount_Success(SutProvider<ServiceAccountsController> sutProvider, ServiceAccountUpdateRequestModel data, Guid serviceAccountId)
|
||||
{
|
||||
var resultServiceAccount = data.ToServiceAccount(serviceAccountId);
|
||||
sutProvider.GetDependency<IUpdateServiceAccountCommand>().UpdateAsync(default).ReturnsForAnyArgs(resultServiceAccount);
|
||||
|
||||
var result = await sutProvider.Sut.UpdateServiceAccountAsync(serviceAccountId, data);
|
||||
await sutProvider.GetDependency<IUpdateServiceAccountCommand>().Received(1)
|
||||
.UpdateAsync(Arg.Any<ServiceAccount>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void CreateAccessToken_Success(SutProvider<ServiceAccountsController> sutProvider, AccessTokenCreateRequestModel data, Guid serviceAccountId)
|
||||
{
|
||||
var resultAccessToken = data.ToApiKey(serviceAccountId);
|
||||
|
||||
sutProvider.GetDependency<ICreateAccessTokenCommand>().CreateAsync(default).ReturnsForAnyArgs(resultAccessToken);
|
||||
|
||||
var result = await sutProvider.Sut.CreateAccessTokenAsync(serviceAccountId, data);
|
||||
await sutProvider.GetDependency<ICreateAccessTokenCommand>().Received(1)
|
||||
.CreateAsync(Arg.Any<ApiKey>());
|
||||
}
|
||||
}
|
@ -658,6 +658,15 @@
|
||||
"Microsoft.Extensions.DependencyModel": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.12",
|
||||
"contentHash": "bdKnSz1w+WZz9QYWhs3wwGuMn4YssjdR+HOBpzChQ6C3+dblq4Pammm5fzugcPOhTgCiWftOT2jPOT5hEy4bYg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Data.SqlClient": "2.1.4",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.ApiDescription.Server": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.0",
|
||||
@ -1053,6 +1062,15 @@
|
||||
"System.Security.Cryptography.Pkcs": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Moq": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.17.2",
|
||||
"contentHash": "HytUPJ3/uks2UgJ9hIcyXm3YxpFAR4OJzbQwTHltbKGun3lFLhEHs97hiiPj1dY8jV/kasXeihTzDxct6Zf3iQ==",
|
||||
"dependencies": {
|
||||
"Castle.Core": "4.4.1",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"MySqlConnector": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.1.2",
|
||||
@ -3002,6 +3020,7 @@
|
||||
"dependencies": {
|
||||
"Azure.Messaging.EventGrid": "[4.10.0, )",
|
||||
"Commercial.Core": "[2022.12.0, )",
|
||||
"Commercial.Infrastructure.EntityFramework": "[2022.12.0, )",
|
||||
"Core": "[2022.12.0, )",
|
||||
"SharedWeb": "[2022.12.0, )",
|
||||
"Swashbuckle.AspNetCore": "[6.3.1, )"
|
||||
@ -3013,6 +3032,14 @@
|
||||
"Core": "[2022.12.0, )"
|
||||
}
|
||||
},
|
||||
"commercial.infrastructure.entityframework": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[11.0.0, )",
|
||||
"Core": "[2022.12.0, )",
|
||||
"Infrastructure.EntityFramework": "[2022.12.0, )"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
@ -3065,6 +3092,20 @@
|
||||
"YubicoDotNetClient": "[1.2.0, )"
|
||||
}
|
||||
},
|
||||
"core.test": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoFixture.AutoNSubstitute": "[4.17.0, )",
|
||||
"AutoFixture.Xunit2": "[4.17.0, )",
|
||||
"Common": "[2022.12.0, )",
|
||||
"Core": "[2022.12.0, )",
|
||||
"Kralizek.AutoFixture.Extensions.MockHttp": "[1.2.0, )",
|
||||
"Microsoft.NET.Test.Sdk": "[17.1.0, )",
|
||||
"Moq": "[4.17.2, )",
|
||||
"NSubstitute": "[4.3.0, )",
|
||||
"xunit": "[2.4.1, )"
|
||||
}
|
||||
},
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
@ -3078,6 +3119,7 @@
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[11.0.0, )",
|
||||
"Core": "[2022.12.0, )",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "[6.0.12, )",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "[6.0.12, )",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "[6.0.12, )",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "[6.0.8, )",
|
||||
"Pomelo.EntityFrameworkCore.MySql": "[6.0.2, )",
|
||||
|
Reference in New Issue
Block a user