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

[SM-1293] Add endpoint to fetch secret's access policies (#4146)

* Add authz handling for secret access policy reads

* Add the ability to fetch secret access polices from the repository

* refactor response models

* Add new endpoint
This commit is contained in:
Thomas Avery
2024-06-07 12:08:38 -05:00
committed by GitHub
parent a1d609b208
commit 36705790ad
17 changed files with 554 additions and 143 deletions

View File

@ -24,6 +24,7 @@ public class AccessPoliciesController : Controller
private readonly IAuthorizationService _authorizationService;
private readonly ICurrentContext _currentContext;
private readonly IProjectRepository _projectRepository;
private readonly ISecretRepository _secretRepository;
private readonly IServiceAccountGrantedPolicyUpdatesQuery _serviceAccountGrantedPolicyUpdatesQuery;
private readonly IServiceAccountRepository _serviceAccountRepository;
private readonly IUpdateServiceAccountGrantedPoliciesCommand _updateServiceAccountGrantedPoliciesCommand;
@ -41,6 +42,7 @@ public class AccessPoliciesController : Controller
IAccessPolicyRepository accessPolicyRepository,
IServiceAccountRepository serviceAccountRepository,
IProjectRepository projectRepository,
ISecretRepository secretRepository,
IAccessClientQuery accessClientQuery,
IServiceAccountGrantedPolicyUpdatesQuery serviceAccountGrantedPolicyUpdatesQuery,
IProjectServiceAccountsAccessPoliciesUpdatesQuery projectServiceAccountsAccessPoliciesUpdatesQuery,
@ -52,6 +54,7 @@ public class AccessPoliciesController : Controller
_currentContext = currentContext;
_serviceAccountRepository = serviceAccountRepository;
_projectRepository = projectRepository;
_secretRepository = secretRepository;
_accessPolicyRepository = accessPolicyRepository;
_updateServiceAccountGrantedPoliciesCommand = updateServiceAccountGrantedPoliciesCommand;
_accessClientQuery = accessClientQuery;
@ -259,6 +262,22 @@ public class AccessPoliciesController : Controller
return new ProjectServiceAccountsAccessPoliciesResponseModel(results);
}
[HttpGet("/secrets/{secretId}/access-policies")]
public async Task<SecretAccessPoliciesResponseModel> GetSecretAccessPoliciesAsync(Guid secretId)
{
var secret = await _secretRepository.GetByIdAsync(secretId);
var authorizationResult = await _authorizationService.AuthorizeAsync(User, secret, SecretOperations.ReadAccessPolicies);
if (!authorizationResult.Succeeded)
{
throw new NotFoundException();
}
var userId = _userService.GetProperUserId(User)!.Value;
var accessPolicies = await _accessPolicyRepository.GetSecretAccessPoliciesAsync(secretId, userId);
return new SecretAccessPoliciesResponseModel(accessPolicies, userId);
}
private async Task<(AccessClientType AccessClientType, Guid UserId)> CheckUserHasWriteAccessToProjectAsync(
Project project)
{

View File

@ -9,161 +9,133 @@ public abstract class BaseAccessPolicyResponseModel : ResponseModel
{
protected BaseAccessPolicyResponseModel(BaseAccessPolicy baseAccessPolicy, string obj) : base(obj)
{
Id = baseAccessPolicy.Id;
Read = baseAccessPolicy.Read;
Write = baseAccessPolicy.Write;
CreationDate = baseAccessPolicy.CreationDate;
RevisionDate = baseAccessPolicy.RevisionDate;
}
public Guid Id { get; set; }
public bool Read { get; set; }
public bool Write { get; set; }
public DateTime CreationDate { get; set; }
public DateTime RevisionDate { get; set; }
public string? GetUserDisplayName(User? user)
protected static string? GetUserDisplayName(User? user)
{
return string.IsNullOrWhiteSpace(user?.Name) ? user?.Email : user?.Name;
}
}
public class UserProjectAccessPolicyResponseModel : BaseAccessPolicyResponseModel
public class UserAccessPolicyResponseModel : BaseAccessPolicyResponseModel
{
private const string _objectName = "userProjectAccessPolicy";
private const string _objectName = "userAccessPolicy";
public UserProjectAccessPolicyResponseModel(UserProjectAccessPolicy accessPolicy) : base(accessPolicy, _objectName)
{
SetProperties(accessPolicy);
}
public UserProjectAccessPolicyResponseModel(UserProjectAccessPolicy accessPolicy, Guid currentUserId) : base(accessPolicy, _objectName)
public UserAccessPolicyResponseModel(UserProjectAccessPolicy accessPolicy, Guid currentUserId) : base(accessPolicy, _objectName)
{
CurrentUser = currentUserId == accessPolicy.User?.Id;
SetProperties(accessPolicy);
OrganizationUserId = accessPolicy.OrganizationUserId;
OrganizationUserName = GetUserDisplayName(accessPolicy.User);
}
public UserProjectAccessPolicyResponseModel() : base(new UserProjectAccessPolicy(), _objectName)
public UserAccessPolicyResponseModel(UserServiceAccountAccessPolicy accessPolicy, Guid currentUserId) : base(accessPolicy, _objectName)
{
CurrentUser = currentUserId == accessPolicy.User?.Id;
OrganizationUserId = accessPolicy.OrganizationUserId;
OrganizationUserName = GetUserDisplayName(accessPolicy.User);
}
public UserAccessPolicyResponseModel(UserSecretAccessPolicy accessPolicy, Guid currentUserId) : base(accessPolicy, _objectName)
{
CurrentUser = currentUserId == accessPolicy.User?.Id;
OrganizationUserId = accessPolicy.OrganizationUserId;
OrganizationUserName = GetUserDisplayName(accessPolicy.User);
}
public UserAccessPolicyResponseModel() : base(new UserProjectAccessPolicy(), _objectName)
{
}
public Guid? OrganizationUserId { get; set; }
public string? OrganizationUserName { get; set; }
public Guid? UserId { get; set; }
public Guid? GrantedProjectId { get; set; }
public bool? CurrentUser { get; set; }
private void SetProperties(UserProjectAccessPolicy accessPolicy)
{
OrganizationUserId = accessPolicy.OrganizationUserId;
GrantedProjectId = accessPolicy.GrantedProjectId;
OrganizationUserName = GetUserDisplayName(accessPolicy.User);
UserId = accessPolicy.User?.Id;
}
}
public class UserServiceAccountAccessPolicyResponseModel : BaseAccessPolicyResponseModel
public class GroupAccessPolicyResponseModel : BaseAccessPolicyResponseModel
{
private const string _objectName = "userServiceAccountAccessPolicy";
private const string _objectName = "groupAccessPolicy";
public UserServiceAccountAccessPolicyResponseModel(UserServiceAccountAccessPolicy accessPolicy)
: base(accessPolicy, _objectName)
{
SetProperties(accessPolicy);
}
public UserServiceAccountAccessPolicyResponseModel(UserServiceAccountAccessPolicy accessPolicy, Guid userId)
: base(accessPolicy, _objectName)
{
SetProperties(accessPolicy);
CurrentUser = accessPolicy.User?.Id == userId;
}
public UserServiceAccountAccessPolicyResponseModel() : base(new UserServiceAccountAccessPolicy(), _objectName)
{
}
public Guid? OrganizationUserId { get; set; }
public string? OrganizationUserName { get; set; }
public Guid? UserId { get; set; }
public Guid? GrantedServiceAccountId { get; set; }
public bool CurrentUser { get; set; }
private void SetProperties(UserServiceAccountAccessPolicy accessPolicy)
{
OrganizationUserId = accessPolicy.OrganizationUserId;
GrantedServiceAccountId = accessPolicy.GrantedServiceAccountId;
OrganizationUserName = GetUserDisplayName(accessPolicy.User);
UserId = accessPolicy.User?.Id;
}
}
public class GroupProjectAccessPolicyResponseModel : BaseAccessPolicyResponseModel
{
private const string _objectName = "groupProjectAccessPolicy";
public GroupProjectAccessPolicyResponseModel(GroupProjectAccessPolicy accessPolicy)
public GroupAccessPolicyResponseModel(GroupProjectAccessPolicy accessPolicy)
: base(accessPolicy, _objectName)
{
GroupId = accessPolicy.GroupId;
GrantedProjectId = accessPolicy.GrantedProjectId;
GroupName = accessPolicy.Group?.Name;
CurrentUserInGroup = accessPolicy.CurrentUserInGroup;
}
public GroupProjectAccessPolicyResponseModel() : base(new GroupProjectAccessPolicy(), _objectName)
public GroupAccessPolicyResponseModel(GroupServiceAccountAccessPolicy accessPolicy)
: base(accessPolicy, _objectName)
{
GroupId = accessPolicy.GroupId;
GroupName = accessPolicy.Group?.Name;
CurrentUserInGroup = accessPolicy.CurrentUserInGroup;
}
public GroupAccessPolicyResponseModel(GroupSecretAccessPolicy accessPolicy)
: base(accessPolicy, _objectName)
{
GroupId = accessPolicy.GroupId;
GroupName = accessPolicy.Group?.Name;
CurrentUserInGroup = accessPolicy.CurrentUserInGroup;
}
public GroupAccessPolicyResponseModel() : base(new GroupProjectAccessPolicy(), _objectName)
{
}
public Guid? GroupId { get; set; }
public string? GroupName { get; set; }
public bool? CurrentUserInGroup { get; set; }
public Guid? GrantedProjectId { get; set; }
}
public class GroupServiceAccountAccessPolicyResponseModel : BaseAccessPolicyResponseModel
{
private const string _objectName = "groupServiceAccountAccessPolicy";
public GroupServiceAccountAccessPolicyResponseModel(GroupServiceAccountAccessPolicy accessPolicy)
: base(accessPolicy, _objectName)
{
GroupId = accessPolicy.GroupId;
GroupName = accessPolicy.Group?.Name;
GrantedServiceAccountId = accessPolicy.GrantedServiceAccountId;
CurrentUserInGroup = accessPolicy.CurrentUserInGroup;
}
public GroupServiceAccountAccessPolicyResponseModel() : base(new GroupServiceAccountAccessPolicy(), _objectName)
{
}
public Guid? GroupId { get; set; }
public string? GroupName { get; set; }
public Guid? GrantedServiceAccountId { get; set; }
public bool? CurrentUserInGroup { get; set; }
}
public class ServiceAccountProjectAccessPolicyResponseModel : BaseAccessPolicyResponseModel
public class ServiceAccountAccessPolicyResponseModel : BaseAccessPolicyResponseModel
{
private const string _objectName = "serviceAccountProjectAccessPolicy";
public ServiceAccountProjectAccessPolicyResponseModel(ServiceAccountProjectAccessPolicy accessPolicy)
public ServiceAccountAccessPolicyResponseModel(ServiceAccountProjectAccessPolicy accessPolicy)
: base(accessPolicy, _objectName)
{
ServiceAccountId = accessPolicy.ServiceAccountId;
GrantedProjectId = accessPolicy.GrantedProjectId;
ServiceAccountName = accessPolicy.ServiceAccount?.Name;
GrantedProjectName = accessPolicy.GrantedProject?.Name;
}
public ServiceAccountProjectAccessPolicyResponseModel()
public ServiceAccountAccessPolicyResponseModel(ServiceAccountSecretAccessPolicy accessPolicy)
: base(accessPolicy, _objectName)
{
ServiceAccountId = accessPolicy.ServiceAccountId;
ServiceAccountName = accessPolicy.ServiceAccount?.Name;
}
public ServiceAccountAccessPolicyResponseModel()
: base(new ServiceAccountProjectAccessPolicy(), _objectName)
{
}
public Guid? ServiceAccountId { get; set; }
public string? ServiceAccountName { get; set; }
}
public class GrantedProjectAccessPolicyResponseModel : BaseAccessPolicyResponseModel
{
private const string _objectName = "grantedProjectAccessPolicy";
public GrantedProjectAccessPolicyResponseModel(ServiceAccountProjectAccessPolicy accessPolicy)
: base(accessPolicy, _objectName)
{
GrantedProjectId = accessPolicy.GrantedProjectId;
GrantedProjectName = accessPolicy.GrantedProject?.Name;
}
public GrantedProjectAccessPolicyResponseModel()
: base(new ServiceAccountProjectAccessPolicy(), _objectName)
{
}
public Guid? GrantedProjectId { get; set; }
public string? GrantedProjectName { get; set; }
}

View File

@ -0,0 +1,25 @@
#nullable enable
using Bit.Core.Models.Api;
using Bit.Core.SecretsManager.Models.Data;
namespace Bit.Api.SecretsManager.Models.Response;
public class GrantedProjectAccessPolicyPermissionDetailsResponseModel : ResponseModel
{
private const string _objectName = "grantedProjectAccessPolicyPermissionDetails";
public GrantedProjectAccessPolicyPermissionDetailsResponseModel(
ServiceAccountProjectAccessPolicyPermissionDetails apPermissionDetails, string obj = _objectName) : base(obj)
{
AccessPolicy = new GrantedProjectAccessPolicyResponseModel(apPermissionDetails.AccessPolicy);
HasPermission = apPermissionDetails.HasPermission;
}
public GrantedProjectAccessPolicyPermissionDetailsResponseModel()
: base(_objectName)
{
}
public GrantedProjectAccessPolicyResponseModel AccessPolicy { get; set; } = new();
public bool HasPermission { get; set; }
}

View File

@ -15,10 +15,10 @@ public class ProjectPeopleAccessPoliciesResponseModel : ResponseModel
switch (baseAccessPolicy)
{
case UserProjectAccessPolicy accessPolicy:
UserAccessPolicies.Add(new UserProjectAccessPolicyResponseModel(accessPolicy, userId));
UserAccessPolicies.Add(new UserAccessPolicyResponseModel(accessPolicy, userId));
break;
case GroupProjectAccessPolicy accessPolicy:
GroupAccessPolicies.Add(new GroupProjectAccessPolicyResponseModel(accessPolicy));
GroupAccessPolicies.Add(new GroupAccessPolicyResponseModel(accessPolicy));
break;
}
}
@ -28,7 +28,7 @@ public class ProjectPeopleAccessPoliciesResponseModel : ResponseModel
{
}
public List<UserProjectAccessPolicyResponseModel> UserAccessPolicies { get; set; } = new();
public List<UserAccessPolicyResponseModel> UserAccessPolicies { get; set; } = new();
public List<GroupProjectAccessPolicyResponseModel> GroupAccessPolicies { get; set; } = new();
public List<GroupAccessPolicyResponseModel> GroupAccessPolicies { get; set; } = new();
}

