mirror of
https://github.com/bitwarden/server.git
synced 2025-05-22 20:11:04 -05:00
[SM-670] Add permission context to project lists. (#2822)
* Attach permission context to project lists. * restrict service-account actions * Fix project permission details * Add getters and setters * dotnet format * Fix admin create unassigned secret (#2872)
This commit is contained in:
parent
9cbd0ac799
commit
20d3b4b4e8
@ -118,7 +118,7 @@ public class CreateAccessPoliciesCommand : ICreateAccessPoliciesCommand
|
|||||||
case AccessClientType.User:
|
case AccessClientType.User:
|
||||||
if (projectIdToCheck.HasValue)
|
if (projectIdToCheck.HasValue)
|
||||||
{
|
{
|
||||||
hasAccess = await _projectRepository.UserHasWriteAccessToProject(projectIdToCheck.Value, userId);
|
hasAccess = (await _projectRepository.AccessToProjectAsync(projectIdToCheck.Value, userId, accessClient)).Write;
|
||||||
}
|
}
|
||||||
else if (serviceAccountIdToCheck.HasValue)
|
else if (serviceAccountIdToCheck.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -83,7 +83,7 @@ public class DeleteAccessPolicyCommand : IDeleteAccessPolicyCommand
|
|||||||
case AccessClientType.User:
|
case AccessClientType.User:
|
||||||
if (projectIdToCheck.HasValue)
|
if (projectIdToCheck.HasValue)
|
||||||
{
|
{
|
||||||
hasAccess = await _projectRepository.UserHasWriteAccessToProject(projectIdToCheck.Value, userId);
|
hasAccess = (await _projectRepository.AccessToProjectAsync(projectIdToCheck.Value, userId, accessClient)).Write;
|
||||||
}
|
}
|
||||||
else if (serviceAccountIdToCheck.HasValue)
|
else if (serviceAccountIdToCheck.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -87,7 +87,7 @@ public class UpdateAccessPolicyCommand : IUpdateAccessPolicyCommand
|
|||||||
case AccessClientType.User:
|
case AccessClientType.User:
|
||||||
if (projectIdToCheck.HasValue)
|
if (projectIdToCheck.HasValue)
|
||||||
{
|
{
|
||||||
hasAccess = await _projectRepository.UserHasWriteAccessToProject(projectIdToCheck.Value, userId);
|
hasAccess = (await _projectRepository.AccessToProjectAsync(projectIdToCheck.Value, userId, accessClient)).Write;
|
||||||
}
|
}
|
||||||
else if (serviceAccountIdToCheck.HasValue)
|
else if (serviceAccountIdToCheck.HasValue)
|
||||||
{
|
{
|
||||||
|
@ -49,19 +49,13 @@ public class DeleteProjectCommand : IDeleteProjectCommand
|
|||||||
var orgAdmin = await _currentContext.OrganizationAdmin(organizationId);
|
var orgAdmin = await _currentContext.OrganizationAdmin(organizationId);
|
||||||
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
||||||
|
|
||||||
var results = new List<Tuple<Project, String>>(projects.Count);
|
var results = new List<Tuple<Project, string>>(projects.Count);
|
||||||
var deleteIds = new List<Guid>();
|
var deleteIds = new List<Guid>();
|
||||||
|
|
||||||
foreach (var project in projects)
|
foreach (var project in projects)
|
||||||
{
|
{
|
||||||
var hasAccess = accessClient switch
|
var access = await _projectRepository.AccessToProjectAsync(project.Id, userId, accessClient);
|
||||||
{
|
if (!access.Write || accessClient == AccessClientType.ServiceAccount)
|
||||||
AccessClientType.NoAccessCheck => true,
|
|
||||||
AccessClientType.User => await _projectRepository.UserHasWriteAccessToProject(project.Id, userId),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!hasAccess)
|
|
||||||
{
|
{
|
||||||
results.Add(new Tuple<Project, string>(project, "access denied"));
|
results.Add(new Tuple<Project, string>(project, "access denied"));
|
||||||
}
|
}
|
||||||
|
@ -34,14 +34,8 @@ public class UpdateProjectCommand : IUpdateProjectCommand
|
|||||||
var orgAdmin = await _currentContext.OrganizationAdmin(project.OrganizationId);
|
var orgAdmin = await _currentContext.OrganizationAdmin(project.OrganizationId);
|
||||||
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
||||||
|
|
||||||
var hasAccess = accessClient switch
|
var access = await _projectRepository.AccessToProjectAsync(updatedProject.Id, userId, accessClient);
|
||||||
{
|
if (!access.Write || accessClient == AccessClientType.ServiceAccount)
|
||||||
AccessClientType.NoAccessCheck => true,
|
|
||||||
AccessClientType.User => await _projectRepository.UserHasWriteAccessToProject(updatedProject.Id, userId),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!hasAccess)
|
|
||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public class CreateSecretCommand : ICreateSecretCommand
|
|||||||
var hasAccess = accessClient switch
|
var hasAccess = accessClient switch
|
||||||
{
|
{
|
||||||
AccessClientType.NoAccessCheck => true,
|
AccessClientType.NoAccessCheck => true,
|
||||||
AccessClientType.User => await _projectRepository.UserHasWriteAccessToProject(project.Id, userId),
|
AccessClientType.User => (await _projectRepository.AccessToProjectAsync(project.Id, userId, accessClient)).Write,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,16 +54,10 @@ public class DeleteSecretCommand : IDeleteSecretCommand
|
|||||||
if (secret.Projects != null && secret.Projects?.Count > 0)
|
if (secret.Projects != null && secret.Projects?.Count > 0)
|
||||||
{
|
{
|
||||||
var projectId = secret.Projects.First().Id;
|
var projectId = secret.Projects.First().Id;
|
||||||
|
hasAccess = (await _projectRepository.AccessToProjectAsync(projectId, userId, accessClient)).Write;
|
||||||
hasAccess = accessClient switch
|
|
||||||
{
|
|
||||||
AccessClientType.NoAccessCheck => true,
|
|
||||||
AccessClientType.User => await _projectRepository.UserHasWriteAccessToProject(projectId, userId),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasAccess)
|
if (!hasAccess || accessClient == AccessClientType.ServiceAccount)
|
||||||
{
|
{
|
||||||
results.Add(new Tuple<Secret, string>(secret, "access denied"));
|
results.Add(new Tuple<Secret, string>(secret, "access denied"));
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ public class UpdateSecretCommand : IUpdateSecretCommand
|
|||||||
return secret;
|
return secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> HasAccessToOriginalAndUpdatedProject(AccessClientType accessClient, Secret secret, Secret updatedSecret, Guid userId)
|
private async Task<bool> HasAccessToOriginalAndUpdatedProject(AccessClientType accessClient, Secret secret, Secret updatedSecret, Guid userId)
|
||||||
{
|
{
|
||||||
switch (accessClient)
|
switch (accessClient)
|
||||||
{
|
{
|
||||||
@ -60,8 +60,8 @@ public class UpdateSecretCommand : IUpdateSecretCommand
|
|||||||
case AccessClientType.User:
|
case AccessClientType.User:
|
||||||
var oldProject = secret.Projects?.FirstOrDefault();
|
var oldProject = secret.Projects?.FirstOrDefault();
|
||||||
var newProject = updatedSecret.Projects?.FirstOrDefault();
|
var newProject = updatedSecret.Projects?.FirstOrDefault();
|
||||||
var accessToOld = oldProject != null && await _projectRepository.UserHasWriteAccessToProject(oldProject.Id, userId);
|
var accessToOld = oldProject != null && (await _projectRepository.AccessToProjectAsync(oldProject.Id, userId, accessClient)).Write;
|
||||||
var accessToNew = newProject != null && await _projectRepository.UserHasWriteAccessToProject(newProject.Id, userId);
|
var accessToNew = newProject != null && (await _projectRepository.AccessToProjectAsync(newProject.Id, userId, accessClient)).Write;
|
||||||
return accessToOld && accessToNew;
|
return accessToOld && accessToNew;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.SecretsManager.Models;
|
using Bit.Infrastructure.EntityFramework.SecretsManager.Models;
|
||||||
@ -27,22 +28,16 @@ public class ProjectRepository : Repository<Core.SecretsManager.Entities.Project
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Core.SecretsManager.Entities.Project>> GetManyByOrganizationIdAsync(Guid organizationId, Guid userId, AccessClientType accessType)
|
public async Task<IEnumerable<ProjectPermissionDetails>> GetManyByOrganizationIdAsync(Guid organizationId, Guid userId, AccessClientType accessType)
|
||||||
{
|
{
|
||||||
using var scope = ServiceScopeFactory.CreateScope();
|
using var scope = ServiceScopeFactory.CreateScope();
|
||||||
var dbContext = GetDatabaseContext(scope);
|
var dbContext = GetDatabaseContext(scope);
|
||||||
var query = dbContext.Project.Where(p => p.OrganizationId == organizationId && p.DeletedDate == null);
|
|
||||||
|
|
||||||
query = accessType switch
|
var query = dbContext.Project.Where(p => p.OrganizationId == organizationId && p.DeletedDate == null).OrderBy(p => p.RevisionDate);
|
||||||
{
|
|
||||||
AccessClientType.NoAccessCheck => query,
|
|
||||||
AccessClientType.User => query.Where(UserHasReadAccessToProject(userId)),
|
|
||||||
AccessClientType.ServiceAccount => query.Where(ServiceAccountHasReadAccessToProject(userId)),
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(accessType), accessType, null),
|
|
||||||
};
|
|
||||||
|
|
||||||
var projects = await query.OrderBy(p => p.RevisionDate).ToListAsync();
|
var projects = ProjectToPermissionDetails(query, userId, accessType);
|
||||||
return Mapper.Map<List<Core.SecretsManager.Entities.Project>>(projects);
|
|
||||||
|
return await projects.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Core.SecretsManager.Entities.Project>> GetManyByOrganizationIdWriteAccessAsync(
|
public async Task<IEnumerable<Core.SecretsManager.Entities.Project>> GetManyByOrganizationIdWriteAccessAsync(
|
||||||
@ -63,20 +58,6 @@ public class ProjectRepository : Repository<Core.SecretsManager.Entities.Project
|
|||||||
return Mapper.Map<List<Core.SecretsManager.Entities.Project>>(projects);
|
return Mapper.Map<List<Core.SecretsManager.Entities.Project>>(projects);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Expression<Func<Project, bool>> UserHasReadAccessToProject(Guid userId) => p =>
|
|
||||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Read) ||
|
|
||||||
p.GroupAccessPolicies.Any(ap => ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Read));
|
|
||||||
|
|
||||||
private static Expression<Func<Project, bool>> UserHasWriteAccessToProject(Guid userId) => p =>
|
|
||||||
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Write) ||
|
|
||||||
p.GroupAccessPolicies.Any(ap => ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Write));
|
|
||||||
|
|
||||||
private static Expression<Func<Project, bool>> ServiceAccountHasReadAccessToProject(Guid serviceAccountId) => p =>
|
|
||||||
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccount.Id == serviceAccountId && ap.Read);
|
|
||||||
|
|
||||||
private static Expression<Func<Project, bool>> ServiceAccountHasWriteAccessToProject(Guid serviceAccountId) => p =>
|
|
||||||
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccount.Id == serviceAccountId && ap.Write);
|
|
||||||
|
|
||||||
public async Task DeleteManyByIdAsync(IEnumerable<Guid> ids)
|
public async Task DeleteManyByIdAsync(IEnumerable<Guid> ids)
|
||||||
{
|
{
|
||||||
using (var scope = ServiceScopeFactory.CreateScope())
|
using (var scope = ServiceScopeFactory.CreateScope())
|
||||||
@ -97,57 +78,13 @@ public class ProjectRepository : Repository<Core.SecretsManager.Entities.Project
|
|||||||
{
|
{
|
||||||
var dbContext = GetDatabaseContext(scope);
|
var dbContext = GetDatabaseContext(scope);
|
||||||
var projects = await dbContext.Project
|
var projects = await dbContext.Project
|
||||||
.Include(p => p.Secrets)
|
.Include(p => p.Secrets)
|
||||||
.Where(c => ids.Contains(c.Id) && c.DeletedDate == null)
|
.Where(c => ids.Contains(c.Id) && c.DeletedDate == null)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
return Mapper.Map<List<Core.SecretsManager.Entities.Project>>(projects);
|
return Mapper.Map<List<Core.SecretsManager.Entities.Project>>(projects);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ServiceAccountHasReadAccessToProject(Guid id, Guid userId)
|
|
||||||
{
|
|
||||||
using var scope = ServiceScopeFactory.CreateScope();
|
|
||||||
var dbContext = GetDatabaseContext(scope);
|
|
||||||
var query = dbContext.Project
|
|
||||||
.Where(p => p.Id == id)
|
|
||||||
.Where(ServiceAccountHasReadAccessToProject(userId));
|
|
||||||
|
|
||||||
return await query.AnyAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> ServiceAccountHasWriteAccessToProject(Guid id, Guid userId)
|
|
||||||
{
|
|
||||||
using var scope = ServiceScopeFactory.CreateScope();
|
|
||||||
var dbContext = GetDatabaseContext(scope);
|
|
||||||
var query = dbContext.Project
|
|
||||||
.Where(p => p.Id == id)
|
|
||||||
.Where(ServiceAccountHasWriteAccessToProject(userId));
|
|
||||||
|
|
||||||
return await query.AnyAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> UserHasReadAccessToProject(Guid id, Guid userId)
|
|
||||||
{
|
|
||||||
using var scope = ServiceScopeFactory.CreateScope();
|
|
||||||
var dbContext = GetDatabaseContext(scope);
|
|
||||||
var query = dbContext.Project
|
|
||||||
.Where(p => p.Id == id)
|
|
||||||
.Where(UserHasReadAccessToProject(userId));
|
|
||||||
|
|
||||||
return await query.AnyAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> UserHasWriteAccessToProject(Guid id, Guid userId)
|
|
||||||
{
|
|
||||||
using var scope = ServiceScopeFactory.CreateScope();
|
|
||||||
var dbContext = GetDatabaseContext(scope);
|
|
||||||
var query = dbContext.Project
|
|
||||||
.Where(p => p.Id == id)
|
|
||||||
.Where(UserHasWriteAccessToProject(userId));
|
|
||||||
|
|
||||||
return await query.AnyAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<Core.SecretsManager.Entities.Project>> ImportAsync(IEnumerable<Core.SecretsManager.Entities.Project> projects)
|
public async Task<IEnumerable<Core.SecretsManager.Entities.Project>> ImportAsync(IEnumerable<Core.SecretsManager.Entities.Project> projects)
|
||||||
{
|
{
|
||||||
using var scope = ServiceScopeFactory.CreateScope();
|
using var scope = ServiceScopeFactory.CreateScope();
|
||||||
@ -199,4 +136,54 @@ public class ProjectRepository : Repository<Core.SecretsManager.Entities.Project
|
|||||||
|
|
||||||
return projectIds.Count == results.Count;
|
return projectIds.Count == results.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IQueryable<ProjectPermissionDetails> ProjectToPermissionDetails(IQueryable<Project> query, Guid userId, AccessClientType accessType)
|
||||||
|
{
|
||||||
|
var projects = accessType switch
|
||||||
|
{
|
||||||
|
AccessClientType.NoAccessCheck => query.Select(p => new ProjectPermissionDetails
|
||||||
|
{
|
||||||
|
Project = Mapper.Map<Bit.Core.SecretsManager.Entities.Project>(p),
|
||||||
|
Read = true,
|
||||||
|
Write = true,
|
||||||
|
}),
|
||||||
|
AccessClientType.User => query.Where(UserHasReadAccessToProject(userId)).Select(ProjectToPermissionsUser(userId, true)),
|
||||||
|
AccessClientType.ServiceAccount => query.Where(ServiceAccountHasReadAccessToProject(userId)).Select(ProjectToPermissionsServiceAccount(userId, true)),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(accessType), accessType, null),
|
||||||
|
};
|
||||||
|
return projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression<Func<Project, ProjectPermissionDetails>> ProjectToPermissionsUser(Guid userId, bool read) =>
|
||||||
|
p => new ProjectPermissionDetails
|
||||||
|
{
|
||||||
|
Project = Mapper.Map<Bit.Core.SecretsManager.Entities.Project>(p),
|
||||||
|
Read = read,
|
||||||
|
Write = p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Write) ||
|
||||||
|
p.GroupAccessPolicies.Any(ap =>
|
||||||
|
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Write)),
|
||||||
|
};
|
||||||
|
|
||||||
|
private Expression<Func<Project, ProjectPermissionDetails>> ProjectToPermissionsServiceAccount(Guid userId, bool read) =>
|
||||||
|
p => new ProjectPermissionDetails
|
||||||
|
{
|
||||||
|
Project = Mapper.Map<Bit.Core.SecretsManager.Entities.Project>(p),
|
||||||
|
Read = read,
|
||||||
|
Write = p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccount.Id == userId && ap.Write),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static Expression<Func<Project, bool>> UserHasReadAccessToProject(Guid userId) => p =>
|
||||||
|
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Read) ||
|
||||||
|
p.GroupAccessPolicies.Any(ap => ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Read));
|
||||||
|
|
||||||
|
private static Expression<Func<Project, bool>> UserHasWriteAccessToProject(Guid userId) => p =>
|
||||||
|
p.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Write) ||
|
||||||
|
p.GroupAccessPolicies.Any(ap => ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Write));
|
||||||
|
|
||||||
|
private static Expression<Func<Project, bool>> ServiceAccountHasReadAccessToProject(Guid serviceAccountId) => p =>
|
||||||
|
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccount.Id == serviceAccountId && ap.Read);
|
||||||
|
|
||||||
|
private static Expression<Func<Project, bool>> ServiceAccountHasWriteAccessToProject(Guid serviceAccountId) => p =>
|
||||||
|
p.ServiceAccountAccessPolicies.Any(ap => ap.ServiceAccount.Id == serviceAccountId && ap.Write);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -136,8 +136,8 @@ public class CreateAccessPoliciesCommandTests
|
|||||||
{
|
{
|
||||||
if (permissionType == PermissionType.RunAsUserWithPermission)
|
if (permissionType == PermissionType.RunAsUserWithPermission)
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(project.Id, userId)
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(project.Id, userId, AccessClientType.User)
|
||||||
.Returns(true);
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
@ -28,8 +29,8 @@ public class DeleteAccessPolicyCommandTests
|
|||||||
.Returns(true);
|
.Returns(true);
|
||||||
break;
|
break;
|
||||||
case PermissionType.RunAsUserWithPermission:
|
case PermissionType.RunAsUserWithPermission:
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(grantedProject.Id, userId)
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(grantedProject.Id, userId, AccessClientType.User)
|
||||||
.Returns(true);
|
.Returns((true, true));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(permissionType), permissionType, null);
|
throw new ArgumentOutOfRangeException(nameof(permissionType), permissionType, null);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
@ -28,8 +29,8 @@ public class UpdateAccessPolicyCommandTests
|
|||||||
.Returns(true);
|
.Returns(true);
|
||||||
break;
|
break;
|
||||||
case PermissionType.RunAsUserWithPermission:
|
case PermissionType.RunAsUserWithPermission:
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(grantedProject.Id, userId)
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(grantedProject.Id, userId, AccessClientType.User)
|
||||||
.Returns(true);
|
.Returns((true, true));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(permissionType), permissionType, null);
|
throw new ArgumentOutOfRangeException(nameof(permissionType), permissionType, null);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Bit.Commercial.Core.SecretsManager.Commands.Projects;
|
using Bit.Commercial.Core.SecretsManager.Commands.Projects;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Identity;
|
using Bit.Core.Identity;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
@ -52,7 +53,8 @@ public class DeleteProjectCommandTests
|
|||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ClientType = ClientType.User;
|
sutProvider.GetDependency<ICurrentContext>().ClientType = ClientType.User;
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetManyWithSecretsByIds(data).Returns(projects);
|
sutProvider.GetDependency<IProjectRepository>().GetManyWithSecretsByIds(data).Returns(projects);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(Arg.Any<Guid>(), userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), userId, AccessClientType.User)
|
||||||
|
.Returns((true, true));
|
||||||
|
|
||||||
var results = await sutProvider.Sut.DeleteProjects(data, userId);
|
var results = await sutProvider.Sut.DeleteProjects(data, userId);
|
||||||
|
|
||||||
@ -74,7 +76,8 @@ public class DeleteProjectCommandTests
|
|||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ClientType = ClientType.User;
|
sutProvider.GetDependency<ICurrentContext>().ClientType = ClientType.User;
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetManyWithSecretsByIds(data).Returns(projects);
|
sutProvider.GetDependency<IProjectRepository>().GetManyWithSecretsByIds(data).Returns(projects);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(userId, userId).Returns(false);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), userId, AccessClientType.User)
|
||||||
|
.Returns((false, false));
|
||||||
|
|
||||||
var results = await sutProvider.Sut.DeleteProjects(data, userId);
|
var results = await sutProvider.Sut.DeleteProjects(data, userId);
|
||||||
|
|
||||||
@ -96,6 +99,9 @@ public class DeleteProjectCommandTests
|
|||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(true);
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetManyWithSecretsByIds(data).Returns(projects);
|
sutProvider.GetDependency<IProjectRepository>().GetManyWithSecretsByIds(data).Returns(projects);
|
||||||
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), userId, AccessClientType.NoAccessCheck)
|
||||||
|
.Returns((true, true));
|
||||||
|
|
||||||
|
|
||||||
var results = await sutProvider.Sut.DeleteProjects(data, userId);
|
var results = await sutProvider.Sut.DeleteProjects(data, userId);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Bit.Commercial.Core.SecretsManager.Commands.Projects;
|
using Bit.Commercial.Core.SecretsManager.Commands.Projects;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
@ -35,6 +36,8 @@ public class UpdateProjectCommandTests
|
|||||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(true);
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(project.OrganizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(project.OrganizationId).Returns(true);
|
||||||
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(project.Id, userId, AccessClientType.NoAccessCheck)
|
||||||
|
.Returns((true, true));
|
||||||
|
|
||||||
var project2 = new Project { Id = project.Id, Name = "newName" };
|
var project2 = new Project { Id = project.Id, Name = "newName" };
|
||||||
var result = await sutProvider.Sut.UpdateAsync(project2, userId);
|
var result = await sutProvider.Sut.UpdateAsync(project2, userId);
|
||||||
@ -51,7 +54,8 @@ public class UpdateProjectCommandTests
|
|||||||
public async Task UpdateAsync_User_NoAccess(Project project, Guid userId, SutProvider<UpdateProjectCommand> sutProvider)
|
public async Task UpdateAsync_User_NoAccess(Project project, Guid userId, SutProvider<UpdateProjectCommand> sutProvider)
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(project.Id, userId).Returns(false);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(project.Id, userId, AccessClientType.User)
|
||||||
|
.Returns((false, false));
|
||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(true);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(project, userId));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(project, userId));
|
||||||
@ -64,7 +68,8 @@ public class UpdateProjectCommandTests
|
|||||||
public async Task UpdateAsync_User_Success(Project project, Guid userId, SutProvider<UpdateProjectCommand> sutProvider)
|
public async Task UpdateAsync_User_Success(Project project, Guid userId, SutProvider<UpdateProjectCommand> sutProvider)
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(project.Id).Returns(project);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(project.Id, userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(project.Id, userId, AccessClientType.User)
|
||||||
|
.Returns((true, true));
|
||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(project.OrganizationId).Returns(true);
|
||||||
|
|
||||||
var project2 = new Project { Id = project.Id, Name = "newName" };
|
var project2 = new Project { Id = project.Id, Name = "newName" };
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Bit.Commercial.Core.SecretsManager.Commands.Secrets;
|
using Bit.Commercial.Core.SecretsManager.Commands.Secrets;
|
||||||
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
@ -30,11 +31,14 @@ public class CreateSecretCommandTests
|
|||||||
if (permissionType == PermissionType.RunAsAdmin)
|
if (permissionType == PermissionType.RunAsAdmin)
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(true);
|
||||||
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync((Guid)data.Projects?.First().Id, userId, AccessClientType.NoAccessCheck)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject((Guid)(data.Projects?.First().Id), userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync((Guid)data.Projects?.First().Id, userId, AccessClientType.User)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
await sutProvider.Sut.CreateAsync(data, userId);
|
await sutProvider.Sut.CreateAsync(data, userId);
|
||||||
@ -52,7 +56,8 @@ public class CreateSecretCommandTests
|
|||||||
data.Projects = new List<Project>() { mockProject };
|
data.Projects = new List<Project>() { mockProject };
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject((Guid)(data.Projects?.First().Id), userId).Returns(false);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync((Guid)data.Projects?.First().Id, userId, AccessClientType.User)
|
||||||
|
.Returns((false, false));
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||||
sutProvider.Sut.CreateAsync(data, userId));
|
sutProvider.Sut.CreateAsync(data, userId));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Bit.Commercial.Core.SecretsManager.Commands.Secrets;
|
using Bit.Commercial.Core.SecretsManager.Commands.Secrets;
|
||||||
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
@ -60,7 +61,8 @@ public class DeleteSecretCommandTests
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(mockProject.Id, userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(mockProject.Id, userId, AccessClientType.User)
|
||||||
|
.Returns((true, true));
|
||||||
projects = new List<Project>() { mockProject };
|
projects = new List<Project>() { mockProject };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Bit.Commercial.Core.SecretsManager.Commands.Secrets;
|
using Bit.Commercial.Core.SecretsManager.Commands.Secrets;
|
||||||
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
using Bit.Commercial.Core.Test.SecretsManager.Enums;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
@ -46,7 +47,9 @@ public class UpdateSecretCommandTests
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(data.OrganizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject((Guid)(data.Projects?.First().Id), userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>()
|
||||||
|
.AccessToProjectAsync((Guid)data.Projects?.First().Id, userId, AccessClientType.User)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(data.Id).Returns(data);
|
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(data.Id).Returns(data);
|
||||||
|
@ -249,14 +249,8 @@ public class AccessPoliciesController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (accessClient, userId) = await GetAccessClientTypeAsync(project.OrganizationId);
|
var (accessClient, userId) = await GetAccessClientTypeAsync(project.OrganizationId);
|
||||||
var hasAccess = accessClient switch
|
var access = await _projectRepository.AccessToProjectAsync(project.Id, userId, accessClient);
|
||||||
{
|
if (!access.Write || accessClient == AccessClientType.ServiceAccount)
|
||||||
AccessClientType.NoAccessCheck => true,
|
|
||||||
AccessClientType.User => await _projectRepository.UserHasWriteAccessToProject(project.Id, userId),
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!hasAccess)
|
|
||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,9 @@ public class ProjectsController : Controller
|
|||||||
|
|
||||||
var userId = _userService.GetProperUserId(User).Value;
|
var userId = _userService.GetProperUserId(User).Value;
|
||||||
var result = await _createProjectCommand.CreateAsync(createRequest.ToProject(organizationId), userId);
|
var result = await _createProjectCommand.CreateAsync(createRequest.ToProject(organizationId), userId);
|
||||||
return new ProjectResponseModel(result);
|
|
||||||
|
// Creating a project means you have read & write permission.
|
||||||
|
return new ProjectResponseModel(result, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("projects/{id}")]
|
[HttpPut("projects/{id}")]
|
||||||
@ -76,11 +78,13 @@ public class ProjectsController : Controller
|
|||||||
var userId = _userService.GetProperUserId(User).Value;
|
var userId = _userService.GetProperUserId(User).Value;
|
||||||
|
|
||||||
var result = await _updateProjectCommand.UpdateAsync(updateRequest.ToProject(id), userId);
|
var result = await _updateProjectCommand.UpdateAsync(updateRequest.ToProject(id), userId);
|
||||||
return new ProjectResponseModel(result);
|
|
||||||
|
// Updating a project means you have read & write permission.
|
||||||
|
return new ProjectResponseModel(result, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("projects/{id}")]
|
[HttpGet("projects/{id}")]
|
||||||
public async Task<ProjectPermissionDetailsResponseModel> GetAsync([FromRoute] Guid id)
|
public async Task<ProjectResponseModel> GetAsync([FromRoute] Guid id)
|
||||||
{
|
{
|
||||||
var project = await _projectRepository.GetByIdAsync(id);
|
var project = await _projectRepository.GetByIdAsync(id);
|
||||||
if (project == null)
|
if (project == null)
|
||||||
@ -104,7 +108,7 @@ public class ProjectsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ProjectPermissionDetailsResponseModel(project, access.Read, access.Write);
|
return new ProjectResponseModel(project, access.Read, access.Write);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("projects/delete")]
|
[HttpPost("projects/delete")]
|
||||||
|
@ -47,7 +47,7 @@ public class SecretsManagerPortingController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SMExportResponseModel(projects, secrets.Select(s => s.Secret));
|
return new SMExportResponseModel(projects.Select(p => p.Project), secrets.Select(s => s.Secret));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("sm/{organizationId}/import")]
|
[HttpPost("sm/{organizationId}/import")]
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
using Bit.Core.SecretsManager.Entities;
|
|
||||||
|
|
||||||
namespace Bit.Api.SecretsManager.Models.Response;
|
|
||||||
|
|
||||||
public class ProjectPermissionDetailsResponseModel : ProjectResponseModel
|
|
||||||
{
|
|
||||||
private const string _objectName = "projectPermissionDetails";
|
|
||||||
|
|
||||||
public ProjectPermissionDetailsResponseModel(Project project, bool read, bool write, string obj = _objectName) : base(project, obj)
|
|
||||||
{
|
|
||||||
Read = read;
|
|
||||||
Write = write;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectPermissionDetailsResponseModel()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Read { get; set; }
|
|
||||||
|
|
||||||
public bool Write { get; set; }
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Api.SecretsManager.Models.Response;
|
namespace Bit.Api.SecretsManager.Models.Response;
|
||||||
|
|
||||||
@ -7,7 +8,7 @@ public class ProjectResponseModel : ResponseModel
|
|||||||
{
|
{
|
||||||
private const string _objectName = "project";
|
private const string _objectName = "project";
|
||||||
|
|
||||||
public ProjectResponseModel(Project project, string obj = _objectName)
|
public ProjectResponseModel(Project project, bool read, bool write, string obj = _objectName)
|
||||||
: base(obj)
|
: base(obj)
|
||||||
{
|
{
|
||||||
if (project == null)
|
if (project == null)
|
||||||
@ -20,6 +21,25 @@ public class ProjectResponseModel : ResponseModel
|
|||||||
Name = project.Name;
|
Name = project.Name;
|
||||||
CreationDate = project.CreationDate;
|
CreationDate = project.CreationDate;
|
||||||
RevisionDate = project.RevisionDate;
|
RevisionDate = project.RevisionDate;
|
||||||
|
Read = read;
|
||||||
|
Write = write;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectResponseModel(ProjectPermissionDetails projectDetails, string obj = _objectName)
|
||||||
|
: base(obj)
|
||||||
|
{
|
||||||
|
if (projectDetails == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(projectDetails));
|
||||||
|
}
|
||||||
|
|
||||||
|
Id = projectDetails.Project.Id.ToString();
|
||||||
|
OrganizationId = projectDetails.Project.OrganizationId.ToString();
|
||||||
|
Name = projectDetails.Project.Name;
|
||||||
|
CreationDate = projectDetails.Project.CreationDate;
|
||||||
|
RevisionDate = projectDetails.Project.RevisionDate;
|
||||||
|
Read = projectDetails.Read;
|
||||||
|
Write = projectDetails.Write;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProjectResponseModel() : base(_objectName)
|
public ProjectResponseModel() : base(_objectName)
|
||||||
@ -36,5 +56,7 @@ public class ProjectResponseModel : ResponseModel
|
|||||||
|
|
||||||
public DateTime RevisionDate { get; set; }
|
public DateTime RevisionDate { get; set; }
|
||||||
|
|
||||||
public IEnumerable<Guid> Secrets { get; set; }
|
public bool Read { get; set; }
|
||||||
|
|
||||||
|
public bool Write { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
namespace Bit.Core.SecretsManager.Models.Data;
|
namespace Bit.Core.SecretsManager.Models.Data;
|
||||||
|
|
||||||
public class ProjectPermissionDetails : Project
|
public class ProjectPermissionDetails
|
||||||
{
|
{
|
||||||
|
public Project Project { get; set; }
|
||||||
public bool Read { get; set; }
|
public bool Read { get; set; }
|
||||||
public bool Write { get; set; }
|
public bool Write { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ namespace Bit.Core.SecretsManager.Models.Data;
|
|||||||
|
|
||||||
public class SecretPermissionDetails
|
public class SecretPermissionDetails
|
||||||
{
|
{
|
||||||
public Secret Secret;
|
public Secret Secret { get; set; }
|
||||||
public bool Read { get; set; }
|
public bool Read { get; set; }
|
||||||
public bool Write { get; set; }
|
public bool Write { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Core.SecretsManager.Repositories;
|
namespace Bit.Core.SecretsManager.Repositories;
|
||||||
|
|
||||||
public interface IProjectRepository
|
public interface IProjectRepository
|
||||||
{
|
{
|
||||||
Task<IEnumerable<Project>> GetManyByOrganizationIdAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
Task<IEnumerable<ProjectPermissionDetails>> GetManyByOrganizationIdAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
||||||
Task<IEnumerable<Project>> GetManyByOrganizationIdWriteAccessAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
Task<IEnumerable<Project>> GetManyByOrganizationIdWriteAccessAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
||||||
Task<IEnumerable<Project>> GetManyWithSecretsByIds(IEnumerable<Guid> ids);
|
Task<IEnumerable<Project>> GetManyWithSecretsByIds(IEnumerable<Guid> ids);
|
||||||
Task<Project> GetByIdAsync(Guid id);
|
Task<Project> GetByIdAsync(Guid id);
|
||||||
@ -13,10 +14,6 @@ public interface IProjectRepository
|
|||||||
Task ReplaceAsync(Project project);
|
Task ReplaceAsync(Project project);
|
||||||
Task DeleteManyByIdAsync(IEnumerable<Guid> ids);
|
Task DeleteManyByIdAsync(IEnumerable<Guid> ids);
|
||||||
Task<IEnumerable<Project>> ImportAsync(IEnumerable<Project> projects);
|
Task<IEnumerable<Project>> ImportAsync(IEnumerable<Project> projects);
|
||||||
Task<bool> UserHasReadAccessToProject(Guid id, Guid userId);
|
|
||||||
Task<bool> UserHasWriteAccessToProject(Guid id, Guid userId);
|
|
||||||
Task<bool> ServiceAccountHasWriteAccessToProject(Guid id, Guid userId);
|
|
||||||
Task<bool> ServiceAccountHasReadAccessToProject(Guid id, Guid userId);
|
|
||||||
Task<(bool Read, bool Write)> AccessToProjectAsync(Guid id, Guid userId, AccessClientType accessType);
|
Task<(bool Read, bool Write)> AccessToProjectAsync(Guid id, Guid userId, AccessClientType accessType);
|
||||||
Task<bool> ProjectsAreInOrganization(List<Guid> projectIds, Guid organizationId);
|
Task<bool> ProjectsAreInOrganization(List<Guid> projectIds, Guid organizationId);
|
||||||
}
|
}
|
||||||
|
@ -304,7 +304,7 @@ public class ProjectsControllerTests : IClassFixture<ApiApplicationFactory>, IAs
|
|||||||
|
|
||||||
var response = await _client.GetAsync($"/projects/{project.Id}");
|
var response = await _client.GetAsync($"/projects/{project.Id}");
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
var result = await response.Content.ReadFromJsonAsync<ProjectPermissionDetailsResponseModel>();
|
var result = await response.Content.ReadFromJsonAsync<ProjectResponseModel>();
|
||||||
Assert.Equal(project.Name, result!.Name);
|
Assert.Equal(project.Name, result!.Name);
|
||||||
Assert.Equal(project.RevisionDate, result.RevisionDate);
|
Assert.Equal(project.RevisionDate, result.RevisionDate);
|
||||||
Assert.Equal(project.CreationDate, result.CreationDate);
|
Assert.Equal(project.CreationDate, result.CreationDate);
|
||||||
|
@ -255,7 +255,7 @@ public class SecretsControllerTests : IClassFixture<ApiApplicationFactory>, IAsy
|
|||||||
Name = _mockEncryptedString
|
Name = _mockEncryptedString
|
||||||
});
|
});
|
||||||
|
|
||||||
var orgUserId = (Guid)orgAdminUser.UserId;
|
var orgUserId = (Guid)orgAdminUser.UserId!;
|
||||||
|
|
||||||
if (permissionType == PermissionType.RunAsUserWithPermission)
|
if (permissionType == PermissionType.RunAsUserWithPermission)
|
||||||
{
|
{
|
||||||
@ -270,7 +270,7 @@ public class SecretsControllerTests : IClassFixture<ApiApplicationFactory>, IAsy
|
|||||||
GrantedProjectId = project.Id, OrganizationUserId = orgUser.Id , Read = true, Write = true,
|
GrantedProjectId = project.Id, OrganizationUserId = orgUser.Id , Read = true, Write = true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
orgUserId = (Guid)orgUser.UserId;
|
orgUserId = (Guid)orgUser.UserId!;
|
||||||
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
|
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,11 +102,13 @@ public class AccessPoliciesControllerTests
|
|||||||
{
|
{
|
||||||
case PermissionType.RunAsAdmin:
|
case PermissionType.RunAsAdmin:
|
||||||
SetupAdmin(sutProvider, data.OrganizationId);
|
SetupAdmin(sutProvider, data.OrganizationId);
|
||||||
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), AccessClientType.NoAccessCheck)
|
||||||
|
.Returns((true, true));
|
||||||
break;
|
break;
|
||||||
case PermissionType.RunAsUserWithPermission:
|
case PermissionType.RunAsUserWithPermission:
|
||||||
SetupUserWithPermission(sutProvider, data.OrganizationId);
|
SetupUserWithPermission(sutProvider, data.OrganizationId);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(default, default)
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), AccessClientType.User)
|
||||||
.ReturnsForAnyArgs(true);
|
.Returns((true, true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,8 +131,8 @@ public class AccessPoliciesControllerTests
|
|||||||
{
|
{
|
||||||
SetupUserWithoutPermission(sutProvider, data.OrganizationId);
|
SetupUserWithoutPermission(sutProvider, data.OrganizationId);
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(default).ReturnsForAnyArgs(data);
|
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(default).ReturnsForAnyArgs(data);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(default, default)
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(default, default, default)
|
||||||
.ReturnsForAnyArgs(false);
|
.Returns((false, false));
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetProjectAccessPoliciesAsync(id));
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetProjectAccessPoliciesAsync(id));
|
||||||
|
|
||||||
@ -153,11 +155,13 @@ public class AccessPoliciesControllerTests
|
|||||||
{
|
{
|
||||||
case PermissionType.RunAsAdmin:
|
case PermissionType.RunAsAdmin:
|
||||||
SetupAdmin(sutProvider, data.OrganizationId);
|
SetupAdmin(sutProvider, data.OrganizationId);
|
||||||
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), AccessClientType.NoAccessCheck)
|
||||||
|
.Returns((true, true));
|
||||||
break;
|
break;
|
||||||
case PermissionType.RunAsUserWithPermission:
|
case PermissionType.RunAsUserWithPermission:
|
||||||
SetupUserWithPermission(sutProvider, data.OrganizationId);
|
SetupUserWithPermission(sutProvider, data.OrganizationId);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(default, default)
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), AccessClientType.User)
|
||||||
.ReturnsForAnyArgs(true);
|
.Returns((true, true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,8 +188,8 @@ public class AccessPoliciesControllerTests
|
|||||||
{
|
{
|
||||||
SetupUserWithoutPermission(sutProvider, data.OrganizationId);
|
SetupUserWithoutPermission(sutProvider, data.OrganizationId);
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(default).ReturnsForAnyArgs(data);
|
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(default).ReturnsForAnyArgs(data);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasWriteAccessToProject(default, default)
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(default, default, default)
|
||||||
.ReturnsForAnyArgs(false);
|
.Returns((false, false));
|
||||||
|
|
||||||
sutProvider.GetDependency<IAccessPolicyRepository>().GetManyByGrantedProjectIdAsync(default, default)
|
sutProvider.GetDependency<IAccessPolicyRepository>().GetManyByGrantedProjectIdAsync(default, default)
|
||||||
.ReturnsForAnyArgs(new List<BaseAccessPolicy> { resultAccessPolicy });
|
.ReturnsForAnyArgs(new List<BaseAccessPolicy> { resultAccessPolicy });
|
||||||
|
@ -6,6 +6,7 @@ using Bit.Core.Enums;
|
|||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.SecretsManager.Commands.Projects.Interfaces;
|
using Bit.Core.SecretsManager.Commands.Projects.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Test.SecretsManager.AutoFixture.ProjectsFixture;
|
using Bit.Core.Test.SecretsManager.AutoFixture.ProjectsFixture;
|
||||||
@ -88,7 +89,7 @@ public class ProjectsControllerTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetManyByOrganizationIdAsync(default, default, default)
|
sutProvider.GetDependency<IProjectRepository>().GetManyByOrganizationIdAsync(default, default, default)
|
||||||
.ReturnsForAnyArgs(new List<Project> { mockProject });
|
.ReturnsForAnyArgs(new List<ProjectPermissionDetails> { new() { Project = mockProject, Read = true, Write = true } });
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ListByOrganizationAsync(data);
|
var result = await sutProvider.Sut.ListByOrganizationAsync(data);
|
||||||
|
|
||||||
@ -193,8 +194,8 @@ public class ProjectsControllerTests
|
|||||||
break;
|
break;
|
||||||
case PermissionType.RunAsUserWithPermission:
|
case PermissionType.RunAsUserWithPermission:
|
||||||
SetupUserWithPermission(sutProvider, orgId);
|
SetupUserWithPermission(sutProvider, orgId);
|
||||||
sutProvider.GetDependency<IProjectRepository>()
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(default, default, default)
|
||||||
.UserHasReadAccessToProject(Arg.Is(data), Arg.Any<Guid>()).ReturnsForAnyArgs(true);
|
.Returns((true, true));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,8 +217,8 @@ public class ProjectsControllerTests
|
|||||||
Guid data)
|
Guid data)
|
||||||
{
|
{
|
||||||
SetupUserWithPermission(sutProvider, orgId);
|
SetupUserWithPermission(sutProvider, orgId);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasReadAccessToProject(Arg.Is(data), Arg.Any<Guid>())
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(default, default, default)
|
||||||
.ReturnsForAnyArgs(false);
|
.Returns((false, false));
|
||||||
|
|
||||||
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(Arg.Is(data))
|
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(Arg.Is(data))
|
||||||
.ReturnsForAnyArgs(new Project { Id = data, OrganizationId = orgId });
|
.ReturnsForAnyArgs(new Project { Id = data, OrganizationId = orgId });
|
||||||
|
@ -61,7 +61,8 @@ public class SecretsControllerTests
|
|||||||
{
|
{
|
||||||
resultSecret.Projects = new List<Core.SecretsManager.Entities.Project>() { mockProject };
|
resultSecret.Projects = new List<Core.SecretsManager.Entities.Project>() { mockProject };
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasReadAccessToProject(mockProject.Id, userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(default, default, default)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -107,11 +108,14 @@ public class SecretsControllerTests
|
|||||||
{
|
{
|
||||||
resultSecret.OrganizationId = organizationId;
|
resultSecret.OrganizationId = organizationId;
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(true);
|
||||||
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), AccessClientType.NoAccessCheck)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasReadAccessToProject(mockProject.Id, userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), AccessClientType.User)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
await sutProvider.Sut.GetAsync(resultSecret.Id);
|
await sutProvider.Sut.GetAsync(resultSecret.Id);
|
||||||
@ -142,7 +146,8 @@ public class SecretsControllerTests
|
|||||||
{
|
{
|
||||||
resultSecret.Projects = new List<Core.SecretsManager.Entities.Project>() { mockProject };
|
resultSecret.Projects = new List<Core.SecretsManager.Entities.Project>() { mockProject };
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasReadAccessToProject(mockProject.Id, userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(Arg.Any<Guid>(), Arg.Any<Guid>(), AccessClientType.User)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(organizationId).Returns(true);
|
||||||
@ -174,7 +179,8 @@ public class SecretsControllerTests
|
|||||||
{
|
{
|
||||||
data.ProjectIds = new Guid[] { mockProject.Id };
|
data.ProjectIds = new Guid[] { mockProject.Id };
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasReadAccessToProject(mockProject.Id, userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(default, default, default)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultSecret = data.ToSecret(secretId);
|
var resultSecret = data.ToSecret(secretId);
|
||||||
@ -200,7 +206,8 @@ public class SecretsControllerTests
|
|||||||
{
|
{
|
||||||
data.FirstOrDefault().Projects = new List<Project>() { mockProject };
|
data.FirstOrDefault().Projects = new List<Project>() { mockProject };
|
||||||
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().OrganizationAdmin(organizationId).Returns(false);
|
||||||
sutProvider.GetDependency<IProjectRepository>().UserHasReadAccessToProject(mockProject.Id, userId).Returns(true);
|
sutProvider.GetDependency<IProjectRepository>().AccessToProjectAsync(default, default, default)
|
||||||
|
.Returns((true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user