mirror of
https://github.com/bitwarden/server.git
synced 2025-07-04 01:22:50 -05:00
[SM-716] Adding ability for service account to have write access (#3021)
* adding ability for service account to have write access * Suggested changes * fixing tests * dotnet format changes * Adding RunAsServiceAccountWIthPermission logic to ProjectAuthorizationhandlerTests * Removing logic that prevents deleting and updating a secret. Adding Service Account logic to tests inside of secretAuthorizationhandlerTests. * Removing Service Account from CanUpdateSecret_NotSupportedClientTypes_DoesNotSuceed because it is a supported client type now :) * thomas sugested changes * using Arg.Any<AccessClientType>() instead of default in tests * merge conflict changes and code updates to remove service account tests that are outdated * fixing tests * removing extra spaces that lint hates
This commit is contained in:
@ -52,7 +52,7 @@ public class ProjectAuthorizationHandler : AuthorizationHandler<ProjectOperation
|
||||
{
|
||||
AccessClientType.NoAccessCheck => true,
|
||||
AccessClientType.User => true,
|
||||
AccessClientType.ServiceAccount => false,
|
||||
AccessClientType.ServiceAccount => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@ -67,10 +67,6 @@ public class ProjectAuthorizationHandler : AuthorizationHandler<ProjectOperation
|
||||
{
|
||||
var (accessClient, userId) =
|
||||
await _accessClientQuery.GetAccessClientAsync(context.User, resource.OrganizationId);
|
||||
if (accessClient == AccessClientType.ServiceAccount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var access = await _projectRepository.AccessToProjectAsync(resource.Id, userId, accessClient);
|
||||
|
||||
|
@ -74,7 +74,8 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
|
||||
AccessClientType.NoAccessCheck => true,
|
||||
AccessClientType.User => (await _projectRepository.AccessToProjectAsync(project!.Id, userId, accessClient))
|
||||
.Write,
|
||||
AccessClientType.ServiceAccount => false,
|
||||
AccessClientType.ServiceAccount => (await _projectRepository.AccessToProjectAsync(project!.Id, userId, accessClient))
|
||||
.Write,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@ -84,6 +85,7 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task CanUpdateSecretAsync(AuthorizationHandlerContext context,
|
||||
SecretOperationRequirement requirement, Secret resource)
|
||||
{
|
||||
@ -106,12 +108,10 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
|
||||
hasAccess = true;
|
||||
break;
|
||||
case AccessClientType.User:
|
||||
var newProject = resource.Projects?.FirstOrDefault();
|
||||
var access = (await _secretRepository.AccessToSecretAsync(resource.Id, userId, accessClient)).Write;
|
||||
var accessToNew = newProject != null &&
|
||||
(await _projectRepository.AccessToProjectAsync(newProject.Id, userId, accessClient))
|
||||
.Write;
|
||||
hasAccess = access && accessToNew;
|
||||
hasAccess = await GetAccessToUpdateSecretAsync(resource, userId, accessClient);
|
||||
break;
|
||||
case AccessClientType.ServiceAccount:
|
||||
hasAccess = await GetAccessToUpdateSecretAsync(resource, userId, accessClient);
|
||||
break;
|
||||
default:
|
||||
hasAccess = false;
|
||||
@ -129,11 +129,6 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
|
||||
{
|
||||
var (accessClient, userId) = await _accessClientQuery.GetAccessClientAsync(context.User, resource.OrganizationId);
|
||||
|
||||
if (accessClient == AccessClientType.ServiceAccount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var access = await _secretRepository.AccessToSecretAsync(resource.Id, userId, accessClient);
|
||||
|
||||
if (access.Write)
|
||||
@ -141,4 +136,14 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> GetAccessToUpdateSecretAsync(Secret resource, Guid userId, AccessClientType accessClient)
|
||||
{
|
||||
var newProject = resource.Projects?.FirstOrDefault();
|
||||
var access = (await _secretRepository.AccessToSecretAsync(resource.Id, userId, accessClient)).Write;
|
||||
var accessToNew = newProject != null &&
|
||||
(await _projectRepository.AccessToProjectAsync(newProject.Id, userId, accessClient))
|
||||
.Write;
|
||||
return access && accessToNew;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Identity;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretsManager.Commands.Projects.Interfaces;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Repositories;
|
||||
@ -10,31 +13,58 @@ public class CreateProjectCommand : ICreateProjectCommand
|
||||
private readonly IAccessPolicyRepository _accessPolicyRepository;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IProjectRepository _projectRepository;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
|
||||
public CreateProjectCommand(
|
||||
IAccessPolicyRepository accessPolicyRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IProjectRepository projectRepository)
|
||||
IProjectRepository projectRepository,
|
||||
ICurrentContext currentContext)
|
||||
{
|
||||
_accessPolicyRepository = accessPolicyRepository;
|
||||
_organizationUserRepository = organizationUserRepository;
|
||||
_projectRepository = projectRepository;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
public async Task<Project> CreateAsync(Project project, Guid userId)
|
||||
public async Task<Project> CreateAsync(Project project, Guid id, ClientType clientType)
|
||||
{
|
||||
if (clientType != ClientType.User && clientType != ClientType.ServiceAccount)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var createdProject = await _projectRepository.CreateAsync(project);
|
||||
|
||||
var orgUser = await _organizationUserRepository.GetByOrganizationAsync(createdProject.OrganizationId,
|
||||
userId);
|
||||
var accessPolicy = new UserProjectAccessPolicy()
|
||||
if (clientType == ClientType.User)
|
||||
{
|
||||
OrganizationUserId = orgUser.Id,
|
||||
GrantedProjectId = createdProject.Id,
|
||||
Read = true,
|
||||
Write = true,
|
||||
};
|
||||
await _accessPolicyRepository.CreateManyAsync(new List<BaseAccessPolicy> { accessPolicy });
|
||||
var orgUser = await _organizationUserRepository.GetByOrganizationAsync(createdProject.OrganizationId, id);
|
||||
|
||||
var accessPolicy = new UserProjectAccessPolicy()
|
||||
{
|
||||
OrganizationUserId = orgUser.Id,
|
||||
GrantedProjectId = createdProject.Id,
|
||||
Read = true,
|
||||
Write = true,
|
||||
};
|
||||
|
||||
await _accessPolicyRepository.CreateManyAsync(new List<BaseAccessPolicy> { accessPolicy });
|
||||
|
||||
}
|
||||
else if (clientType == ClientType.ServiceAccount)
|
||||
{
|
||||
var serviceAccountProjectAccessPolicy = new ServiceAccountProjectAccessPolicy()
|
||||
{
|
||||
ServiceAccountId = id,
|
||||
GrantedProjectId = createdProject.Id,
|
||||
Read = true,
|
||||
Write = true,
|
||||
};
|
||||
|
||||
await _accessPolicyRepository.CreateManyAsync(new List<BaseAccessPolicy> { serviceAccountProjectAccessPolicy });
|
||||
}
|
||||
|
||||
return createdProject;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ public class DeleteProjectCommand : IDeleteProjectCommand
|
||||
foreach (var project in projects)
|
||||
{
|
||||
var access = await _projectRepository.AccessToProjectAsync(project.Id, userId, accessClient);
|
||||
if (!access.Write || accessClient == AccessClientType.ServiceAccount)
|
||||
if (!access.Write)
|
||||
{
|
||||
results.Add(new Tuple<Project, string>(project, "access denied"));
|
||||
}
|
||||
|
Reference in New Issue
Block a user