View File

@ -18,12 +18,12 @@ public class ProjectServiceAccountsAccessPoliciesResponseModel : ResponseModel
}
ServiceAccountAccessPolicies = projectServiceAccountsAccessPolicies.ServiceAccountAccessPolicies
.Select(x => new ServiceAccountProjectAccessPolicyResponseModel(x)).ToList();
.Select(x => new ServiceAccountAccessPolicyResponseModel(x)).ToList();
}
public ProjectServiceAccountsAccessPoliciesResponseModel() : base(_objectName)
{
}
public List<ServiceAccountProjectAccessPolicyResponseModel> ServiceAccountAccessPolicies { get; set; } = [];
public List<ServiceAccountAccessPolicyResponseModel> ServiceAccountAccessPolicies { get; set; } = [];
}

View File

@ -0,0 +1,33 @@
#nullable enable
using Bit.Core.Models.Api;
using Bit.Core.SecretsManager.Models.Data;
namespace Bit.Api.SecretsManager.Models.Response;
public class SecretAccessPoliciesResponseModel : ResponseModel
{
private const string _objectName = "secretAccessPolicies";
public SecretAccessPoliciesResponseModel(SecretAccessPolicies? accessPolicies, Guid userId) :
base(_objectName)
{
if (accessPolicies == null)
{
return;
}
UserAccessPolicies = accessPolicies.UserAccessPolicies.Select(x => new UserAccessPolicyResponseModel(x, userId)).ToList();
GroupAccessPolicies = accessPolicies.GroupAccessPolicies.Select(x => new GroupAccessPolicyResponseModel(x)).ToList();
ServiceAccountAccessPolicies = accessPolicies.ServiceAccountAccessPolicies.Select(x => new ServiceAccountAccessPolicyResponseModel(x)).ToList();
}
public SecretAccessPoliciesResponseModel() : base(_objectName)
{
}
public List<UserAccessPolicyResponseModel> UserAccessPolicies { get; set; } = [];
public List<GroupAccessPolicyResponseModel> GroupAccessPolicies { get; set; } = [];
public List<ServiceAccountAccessPolicyResponseModel> ServiceAccountAccessPolicies { get; set; } = [];
}

