1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

[SM-429] Add permission checks to access policy endpoints (#2628)

* Add permission checks to access policy endpoints

* Fix unit tests

* Add service account grant permission checks

* Add service account grant tests

* Add new endpoint unit tests

* Cleanup unit tests add integration tests

* User permission enum in create tests

* Swap to NotFoundException for access checks

* Add filter for potential grantees

* Add in AccessSecretsManager check and test it

* Add code review updates

* Code review updates

* Refactor potential grantees endpoint

* Code review updates
This commit is contained in:
Thomas Avery
2023-02-06 11:26:06 -06:00
committed by GitHub
parent 9110efa44e
commit cf669286ed
20 changed files with 1710 additions and 146 deletions

View File

@ -1,9 +1,11 @@
using System.Net.Http.Headers;
using System.Net;
using System.Net.Http.Headers;
using Bit.Api.IntegrationTest.Factories;
using Bit.Api.IntegrationTest.Helpers;
using Bit.Api.IntegrationTest.SecretsManager.Enums;
using Bit.Api.Models.Response;
using Bit.Api.SecretsManager.Models.Request;
using Bit.Api.SecretsManager.Models.Response;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.SecretsManager.Entities;
using Bit.Core.SecretsManager.Repositories;
using Bit.Test.Common.Helpers;
@ -13,16 +15,17 @@ namespace Bit.Api.IntegrationTest.SecretsManager.Controllers;
public class AccessPoliciesControllerTest : IClassFixture<ApiApplicationFactory>, IAsyncLifetime
{
private const string _mockEncryptedString =
"2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98sp4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=";
private readonly IAccessPolicyRepository _accessPolicyRepository;
private readonly HttpClient _client;
private readonly ApiApplicationFactory _factory;
private const string _mockEncryptedString = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98sp4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=";
private readonly IProjectRepository _projectRepository;
private readonly IServiceAccountRepository _serviceAccountRepository;
private Organization _organization = null!;
private string _email = null!;
private SecretsManagerOrganizationHelper _organizationHelper = null!;
public AccessPoliciesControllerTest(ApiApplicationFactory factory)
{
@ -35,46 +38,105 @@ public class AccessPoliciesControllerTest : IClassFixture<ApiApplicationFactory>
public async Task InitializeAsync()
{
var ownerEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com";
var tokens = await _factory.LoginWithNewAccount(ownerEmail);
var (organization, _) =
await OrganizationTestHelpers.SignUpAsync(_factory, ownerEmail: ownerEmail, billingEmail: ownerEmail);
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token);
_organization = organization;
_email = $"integration-test{Guid.NewGuid()}@bitwarden.com";
await _factory.LoginWithNewAccount(_email);
_organizationHelper = new SecretsManagerOrganizationHelper(_factory, _email);
}
public Task DisposeAsync() => Task.CompletedTask;
[Fact]
public async Task CreateProjectAccessPolicies()
public Task DisposeAsync()
{
var initialProject = await _projectRepository.CreateAsync(new Project
_client.Dispose();
return Task.CompletedTask;
}
private async Task LoginAsync(string email)
{
var tokens = await _factory.LoginAsync(email);
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token);
}
[Theory]
[InlineData(false, false)]
[InlineData(true, false)]
[InlineData(false, true)]
public async Task CreateProjectAccessPolicies_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets)
{
var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets);
await LoginAsync(_email);
var project = await _projectRepository.CreateAsync(new Project
{
OrganizationId = _organization.Id,
Name = _mockEncryptedString
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
var initialServiceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
{
OrganizationId = _organization.Id,
Name = _mockEncryptedString
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
var request = new AccessPoliciesCreateRequest
{
ServiceAccountAccessPolicyRequests = new List<AccessPolicyRequest>
{
new() { GranteeId = initialServiceAccount.Id, Read = true, Write = true }
}
new() { GranteeId = serviceAccount.Id, Read = true, Write = true },
},
};
var response = await _client.PostAsJsonAsync($"/projects/{initialProject.Id}/access-policies", request);
var response = await _client.PostAsJsonAsync($"/projects/{project.Id}/access-policies", request);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Theory]
[InlineData(PermissionType.RunAsAdmin)]
[InlineData(PermissionType.RunAsUserWithPermission)]
public async Task CreateProjectAccessPolicies(PermissionType permissionType)
{
var (org, _) = await _organizationHelper.Initialize(true, true);
await LoginAsync(_email);
var project = await _projectRepository.CreateAsync(new Project
{
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
if (permissionType == PermissionType.RunAsUserWithPermission)
{
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var accessPolicies = new List<BaseAccessPolicy>
{
new UserProjectAccessPolicy
{
GrantedProjectId = project.Id, OrganizationUserId = orgUser.Id, Read = true, Write = true,
},
};
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
}
var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
{
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
var request = new AccessPoliciesCreateRequest
{
ServiceAccountAccessPolicyRequests = new List<AccessPolicyRequest>
{
new() { GranteeId = serviceAccount.Id, Read = true, Write = true },
},
};
var response = await _client.PostAsJsonAsync($"/projects/{project.Id}/access-policies", request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<ProjectAccessPoliciesResponseModel>();
Assert.NotNull(result);
Assert.Equal(initialServiceAccount.Id, result!.ServiceAccountAccessPolicies.First().ServiceAccountId);
Assert.Equal(serviceAccount.Id, result!.ServiceAccountAccessPolicies.First().ServiceAccountId);
Assert.True(result.ServiceAccountAccessPolicies.First().Read);
Assert.True(result.ServiceAccountAccessPolicies.First().Write);
AssertHelper.AssertRecent(result.ServiceAccountAccessPolicies.First().RevisionDate);
@ -91,15 +153,103 @@ public class AccessPoliciesControllerTest : IClassFixture<ApiApplicationFactory>
}
[Fact]
public async Task UpdateAccessPolicy()
public async Task CreateProjectAccessPolicies_NoPermission()
{
var initData = await SetupAccessPolicyRequest();
// Create a new account as a user
var (org, _) = await _organizationHelper.Initialize(true, true);
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var project = await _projectRepository.CreateAsync(new Project
{
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
{
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
var request = new AccessPoliciesCreateRequest
{
ServiceAccountAccessPolicyRequests = new List<AccessPolicyRequest>
{
new() { GranteeId = serviceAccount.Id, Read = true, Write = true },
},
};
var response = await _client.PostAsJsonAsync($"/projects/{project.Id}/access-policies", request);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Theory]
[InlineData(false, false)]
[InlineData(true, false)]
[InlineData(false, true)]
public async Task UpdateAccessPolicy_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets)
{
var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets);
await LoginAsync(_email);
var initData = await SetupAccessPolicyRequest(org.Id);
const bool expectedRead = true;
const bool expectedWrite = false;
var request = new AccessPolicyUpdateRequest { Read = expectedRead, Write = expectedWrite };
var response = await _client.PutAsJsonAsync($"/access-policies/{initData.InitialAccessPolicyId}", request);
var response = await _client.PutAsJsonAsync($"/access-policies/{initData.AccessPolicyId}", request);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Fact]
public async Task UpdateAccessPolicy_NoPermission()
{
// Create a new account as a user
var (org, _) = await _organizationHelper.Initialize(true, true);
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var initData = await SetupAccessPolicyRequest(orgUser.OrganizationId);
const bool expectedRead = true;
const bool expectedWrite = false;
var request = new AccessPolicyUpdateRequest { Read = expectedRead, Write = expectedWrite };
var response = await _client.PutAsJsonAsync($"/access-policies/{initData.AccessPolicyId}", request);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Theory]
[InlineData(PermissionType.RunAsAdmin)]
[InlineData(PermissionType.RunAsUserWithPermission)]
public async Task UpdateAccessPolicy(PermissionType permissionType)
{
var (org, _) = await _organizationHelper.Initialize(true, true);
await LoginAsync(_email);
var initData = await SetupAccessPolicyRequest(org.Id);
if (permissionType == PermissionType.RunAsUserWithPermission)
{
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var accessPolicies = new List<BaseAccessPolicy>
{
new UserProjectAccessPolicy
{
GrantedProjectId = initData.ProjectId, OrganizationUserId = orgUser.Id, Read = true, Write = true,
},
};
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
}
const bool expectedRead = true;
const bool expectedWrite = false;
var request = new AccessPolicyUpdateRequest { Read = expectedRead, Write = expectedWrite };
var response = await _client.PutAsJsonAsync($"/access-policies/{initData.AccessPolicyId}", request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<ServiceAccountProjectAccessPolicyResponseModel>();
@ -116,29 +266,78 @@ public class AccessPoliciesControllerTest : IClassFixture<ApiApplicationFactory>
AssertHelper.AssertRecent(updatedAccessPolicy.RevisionDate);
}
[Theory]
[InlineData(false, false)]
[InlineData(true, false)]
[InlineData(false, true)]
public async Task DeleteAccessPolicy_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets)
{
var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets);
await LoginAsync(_email);
var initData = await SetupAccessPolicyRequest(org.Id);
var response = await _client.DeleteAsync($"/access-policies/{initData.AccessPolicyId}");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Fact]
public async Task DeleteAccessPolicy()
public async Task DeleteAccessPolicy_NoPermission()
{
var initData = await SetupAccessPolicyRequest();
// Create a new account as a user
var (org, _) = await _organizationHelper.Initialize(true, true);
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var response = await _client.DeleteAsync($"/access-policies/{initData.InitialAccessPolicyId}");
var initData = await SetupAccessPolicyRequest(orgUser.OrganizationId);
var response = await _client.DeleteAsync($"/access-policies/{initData.AccessPolicyId}");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Theory]
[InlineData(PermissionType.RunAsAdmin)]
[InlineData(PermissionType.RunAsUserWithPermission)]
public async Task DeleteAccessPolicy(PermissionType permissionType)
{
var (org, _) = await _organizationHelper.Initialize(true, true);
await LoginAsync(_email);
var initData = await SetupAccessPolicyRequest(org.Id);
if (permissionType == PermissionType.RunAsUserWithPermission)
{
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var accessPolicies = new List<BaseAccessPolicy>
{
new UserProjectAccessPolicy
{
GrantedProjectId = initData.ProjectId, OrganizationUserId = orgUser.Id, Read = true, Write = true,
},
};
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
}
var response = await _client.DeleteAsync($"/access-policies/{initData.AccessPolicyId}");
response.EnsureSuccessStatusCode();
var test = await _accessPolicyRepository.GetByIdAsync(initData.InitialAccessPolicyId);
var test = await _accessPolicyRepository.GetByIdAsync(initData.AccessPolicyId);
Assert.Null(test);
}
[Fact]
public async Task GetProjectAccessPolicies_ReturnsEmpty()
{
var initialProject = await _projectRepository.CreateAsync(new Project
var (org, _) = await _organizationHelper.Initialize(true, true);
await LoginAsync(_email);
var project = await _projectRepository.CreateAsync(new Project
{
OrganizationId = _organization.Id,
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
var response = await _client.GetAsync($"/projects/{initialProject.Id}/access-policies");
var response = await _client.GetAsync($"/projects/{project.Id}/access-policies");
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<ProjectAccessPoliciesResponseModel>();
@ -149,12 +348,59 @@ public class AccessPoliciesControllerTest : IClassFixture<ApiApplicationFactory>
Assert.Empty(result!.ServiceAccountAccessPolicies);
}
[Fact]
public async Task GetProjectAccessPolicies()
[Theory]
[InlineData(false, false)]
[InlineData(true, false)]
[InlineData(false, true)]
public async Task GetProjectAccessPolicies_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets)
{
var initData = await SetupAccessPolicyRequest();
var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets);
await LoginAsync(_email);
var initData = await SetupAccessPolicyRequest(org.Id);
var response = await _client.GetAsync($"/projects/{initData.InitialProjectId}/access-policies");
var response = await _client.GetAsync($"/projects/{initData.ProjectId}/access-policies");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Fact]
public async Task GetProjectAccessPolicies_NoPermission()
{
// Create a new account as a user
var (org, _) = await _organizationHelper.Initialize(true, true);
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var initData = await SetupAccessPolicyRequest(orgUser.OrganizationId);
var response = await _client.GetAsync($"/projects/{initData.ProjectId}/access-policies");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Theory]
[InlineData(PermissionType.RunAsAdmin)]
[InlineData(PermissionType.RunAsUserWithPermission)]
public async Task GetProjectAccessPolicies(PermissionType permissionType)
{
var (org, _) = await _organizationHelper.Initialize(true, true);
await LoginAsync(_email);
var initData = await SetupAccessPolicyRequest(org.Id);
if (permissionType == PermissionType.RunAsUserWithPermission)
{
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var accessPolicies = new List<BaseAccessPolicy>
{
new UserProjectAccessPolicy
{
GrantedProjectId = initData.ProjectId, OrganizationUserId = orgUser.Id, Read = true, Write = true,
},
};
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
}
var response = await _client.GetAsync($"/projects/{initData.ProjectId}/access-policies");
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<ProjectAccessPoliciesResponseModel>();
@ -163,44 +409,166 @@ public class AccessPoliciesControllerTest : IClassFixture<ApiApplicationFactory>
Assert.Single(result!.ServiceAccountAccessPolicies);
}
private async Task<RequestSetupData> SetupAccessPolicyRequest()
[Theory]
[InlineData(false, false)]
[InlineData(true, false)]
[InlineData(false, true)]
public async Task GetPeoplePotentialGrantees_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets)
{
var initialProject = await _projectRepository.CreateAsync(new Project
var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets);
await LoginAsync(_email);
var response =
await _client.GetAsync(
$"/organizations/{org.Id}/access-policies/people/potential-grantees");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Theory]
[InlineData(PermissionType.RunAsAdmin)]
[InlineData(PermissionType.RunAsUserWithPermission)]
public async Task GetPeoplePotentialGrantees_Success(PermissionType permissionType)
{
var (org, _) = await _organizationHelper.Initialize(true, true);
await LoginAsync(_email);
if (permissionType == PermissionType.RunAsUserWithPermission)
{
OrganizationId = _organization.Id,
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
}
var response =
await _client.GetAsync(
$"/organizations/{org.Id}/access-policies/people/potential-grantees");
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<ListResponseModel<PotentialGranteeResponseModel>>();
Assert.NotNull(result?.Data);
Assert.NotEmpty(result!.Data);
}
[Theory]
[InlineData(false, false)]
[InlineData(true, false)]
[InlineData(false, true)]
public async Task GetServiceAccountPotentialGrantees_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets)
{
var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets);
await LoginAsync(_email);
var response =
await _client.GetAsync(
$"/organizations/{org.Id}/access-policies/service-accounts/potential-grantees");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Fact]
public async Task GetServiceAccountPotentialGrantees_OnlyReturnsServiceAccountsWithWriteAccess()
{
// Create a new account as a user
var (org, _) = await _organizationHelper.Initialize(true, true);
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
{
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
var initialServiceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
var response =
await _client.GetAsync(
$"/organizations/{org.Id}/access-policies/service-accounts/potential-grantees");
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<ListResponseModel<PotentialGranteeResponseModel>>();
Assert.NotNull(result?.Data);
Assert.Empty(result!.Data);
}
[Theory]
[InlineData(PermissionType.RunAsAdmin)]
[InlineData(PermissionType.RunAsUserWithPermission)]
public async Task GetServiceAccountsPotentialGrantees_Success(PermissionType permissionType)
{
var (org, _) = await _organizationHelper.Initialize(true, true);
await LoginAsync(_email);
var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
{
OrganizationId = _organization.Id,
OrganizationId = org.Id,
Name = _mockEncryptedString,
});
var initialAccessPolicy = await _accessPolicyRepository.CreateManyAsync(
if (permissionType == PermissionType.RunAsUserWithPermission)
{
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
await LoginAsync(email);
await _accessPolicyRepository.CreateManyAsync(
new List<BaseAccessPolicy>
{
new UserServiceAccountAccessPolicy
{
GrantedServiceAccountId = serviceAccount.Id,
OrganizationUserId = orgUser.Id,
Read = true,
Write = true,
},
});
}
var response =
await _client.GetAsync(
$"/organizations/{org.Id}/access-policies/service-accounts/potential-grantees");
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<ListResponseModel<PotentialGranteeResponseModel>>();
Assert.NotNull(result?.Data);
Assert.NotEmpty(result!.Data);
Assert.Equal(serviceAccount.Id.ToString(), result!.Data.First(x => x.Id == serviceAccount.Id.ToString()).Id);
}
private async Task<RequestSetupData> SetupAccessPolicyRequest(Guid organizationId)
{
var project = await _projectRepository.CreateAsync(new Project
{
OrganizationId = organizationId,
Name = _mockEncryptedString,
});
var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount
{
OrganizationId = organizationId,
Name = _mockEncryptedString,
});
var accessPolicy = await _accessPolicyRepository.CreateManyAsync(
new List<BaseAccessPolicy>
{
new ServiceAccountProjectAccessPolicy
{
Read = true,
Write = true,
ServiceAccountId = initialServiceAccount.Id,
GrantedProjectId = initialProject.Id,
}
Read = true, Write = true, ServiceAccountId = serviceAccount.Id, GrantedProjectId = project.Id,
},
});
return new RequestSetupData
{
InitialProjectId = initialProject.Id,
InitialServiceAccountId = initialServiceAccount.Id,
InitialAccessPolicyId = initialAccessPolicy.First().Id,
ProjectId = project.Id,
ServiceAccountId = serviceAccount.Id,
AccessPolicyId = accessPolicy.First().Id,
};
}
private class RequestSetupData
{
public Guid InitialProjectId { get; set; }
public Guid InitialAccessPolicyId { get; set; }
public Guid InitialServiceAccountId { get; set; }
public Guid ProjectId { get; set; }
public Guid AccessPolicyId { get; set; }
public Guid ServiceAccountId { get; set; }
}
}

View File

@ -0,0 +1,7 @@
namespace Bit.Api.IntegrationTest.SecretsManager.Enums;
public enum PermissionType
{
RunAsAdmin,
RunAsUserWithPermission,
}

View File

@ -1,8 +1,15 @@
using Bit.Api.SecretsManager.Controllers;
using Bit.Api.SecretsManager.Models.Request;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.SecretsManager.Commands.AccessPolicies.Interfaces;
using Bit.Core.SecretsManager.Entities;
using Bit.Core.SecretsManager.Repositories;
using Bit.Core.Services;
using Bit.Core.Test.SecretsManager.AutoFixture.ProjectsFixture;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@ -14,14 +21,64 @@ namespace Bit.Api.Test.SecretsManager.Controllers;
[ControllerCustomize(typeof(AccessPoliciesController))]
[SutProviderCustomize]
[ProjectCustomize]
[JsonDocumentCustomize]
public class AccessPoliciesControllerTests
{
[Theory]
[BitAutoData]
public async void GetAccessPoliciesByProject_ReturnsEmptyList(SutProvider<AccessPoliciesController> sutProvider,
Guid id)
public enum PermissionType
{
RunAsAdmin,
RunAsUserWithPermission,
}
private static void SetupAdmin(SutProvider<AccessPoliciesController> sutProvider, Project data)
{
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(default).ReturnsForAnyArgs(data);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(true);
}
private static void SetupUserWithPermission(SutProvider<AccessPoliciesController> sutProvider, Project data)
{
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(default).ReturnsForAnyArgs(data);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(false);
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(default, default)
.ReturnsForAnyArgs(true);
}
private static void SetupUserWithoutPermission(SutProvider<AccessPoliciesController> sutProvider, Project data)
{
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(default).ReturnsForAnyArgs(data);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(false);
sutProvider.GetDependency<ICurrentContext>().OrganizationUser(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(default, default)
.ReturnsForAnyArgs(false);
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async void GetAccessPoliciesByProject_ReturnsEmptyList(
PermissionType permissionType,
SutProvider<AccessPoliciesController> sutProvider,
Guid id, Project data)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
SetupAdmin(sutProvider, data);
break;
case PermissionType.RunAsUserWithPermission:
SetupUserWithPermission(sutProvider, data);
break;
}
var result = await sutProvider.Sut.GetProjectAccessPoliciesAsync(id);
await sutProvider.GetDependency<IAccessPolicyRepository>().Received(1)
@ -34,9 +91,39 @@ public class AccessPoliciesControllerTests
[Theory]
[BitAutoData]
public async void GetAccessPoliciesByProject_Success(SutProvider<AccessPoliciesController> sutProvider, Guid id,
public async void GetAccessPoliciesByProject_UserWithoutPermission_Throws(
SutProvider<AccessPoliciesController> sutProvider,
Guid id,
Project data)
{
SetupUserWithoutPermission(sutProvider, data);
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetProjectAccessPoliciesAsync(id));
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs()
.GetManyByGrantedProjectIdAsync(Arg.Any<Guid>());
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async void GetAccessPoliciesByProject_Admin_Success(
PermissionType permissionType,
SutProvider<AccessPoliciesController> sutProvider,
Guid id,
Project data,
UserProjectAccessPolicy resultAccessPolicy)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
SetupAdmin(sutProvider, data);
break;
case PermissionType.RunAsUserWithPermission:
SetupUserWithPermission(sutProvider, data);
break;
}
sutProvider.GetDependency<IAccessPolicyRepository>().GetManyByGrantedProjectIdAsync(default)
.ReturnsForAnyArgs(new List<BaseAccessPolicy> { resultAccessPolicy });
@ -52,36 +139,244 @@ public class AccessPoliciesControllerTests
[Theory]
[BitAutoData]
public async void CreateAccessPolicies_Success(SutProvider<AccessPoliciesController> sutProvider, Guid id,
UserProjectAccessPolicy data, AccessPoliciesCreateRequest request)
public async void GetAccessPoliciesByProject_ProjectsExist_UserWithoutPermission_Throws(
SutProvider<AccessPoliciesController> sutProvider,
Guid id,
Project data,
UserProjectAccessPolicy resultAccessPolicy)
{
sutProvider.GetDependency<ICreateAccessPoliciesCommand>().CreateAsync(default)
.ReturnsForAnyArgs(new List<BaseAccessPolicy> { data });
var result = await sutProvider.Sut.CreateProjectAccessPoliciesAsync(id, request);
await sutProvider.GetDependency<ICreateAccessPoliciesCommand>().Received(1)
.CreateAsync(Arg.Any<List<BaseAccessPolicy>>());
}
SetupUserWithoutPermission(sutProvider, data);
sutProvider.GetDependency<IAccessPolicyRepository>().GetManyByGrantedProjectIdAsync(default)
.ReturnsForAnyArgs(new List<BaseAccessPolicy> { resultAccessPolicy });
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetProjectAccessPoliciesAsync(id));
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs()
.GetManyByGrantedProjectIdAsync(Arg.Any<Guid>());
}
[Theory]
[BitAutoData]
public async void UpdateAccessPolicies_Success(SutProvider<AccessPoliciesController> sutProvider, Guid id,
UserProjectAccessPolicy data, AccessPolicyUpdateRequest request)
public async void CreateAccessPolicies_Success(
SutProvider<AccessPoliciesController> sutProvider,
Guid id,
UserProjectAccessPolicy data,
AccessPoliciesCreateRequest request)
{
sutProvider.GetDependency<IUpdateAccessPolicyCommand>().UpdateAsync(default, default, default)
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
sutProvider.GetDependency<ICreateAccessPoliciesCommand>().CreateForProjectAsync(default, default, default)
.ReturnsForAnyArgs(new List<BaseAccessPolicy> { data });
await sutProvider.Sut.CreateProjectAccessPoliciesAsync(id, request);
await sutProvider.GetDependency<ICreateAccessPoliciesCommand>().Received(1)
.CreateForProjectAsync(Arg.Any<Guid>(), Arg.Any<List<BaseAccessPolicy>>(), Arg.Any<Guid>());
}
[Theory]
[BitAutoData]
public async void UpdateAccessPolicies_Success(
SutProvider<AccessPoliciesController> sutProvider,
Guid id,
UserProjectAccessPolicy data,
AccessPolicyUpdateRequest request)
{
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
sutProvider.GetDependency<IUpdateAccessPolicyCommand>().UpdateAsync(default, default, default, default)
.ReturnsForAnyArgs(data);
var result = await sutProvider.Sut.UpdateAccessPolicyAsync(id, request);
await sutProvider.Sut.UpdateAccessPolicyAsync(id, request);
await sutProvider.GetDependency<IUpdateAccessPolicyCommand>().Received(1)
.UpdateAsync(Arg.Any<Guid>(), Arg.Is(request.Read), Arg.Is(request.Write));
.UpdateAsync(Arg.Any<Guid>(), Arg.Is(request.Read), Arg.Is(request.Write), Arg.Any<Guid>());
}
[Theory]
[BitAutoData]
public async void DeleteAccessPolicies_Success(SutProvider<AccessPoliciesController> sutProvider, Guid id)
{
sutProvider.GetDependency<IDeleteAccessPolicyCommand>().DeleteAsync(default).ReturnsNull();
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
sutProvider.GetDependency<IDeleteAccessPolicyCommand>().DeleteAsync(default, default).ReturnsNull();
await sutProvider.Sut.DeleteAccessPolicyAsync(id);
await sutProvider.GetDependency<IDeleteAccessPolicyCommand>().Received(1)
.DeleteAsync(Arg.Any<Guid>());
.DeleteAsync(Arg.Any<Guid>(), Arg.Any<Guid>());
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async void GetPeoplePotentialGranteesAsync_ReturnsEmptyList(
PermissionType permissionType,
SutProvider<AccessPoliciesController> sutProvider,
Guid id)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(true);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
break;
case PermissionType.RunAsUserWithPermission:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(false);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
break;
}
var result = await sutProvider.Sut.GetPeoplePotentialGranteesAsync(id);
await sutProvider.GetDependency<IGroupRepository>().Received(1)
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)));
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
.GetManyDetailsByOrganizationAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)));
Assert.Empty(result.Data);
}
[Theory]
[BitAutoData]
public async void GetPeoplePotentialGranteesAsync_UserWithoutPermission_Throws(
SutProvider<AccessPoliciesController> sutProvider,
Guid id)
{
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(false);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(false);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetPeoplePotentialGranteesAsync(id));
await sutProvider.GetDependency<IGroupRepository>().DidNotReceiveWithAnyArgs()
.GetManyByOrganizationIdAsync(Arg.Any<Guid>());
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
.GetManyDetailsByOrganizationAsync(Arg.Any<Guid>());
await sutProvider.GetDependency<IServiceAccountRepository>().DidNotReceiveWithAnyArgs()
.GetManyByOrganizationIdWriteAccessAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), Arg.Any<AccessClientType>());
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async void GetPeoplePotentialGranteesAsync_Success(
PermissionType permissionType,
SutProvider<AccessPoliciesController> sutProvider,
Guid id,
Group mockGroup)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(true);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
break;
case PermissionType.RunAsUserWithPermission:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(false);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
break;
}
sutProvider.GetDependency<IGroupRepository>().GetManyByOrganizationIdAsync(default)
.ReturnsForAnyArgs(new List<Group> { mockGroup });
var result = await sutProvider.Sut.GetPeoplePotentialGranteesAsync(id);
await sutProvider.GetDependency<IGroupRepository>().Received(1)
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)));
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
.GetManyDetailsByOrganizationAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)));
Assert.NotEmpty(result.Data);
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async void GetServiceAccountsPotentialGranteesAsync_ReturnsEmptyList(
PermissionType permissionType,
SutProvider<AccessPoliciesController> sutProvider,
Guid id)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(true);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
break;
case PermissionType.RunAsUserWithPermission:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(false);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
break;
}
var result = await sutProvider.Sut.GetServiceAccountsPotentialGranteesAsync(id);
await sutProvider.GetDependency<IServiceAccountRepository>().Received(1)
.GetManyByOrganizationIdWriteAccessAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)),
Arg.Is(AssertHelper.AssertPropertyEqual(id)),
Arg.Any<AccessClientType>());
Assert.Empty(result.Data);
}
[Theory]
[BitAutoData]
public async void GetServiceAccountsPotentialGranteesAsync_UserWithoutPermission_Throws(
SutProvider<AccessPoliciesController> sutProvider,
Guid id)
{
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(false);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(false);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetServiceAccountsPotentialGranteesAsync(id));
await sutProvider.GetDependency<IServiceAccountRepository>().DidNotReceiveWithAnyArgs()
.GetManyByOrganizationIdWriteAccessAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), Arg.Any<AccessClientType>());
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async void GetServiceAccountsPotentialGranteesAsync_Success(
PermissionType permissionType,
SutProvider<AccessPoliciesController> sutProvider,
Guid id,
ServiceAccount mockServiceAccount)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(true);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
break;
case PermissionType.RunAsUserWithPermission:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(id).Returns(false);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
break;
}
sutProvider.GetDependency<IServiceAccountRepository>().GetManyByOrganizationIdWriteAccessAsync(default, default, default)
.ReturnsForAnyArgs(new List<ServiceAccount> { mockServiceAccount });
var result = await sutProvider.Sut.GetServiceAccountsPotentialGranteesAsync(id);
await sutProvider.GetDependency<IServiceAccountRepository>().Received(1)
.GetManyByOrganizationIdWriteAccessAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)),
Arg.Is(AssertHelper.AssertPropertyEqual(id)),
Arg.Any<AccessClientType>());
Assert.NotEmpty(result.Data);
}
}