1
0
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:
cd-bitwarden
2023-06-30 13:17:41 -04:00
committed by GitHub
parent b87e6d4a38
commit 3f3f52399b
11 changed files with 113 additions and 70 deletions

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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"));
}