View File

@ -18,13 +18,13 @@ public class ServiceAccountGrantedPoliciesPermissionDetailsResponseModel : Respo
}
GrantedProjectPolicies = grantedPoliciesPermissionDetails.ProjectGrantedPolicies
.Select(x => new ServiceAccountProjectAccessPolicyPermissionDetailsResponseModel(x)).ToList();
.Select(x => new GrantedProjectAccessPolicyPermissionDetailsResponseModel(x)).ToList();
}
public ServiceAccountGrantedPoliciesPermissionDetailsResponseModel() : base(_objectName)
{
}
public List<ServiceAccountProjectAccessPolicyPermissionDetailsResponseModel> GrantedProjectPolicies { get; set; } =
public List<GrantedProjectAccessPolicyPermissionDetailsResponseModel> GrantedProjectPolicies { get; set; } =
[];
}

View File

@ -20,10 +20,10 @@ public class ServiceAccountPeopleAccessPoliciesResponseModel : ResponseModel
switch (baseAccessPolicy)
{
case UserServiceAccountAccessPolicy accessPolicy:
UserAccessPolicies.Add(new UserServiceAccountAccessPolicyResponseModel(accessPolicy, userId));
UserAccessPolicies.Add(new UserAccessPolicyResponseModel(accessPolicy, userId));
break;
case GroupServiceAccountAccessPolicy accessPolicy:
GroupAccessPolicies.Add(new GroupServiceAccountAccessPolicyResponseModel(accessPolicy));
GroupAccessPolicies.Add(new GroupAccessPolicyResponseModel(accessPolicy));
break;
}
}
@ -33,7 +33,7 @@ public class ServiceAccountPeopleAccessPoliciesResponseModel : ResponseModel
{
}
public List<UserServiceAccountAccessPolicyResponseModel> UserAccessPolicies { get; set; } = new();
public List<UserAccessPolicyResponseModel> UserAccessPolicies { get; set; } = new();
public List<GroupServiceAccountAccessPolicyResponseModel> GroupAccessPolicies { get; set; } = new();
public List<GroupAccessPolicyResponseModel> GroupAccessPolicies { get; set; } = new();
}

View File

@ -1,25 +0,0 @@
#nullable enable
using Bit.Core.Models.Api;
using Bit.Core.SecretsManager.Models.Data;
namespace Bit.Api.SecretsManager.Models.Response;
public class ServiceAccountProjectAccessPolicyPermissionDetailsResponseModel : ResponseModel
{
private const string _objectName = "serviceAccountProjectAccessPolicyPermissionDetails";
public ServiceAccountProjectAccessPolicyPermissionDetailsResponseModel(
ServiceAccountProjectAccessPolicyPermissionDetails apPermissionDetails, string obj = _objectName) : base(obj)
{
AccessPolicy = new ServiceAccountProjectAccessPolicyResponseModel(apPermissionDetails.AccessPolicy);
HasPermission = apPermissionDetails.HasPermission;
}
public ServiceAccountProjectAccessPolicyPermissionDetailsResponseModel()
: base(_objectName)
{
}
public ServiceAccountProjectAccessPolicyResponseModel AccessPolicy { get; set; } = new();
public bool HasPermission { get; set; }
}