1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-01 08:02:49 -05:00

[SM-473] Access Policies - Service Accounts (#2658)

* Add service account access policy endpoints

* Add unit & integration tests for new endpoints

* Fix formatting on response models

* Cleanup unit tests
This commit is contained in:
Thomas Avery
2023-02-07 14:30:22 -06:00
committed by GitHub
parent cf669286ed
commit 1ee14d93e6
11 changed files with 1030 additions and 305 deletions

View File

@ -17,9 +17,127 @@ namespace Bit.Commercial.Core.Test.SecretsManager.AccessPolicies;
[ProjectCustomize]
public class CreateAccessPoliciesCommandTests
{
private static List<BaseAccessPolicy> MakeDuplicate(List<BaseAccessPolicy> data, AccessPolicyType accessPolicyType)
{
switch (accessPolicyType)
{
case AccessPolicyType.UserProjectAccessPolicy:
{
var mockAccessPolicy = new UserProjectAccessPolicy
{
OrganizationUserId = Guid.NewGuid(),
GrantedProjectId = Guid.NewGuid(),
};
data.Add(mockAccessPolicy);
// Add a duplicate policy
data.Add(mockAccessPolicy);
break;
}
case AccessPolicyType.GroupProjectAccessPolicy:
{
var mockAccessPolicy = new GroupProjectAccessPolicy
{
GroupId = Guid.NewGuid(),
GrantedProjectId = Guid.NewGuid(),
};
data.Add(mockAccessPolicy);
// Add a duplicate policy
data.Add(mockAccessPolicy);
break;
}
case AccessPolicyType.ServiceAccountProjectAccessPolicy:
{
var mockAccessPolicy = new ServiceAccountProjectAccessPolicy
{
ServiceAccountId = Guid.NewGuid(),
GrantedProjectId = Guid.NewGuid(),
};
data.Add(mockAccessPolicy);
// Add a duplicate policy
data.Add(mockAccessPolicy);
break;
}
case AccessPolicyType.UserServiceAccountAccessPolicy:
{
var mockAccessPolicy = new UserServiceAccountAccessPolicy
{
OrganizationUserId = Guid.NewGuid(),
GrantedServiceAccountId = Guid.NewGuid(),
};
data.Add(mockAccessPolicy);
// Add a duplicate policy
data.Add(mockAccessPolicy);
break;
}
case AccessPolicyType.GroupServiceAccountAccessPolicy:
{
var mockAccessPolicy = new GroupServiceAccountAccessPolicy
{
GroupId = Guid.NewGuid(),
GrantedServiceAccountId = Guid.NewGuid(),
};
data.Add(mockAccessPolicy);
// Add a duplicate policy
data.Add(mockAccessPolicy);
break;
}
}
return data;
}
private static void SetupAdmin(SutProvider<CreateAccessPoliciesCommand> sutProvider, Guid organizationId)
{
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(true);
}
private static void SetupUser(SutProvider<CreateAccessPoliciesCommand> sutProvider, Guid organizationId)
{
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
}
private static void SetupPermission(SutProvider<CreateAccessPoliciesCommand> sutProvider,
PermissionType permissionType, Project project, Guid userId)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
SetupAdmin(sutProvider, project.OrganizationId);
break;
case PermissionType.RunAsUserWithPermission:
SetupUser(sutProvider, project.OrganizationId);
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(project.Id, userId)
.Returns(true);
break;
}
}
private static void SetupPermission(SutProvider<CreateAccessPoliciesCommand> sutProvider,
PermissionType permissionType, ServiceAccount serviceAccount, Guid userId)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
SetupAdmin(sutProvider, serviceAccount.OrganizationId);
break;
case PermissionType.RunAsUserWithPermission:
SetupUser(sutProvider, serviceAccount.OrganizationId);
sutProvider.GetDependency<IServiceAccountRepository>()
.UserHasWriteAccessToServiceAccount(serviceAccount.Id, userId).Returns(true);
break;
}
}
[Theory]
[BitAutoData]
public async Task CreateAsync_SmNotEnabled_Throws(
public async Task CreateForProject_SmNotEnabled_Throws(
Guid userId,
Project project,
List<UserProjectAccessPolicy> userProjectAccessPolicies,
@ -42,7 +160,7 @@ public class CreateAccessPoliciesCommandTests
[Theory]
[BitAutoData]
public async Task CreateAsync_AlreadyExists_Throws_BadRequestException(
public async Task CreateForProject_AlreadyExists_Throws_BadRequestException(
Guid userId,
Project project,
List<UserProjectAccessPolicy> userProjectAccessPolicies,
@ -55,10 +173,8 @@ public class CreateAccessPoliciesCommandTests
data.AddRange(groupProjectAccessPolicies);
data.AddRange(serviceAccountProjectAccessPolicies);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(Arg.Any<Guid>()).Returns(true);
SetupAdmin(sutProvider, project.OrganizationId);
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(project.OrganizationId).Returns(true);
sutProvider.GetDependency<IAccessPolicyRepository>().AccessPolicyExists(Arg.Any<BaseAccessPolicy>())
.Returns(true);
@ -69,17 +185,13 @@ public class CreateAccessPoliciesCommandTests
}
[Theory]
[BitAutoData(true, false, false)]
[BitAutoData(false, true, false)]
[BitAutoData(true, true, false)]
[BitAutoData(false, false, true)]
[BitAutoData(true, false, true)]
[BitAutoData(false, true, true)]
[BitAutoData(true, true, true)]
public async Task CreateAsync_NotUnique_ThrowsException(
bool testUserPolicies,
bool testGroupPolicies,
bool testServiceAccountPolicies,
[BitAutoData(AccessPolicyType.UserProjectAccessPolicy)]
[BitAutoData(AccessPolicyType.GroupProjectAccessPolicy)]
[BitAutoData(AccessPolicyType.ServiceAccountProjectAccessPolicy)]
[BitAutoData(AccessPolicyType.UserServiceAccountAccessPolicy)]
[BitAutoData(AccessPolicyType.GroupServiceAccountAccessPolicy)]
public async Task CreateForProjectAsync_NotUnique_ThrowsException(
AccessPolicyType accessPolicyType,
Guid userId,
Project project,
List<UserProjectAccessPolicy> userProjectAccessPolicies,
@ -92,64 +204,24 @@ public class CreateAccessPoliciesCommandTests
data.AddRange(userProjectAccessPolicies);
data.AddRange(groupProjectAccessPolicies);
data.AddRange(serviceAccountProjectAccessPolicies);
data = MakeDuplicate(data, accessPolicyType);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(Arg.Any<Guid>()).Returns(true);
SetupAdmin(sutProvider, project.OrganizationId);
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(project.OrganizationId).Returns(true);
if (testUserPolicies)
{
var mockUserPolicy = new UserProjectAccessPolicy
{
OrganizationUserId = Guid.NewGuid(),
GrantedProjectId = Guid.NewGuid(),
};
data.Add(mockUserPolicy);
// Add a duplicate policy
data.Add(mockUserPolicy);
}
if (testGroupPolicies)
{
var mockGroupPolicy = new GroupProjectAccessPolicy
{
GroupId = Guid.NewGuid(),
GrantedProjectId = Guid.NewGuid(),
};
data.Add(mockGroupPolicy);
// Add a duplicate policy
data.Add(mockGroupPolicy);
}
if (testServiceAccountPolicies)
{
var mockServiceAccountPolicy = new ServiceAccountProjectAccessPolicy
{
ServiceAccountId = Guid.NewGuid(),
GrantedProjectId = Guid.NewGuid(),
};
data.Add(mockServiceAccountPolicy);
// Add a duplicate policy
data.Add(mockServiceAccountPolicy);
}
sutProvider.GetDependency<IAccessPolicyRepository>().AccessPolicyExists(Arg.Any<BaseAccessPolicy>())
.Returns(true);
await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.CreateForProjectAsync(project.Id, data, userId));
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs().CreateManyAsync(default);
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs()
.CreateManyAsync(Arg.Any<List<BaseAccessPolicy>>());
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async Task CreateAsync_Success(
public async Task CreateForProject_Success(
PermissionType permissionType,
Guid userId,
Project project,
@ -163,18 +235,8 @@ public class CreateAccessPoliciesCommandTests
data.AddRange(groupProjectAccessPolicies);
data.AddRange(serviceAccountProjectAccessPolicies);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(Arg.Any<Guid>()).Returns(true);
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
switch (permissionType)
{
case PermissionType.RunAsAdmin:
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(project.OrganizationId).Returns(true);
break;
case PermissionType.RunAsUserWithPermission:
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(project.Id, userId).Returns(true);
break;
}
SetupPermission(sutProvider, permissionType, project, userId);
await sutProvider.Sut.CreateForProjectAsync(project.Id, data, userId);
@ -184,7 +246,7 @@ public class CreateAccessPoliciesCommandTests
[Theory]
[BitAutoData]
public async Task CreateAsync_User_NoPermission(
public async Task CreateForProject_UserNoPermission_ThrowsNotFound(
Guid userId,
Project project,
List<UserProjectAccessPolicy> userProjectAccessPolicies,
@ -197,13 +259,148 @@ public class CreateAccessPoliciesCommandTests
data.AddRange(groupProjectAccessPolicies);
data.AddRange(serviceAccountProjectAccessPolicies);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(Arg.Any<Guid>()).Returns(true);
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
SetupUser(sutProvider, project.OrganizationId);
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(project.Id, userId).Returns(false);
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.CreateForProjectAsync(project.Id, data, userId));
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs().CreateManyAsync(default);
}
[Theory]
[BitAutoData]
public async Task CreateForServiceAccount_SmNotEnabled_Throws(
Guid userId,
ServiceAccount serviceAccount,
List<UserProjectAccessPolicy> userProjectAccessPolicies,
List<GroupProjectAccessPolicy> groupProjectAccessPolicies,
List<ServiceAccountProjectAccessPolicy> serviceAccountProjectAccessPolicies,
SutProvider<CreateAccessPoliciesCommand> sutProvider)
{
var data = new List<BaseAccessPolicy>();
data.AddRange(userProjectAccessPolicies);
data.AddRange(groupProjectAccessPolicies);
data.AddRange(serviceAccountProjectAccessPolicies);
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(Arg.Any<Guid>()).Returns(false);
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.CreateForServiceAccountAsync(serviceAccount.Id, data, userId));
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs()
.CreateManyAsync(Arg.Any<List<BaseAccessPolicy>>());
}
[Theory]
[BitAutoData]
public async Task CreateForServiceAccount_AlreadyExists_ThrowsBadRequestException(
Guid userId,
ServiceAccount serviceAccount,
List<UserProjectAccessPolicy> userProjectAccessPolicies,
List<GroupProjectAccessPolicy> groupProjectAccessPolicies,
List<ServiceAccountProjectAccessPolicy> serviceAccountProjectAccessPolicies,
SutProvider<CreateAccessPoliciesCommand> sutProvider)
{
var data = new List<BaseAccessPolicy>();
data.AddRange(userProjectAccessPolicies);
data.AddRange(groupProjectAccessPolicies);
data.AddRange(serviceAccountProjectAccessPolicies);
SetupAdmin(sutProvider, serviceAccount.OrganizationId);
sutProvider.GetDependency<IServiceAccountRepository>().GetByIdAsync(serviceAccount.Id).Returns(serviceAccount);
sutProvider.GetDependency<IAccessPolicyRepository>().AccessPolicyExists(Arg.Any<BaseAccessPolicy>())
.Returns(true);
await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.CreateForServiceAccountAsync(serviceAccount.Id, data, userId));
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs()
.CreateManyAsync(Arg.Any<List<BaseAccessPolicy>>());
}
[Theory]
[BitAutoData(AccessPolicyType.UserProjectAccessPolicy)]
[BitAutoData(AccessPolicyType.GroupProjectAccessPolicy)]
[BitAutoData(AccessPolicyType.ServiceAccountProjectAccessPolicy)]
[BitAutoData(AccessPolicyType.UserServiceAccountAccessPolicy)]
[BitAutoData(AccessPolicyType.GroupServiceAccountAccessPolicy)]
public async Task CreateForServiceAccount_NotUnique_Throws(
AccessPolicyType accessPolicyType,
Guid userId,
ServiceAccount serviceAccount,
List<UserProjectAccessPolicy> userProjectAccessPolicies,
List<GroupProjectAccessPolicy> groupProjectAccessPolicies,
List<ServiceAccountProjectAccessPolicy> serviceAccountProjectAccessPolicies,
SutProvider<CreateAccessPoliciesCommand> sutProvider
)
{
var data = new List<BaseAccessPolicy>();
data.AddRange(userProjectAccessPolicies);
data.AddRange(groupProjectAccessPolicies);
data.AddRange(serviceAccountProjectAccessPolicies);
data = MakeDuplicate(data, accessPolicyType);
SetupAdmin(sutProvider, serviceAccount.OrganizationId);
sutProvider.GetDependency<IServiceAccountRepository>().GetByIdAsync(serviceAccount.Id).Returns(serviceAccount);
sutProvider.GetDependency<IAccessPolicyRepository>().AccessPolicyExists(Arg.Any<BaseAccessPolicy>())
.Returns(true);
await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.CreateForServiceAccountAsync(serviceAccount.Id, data, userId));
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs()
.CreateManyAsync(Arg.Any<List<BaseAccessPolicy>>());
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async Task CreateForServiceAccount_Success(
PermissionType permissionType,
Guid userId,
ServiceAccount serviceAccount,
List<UserServiceAccountAccessPolicy> userServiceAccountAccessPolicies,
List<GroupServiceAccountAccessPolicy> groupServiceAccountAccessPolicies,
SutProvider<CreateAccessPoliciesCommand> sutProvider)
{
var data = new List<BaseAccessPolicy>();
data.AddRange(userServiceAccountAccessPolicies);
data.AddRange(groupServiceAccountAccessPolicies);
sutProvider.GetDependency<IServiceAccountRepository>().GetByIdAsync(serviceAccount.Id).Returns(serviceAccount);
SetupPermission(sutProvider, permissionType, serviceAccount, userId);
await sutProvider.Sut.CreateForServiceAccountAsync(serviceAccount.Id, data, userId);
await sutProvider.GetDependency<IAccessPolicyRepository>().Received(1)
.CreateManyAsync(Arg.Is(AssertHelper.AssertPropertyEqual(data)));
}
[Theory]
[BitAutoData]
public async Task CreateForServiceAccount_UserWithoutPermission_ThrowsNotFound(
Guid userId,
ServiceAccount serviceAccount,
List<UserServiceAccountAccessPolicy> userServiceAccountAccessPolicies,
List<GroupServiceAccountAccessPolicy> groupServiceAccountAccessPolicies,
SutProvider<CreateAccessPoliciesCommand> sutProvider)
{
var data = new List<BaseAccessPolicy>();
data.AddRange(userServiceAccountAccessPolicies);
data.AddRange(groupServiceAccountAccessPolicies);
SetupUser(sutProvider, serviceAccount.OrganizationId);
sutProvider.GetDependency<IServiceAccountRepository>().GetByIdAsync(serviceAccount.Id).Returns(serviceAccount);
sutProvider.GetDependency<IServiceAccountRepository>()
.UserHasWriteAccessToServiceAccount(serviceAccount.Id, userId).Returns(false);
await Assert.ThrowsAsync<NotFoundException>(() =>
sutProvider.Sut.CreateForServiceAccountAsync(serviceAccount.Id, data, userId));
await sutProvider.GetDependency<IAccessPolicyRepository>().DidNotReceiveWithAnyArgs()
.CreateManyAsync(Arg.Any<List<BaseAccessPolicy>>());
}
}