mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 08:32:50 -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:
@ -12,15 +12,18 @@ public class CreateAccessPoliciesCommand : ICreateAccessPoliciesCommand
|
||||
private readonly IAccessPolicyRepository _accessPolicyRepository;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IProjectRepository _projectRepository;
|
||||
private readonly IServiceAccountRepository _serviceAccountRepository;
|
||||
|
||||
public CreateAccessPoliciesCommand(
|
||||
IAccessPolicyRepository accessPolicyRepository,
|
||||
ICurrentContext currentContext,
|
||||
IProjectRepository projectRepository)
|
||||
IProjectRepository projectRepository,
|
||||
IServiceAccountRepository serviceAccountRepository)
|
||||
{
|
||||
_projectRepository = projectRepository;
|
||||
_accessPolicyRepository = accessPolicyRepository;
|
||||
_currentContext = currentContext;
|
||||
_projectRepository = projectRepository;
|
||||
_serviceAccountRepository = serviceAccountRepository;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<BaseAccessPolicy>> CreateForProjectAsync(Guid projectId,
|
||||
@ -32,21 +35,33 @@ public class CreateAccessPoliciesCommand : ICreateAccessPoliciesCommand
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var orgAdmin = await _currentContext.OrganizationAdmin(project.OrganizationId);
|
||||
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
||||
await CheckPermissionAsync(project.OrganizationId, userId, projectId);
|
||||
CheckForDistinctAccessPolicies(accessPolicies);
|
||||
await CheckAccessPoliciesDoNotExistAsync(accessPolicies);
|
||||
|
||||
var hasAccess = accessClient switch
|
||||
{
|
||||
AccessClientType.NoAccessCheck => true,
|
||||
AccessClientType.User => await _projectRepository.UserHasWriteAccessToProject(project.Id, userId),
|
||||
_ => false,
|
||||
};
|
||||
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
|
||||
return await _accessPolicyRepository.GetManyByGrantedProjectIdAsync(projectId);
|
||||
}
|
||||
|
||||
if (!hasAccess)
|
||||
public async Task<IEnumerable<BaseAccessPolicy>> CreateForServiceAccountAsync(Guid serviceAccountId,
|
||||
List<BaseAccessPolicy> accessPolicies, Guid userId)
|
||||
{
|
||||
var serviceAccount = await _serviceAccountRepository.GetByIdAsync(serviceAccountId);
|
||||
if (serviceAccount == null || !_currentContext.AccessSecretsManager(serviceAccount.OrganizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
await CheckPermissionAsync(serviceAccount.OrganizationId, userId, serviceAccountIdToCheck: serviceAccountId);
|
||||
CheckForDistinctAccessPolicies(accessPolicies);
|
||||
await CheckAccessPoliciesDoNotExistAsync(accessPolicies);
|
||||
|
||||
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
|
||||
return await _accessPolicyRepository.GetManyByGrantedServiceAccountIdAsync(serviceAccountId);
|
||||
}
|
||||
|
||||
private static void CheckForDistinctAccessPolicies(IReadOnlyCollection<BaseAccessPolicy> accessPolicies)
|
||||
{
|
||||
var distinctAccessPolicies = accessPolicies.DistinctBy(baseAccessPolicy =>
|
||||
{
|
||||
return baseAccessPolicy switch
|
||||
@ -55,6 +70,9 @@ public class CreateAccessPoliciesCommand : ICreateAccessPoliciesCommand
|
||||
GroupProjectAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.GroupId, ap.GrantedProjectId),
|
||||
ServiceAccountProjectAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.ServiceAccountId,
|
||||
ap.GrantedProjectId),
|
||||
UserServiceAccountAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.OrganizationUserId,
|
||||
ap.GrantedServiceAccountId),
|
||||
GroupServiceAccountAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.GroupId, ap.GrantedServiceAccountId),
|
||||
_ => throw new ArgumentException("Unsupported access policy type provided.", nameof(baseAccessPolicy)),
|
||||
};
|
||||
}).ToList();
|
||||
@ -63,7 +81,10 @@ public class CreateAccessPoliciesCommand : ICreateAccessPoliciesCommand
|
||||
{
|
||||
throw new BadRequestException("Resources must be unique");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CheckAccessPoliciesDoNotExistAsync(List<BaseAccessPolicy> accessPolicies)
|
||||
{
|
||||
foreach (var accessPolicy in accessPolicies)
|
||||
{
|
||||
if (await _accessPolicyRepository.AccessPolicyExists(accessPolicy))
|
||||
@ -71,7 +92,46 @@ public class CreateAccessPoliciesCommand : ICreateAccessPoliciesCommand
|
||||
throw new BadRequestException("Resource already exists");
|
||||
}
|
||||
}
|
||||
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
|
||||
return await _accessPolicyRepository.GetManyByGrantedProjectIdAsync(projectId);
|
||||
}
|
||||
|
||||
private async Task CheckPermissionAsync(Guid organizationId,
|
||||
Guid userId,
|
||||
Guid? projectIdToCheck = null,
|
||||
Guid? serviceAccountIdToCheck = null)
|
||||
{
|
||||
var orgAdmin = await _currentContext.OrganizationAdmin(organizationId);
|
||||
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
||||
|
||||
bool hasAccess;
|
||||
switch (accessClient)
|
||||
{
|
||||
case AccessClientType.NoAccessCheck:
|
||||
hasAccess = true;
|
||||
break;
|
||||
case AccessClientType.User:
|
||||
if (projectIdToCheck != null)
|
||||
{
|
||||
hasAccess = await _projectRepository.UserHasWriteAccessToProject(projectIdToCheck.Value, userId);
|
||||
}
|
||||
else if (serviceAccountIdToCheck != null)
|
||||
{
|
||||
hasAccess = await _serviceAccountRepository.UserHasWriteAccessToServiceAccount(
|
||||
serviceAccountIdToCheck.Value,
|
||||
userId);
|
||||
}
|
||||
else
|
||||
{
|
||||
hasAccess = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
hasAccess = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hasAccess)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,152 +16,152 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
|
||||
public async Task<List<Core.SecretsManager.Entities.BaseAccessPolicy>> CreateManyAsync(List<Core.SecretsManager.Entities.BaseAccessPolicy> baseAccessPolicies)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
foreach (var baseAccessPolicy in baseAccessPolicies)
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
foreach (var baseAccessPolicy in baseAccessPolicies)
|
||||
{
|
||||
baseAccessPolicy.SetNewId();
|
||||
switch (baseAccessPolicy)
|
||||
{
|
||||
case Core.SecretsManager.Entities.UserProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity =
|
||||
Mapper.Map<UserProjectAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.UserServiceAccountAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity =
|
||||
Mapper.Map<UserServiceAccountAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.GroupProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity = Mapper.Map<GroupProjectAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.GroupServiceAccountAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity = Mapper.Map<GroupServiceAccountAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.ServiceAccountProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity = Mapper.Map<ServiceAccountProjectAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
return baseAccessPolicies;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> AccessPolicyExists(Core.SecretsManager.Entities.BaseAccessPolicy baseAccessPolicy)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
baseAccessPolicy.SetNewId();
|
||||
switch (baseAccessPolicy)
|
||||
{
|
||||
case Core.SecretsManager.Entities.UserProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var policy = await dbContext.UserProjectAccessPolicy
|
||||
.Where(c => c.OrganizationUserId == accessPolicy.OrganizationUserId &&
|
||||
c.GrantedProjectId == accessPolicy.GrantedProjectId)
|
||||
.FirstOrDefaultAsync();
|
||||
return policy != null;
|
||||
var entity =
|
||||
Mapper.Map<UserProjectAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.UserServiceAccountAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity =
|
||||
Mapper.Map<UserServiceAccountAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.GroupProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var policy = await dbContext.GroupProjectAccessPolicy
|
||||
.Where(c => c.GroupId == accessPolicy.GroupId &&
|
||||
c.GrantedProjectId == accessPolicy.GrantedProjectId)
|
||||
.FirstOrDefaultAsync();
|
||||
return policy != null;
|
||||
var entity = Mapper.Map<GroupProjectAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.GroupServiceAccountAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity = Mapper.Map<GroupServiceAccountAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.ServiceAccountProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var policy = await dbContext.ServiceAccountProjectAccessPolicy
|
||||
.Where(c => c.ServiceAccountId == accessPolicy.ServiceAccountId &&
|
||||
c.GrantedProjectId == accessPolicy.GrantedProjectId)
|
||||
.FirstOrDefaultAsync();
|
||||
return policy != null;
|
||||
var entity = Mapper.Map<ServiceAccountProjectAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentException("Unsupported access policy type provided.", nameof(baseAccessPolicy));
|
||||
}
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync();
|
||||
return baseAccessPolicies;
|
||||
}
|
||||
|
||||
public async Task<bool> AccessPolicyExists(Core.SecretsManager.Entities.BaseAccessPolicy baseAccessPolicy)
|
||||
{
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
switch (baseAccessPolicy)
|
||||
{
|
||||
case Core.SecretsManager.Entities.UserProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var policy = await dbContext.UserProjectAccessPolicy
|
||||
.Where(c => c.OrganizationUserId == accessPolicy.OrganizationUserId &&
|
||||
c.GrantedProjectId == accessPolicy.GrantedProjectId)
|
||||
.FirstOrDefaultAsync();
|
||||
return policy != null;
|
||||
}
|
||||
case Core.SecretsManager.Entities.GroupProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var policy = await dbContext.GroupProjectAccessPolicy
|
||||
.Where(c => c.GroupId == accessPolicy.GroupId &&
|
||||
c.GrantedProjectId == accessPolicy.GrantedProjectId)
|
||||
.FirstOrDefaultAsync();
|
||||
return policy != null;
|
||||
}
|
||||
case Core.SecretsManager.Entities.ServiceAccountProjectAccessPolicy accessPolicy:
|
||||
{
|
||||
var policy = await dbContext.ServiceAccountProjectAccessPolicy
|
||||
.Where(c => c.ServiceAccountId == accessPolicy.ServiceAccountId &&
|
||||
c.GrantedProjectId == accessPolicy.GrantedProjectId)
|
||||
.FirstOrDefaultAsync();
|
||||
return policy != null;
|
||||
}
|
||||
case Core.SecretsManager.Entities.UserServiceAccountAccessPolicy accessPolicy:
|
||||
{
|
||||
var policy = await dbContext.UserServiceAccountAccessPolicy
|
||||
.Where(c => c.OrganizationUserId == accessPolicy.OrganizationUserId &&
|
||||
c.GrantedServiceAccountId == accessPolicy.GrantedServiceAccountId)
|
||||
.FirstOrDefaultAsync();
|
||||
return policy != null;
|
||||
}
|
||||
case Core.SecretsManager.Entities.GroupServiceAccountAccessPolicy accessPolicy:
|
||||
{
|
||||
var policy = await dbContext.GroupServiceAccountAccessPolicy
|
||||
.Where(c => c.GroupId == accessPolicy.GroupId &&
|
||||
c.GrantedServiceAccountId == accessPolicy.GrantedServiceAccountId)
|
||||
.FirstOrDefaultAsync();
|
||||
return policy != null;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentException("Unsupported access policy type provided.", nameof(baseAccessPolicy));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Core.SecretsManager.Entities.BaseAccessPolicy?> GetByIdAsync(Guid id)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entity = await dbContext.AccessPolicies.Where(ap => ap.Id == id)
|
||||
.Include(ap => ((UserProjectAccessPolicy)ap).OrganizationUser.User)
|
||||
.Include(ap => ((UserProjectAccessPolicy)ap).GrantedProject)
|
||||
.Include(ap => ((GroupProjectAccessPolicy)ap).Group)
|
||||
.Include(ap => ((GroupProjectAccessPolicy)ap).GrantedProject)
|
||||
.Include(ap => ((ServiceAccountProjectAccessPolicy)ap).ServiceAccount)
|
||||
.Include(ap => ((ServiceAccountProjectAccessPolicy)ap).GrantedProject)
|
||||
.Include(ap => ((UserServiceAccountAccessPolicy)ap).OrganizationUser.User)
|
||||
.Include(ap => ((UserServiceAccountAccessPolicy)ap).GrantedServiceAccount)
|
||||
.Include(ap => ((GroupServiceAccountAccessPolicy)ap).Group)
|
||||
.Include(ap => ((GroupServiceAccountAccessPolicy)ap).GrantedServiceAccount)
|
||||
.FirstOrDefaultAsync();
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entity = await dbContext.AccessPolicies.Where(ap => ap.Id == id)
|
||||
.Include(ap => ((UserProjectAccessPolicy)ap).OrganizationUser.User)
|
||||
.Include(ap => ((UserProjectAccessPolicy)ap).GrantedProject)
|
||||
.Include(ap => ((GroupProjectAccessPolicy)ap).Group)
|
||||
.Include(ap => ((GroupProjectAccessPolicy)ap).GrantedProject)
|
||||
.Include(ap => ((ServiceAccountProjectAccessPolicy)ap).ServiceAccount)
|
||||
.Include(ap => ((ServiceAccountProjectAccessPolicy)ap).GrantedProject)
|
||||
.Include(ap => ((UserServiceAccountAccessPolicy)ap).OrganizationUser.User)
|
||||
.Include(ap => ((UserServiceAccountAccessPolicy)ap).GrantedServiceAccount)
|
||||
.Include(ap => ((GroupServiceAccountAccessPolicy)ap).Group)
|
||||
.Include(ap => ((GroupServiceAccountAccessPolicy)ap).GrantedServiceAccount)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return MapToCore(entity);
|
||||
}
|
||||
return entity == null ? null : MapToCore(entity);
|
||||
}
|
||||
|
||||
public async Task ReplaceAsync(Core.SecretsManager.Entities.BaseAccessPolicy baseAccessPolicy)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entity = await dbContext.AccessPolicies.FindAsync(baseAccessPolicy.Id);
|
||||
if (entity != null)
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entity = await dbContext.AccessPolicies.FindAsync(baseAccessPolicy.Id);
|
||||
if (entity != null)
|
||||
{
|
||||
dbContext.AccessPolicies.Attach(entity);
|
||||
entity.Write = baseAccessPolicy.Write;
|
||||
entity.Read = baseAccessPolicy.Read;
|
||||
entity.RevisionDate = baseAccessPolicy.RevisionDate;
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
dbContext.AccessPolicies.Attach(entity);
|
||||
entity.Write = baseAccessPolicy.Write;
|
||||
entity.Read = baseAccessPolicy.Read;
|
||||
entity.RevisionDate = baseAccessPolicy.RevisionDate;
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Core.SecretsManager.Entities.BaseAccessPolicy>> GetManyByGrantedProjectIdAsync(Guid id)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
|
||||
var entities = await dbContext.AccessPolicies.Where(ap =>
|
||||
((UserProjectAccessPolicy)ap).GrantedProjectId == id ||
|
||||
((GroupProjectAccessPolicy)ap).GrantedProjectId == id ||
|
||||
((ServiceAccountProjectAccessPolicy)ap).GrantedProjectId == id)
|
||||
.Include(ap => ((UserProjectAccessPolicy)ap).OrganizationUser.User)
|
||||
.Include(ap => ((GroupProjectAccessPolicy)ap).Group)
|
||||
.Include(ap => ((ServiceAccountProjectAccessPolicy)ap).ServiceAccount)
|
||||
.ToListAsync();
|
||||
|
||||
return entities.Select(MapToCore);
|
||||
}
|
||||
var entities = await dbContext.AccessPolicies.Where(ap =>
|
||||
((UserProjectAccessPolicy)ap).GrantedProjectId == id ||
|
||||
((GroupProjectAccessPolicy)ap).GrantedProjectId == id ||
|
||||
((ServiceAccountProjectAccessPolicy)ap).GrantedProjectId == id)
|
||||
.Include(ap => ((UserProjectAccessPolicy)ap).OrganizationUser.User)
|
||||
.Include(ap => ((GroupProjectAccessPolicy)ap).Group)
|
||||
.Include(ap => ((ServiceAccountProjectAccessPolicy)ap).ServiceAccount)
|
||||
.ToListAsync();
|
||||
return entities.Select(MapToCore);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Core.SecretsManager.Entities.BaseAccessPolicy>> GetManyByGrantedServiceAccountIdAsync(Guid id)
|
||||
@ -181,15 +181,13 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
|
||||
public async Task DeleteAsync(Guid id)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
using var scope = ServiceScopeFactory.CreateScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entity = await dbContext.AccessPolicies.FindAsync(id);
|
||||
if (entity != null)
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var entity = await dbContext.AccessPolicies.FindAsync(id);
|
||||
if (entity != null)
|
||||
{
|
||||
dbContext.Remove(entity);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
dbContext.Remove(entity);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>>());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user