mirror of
https://github.com/bitwarden/server
synced 2025-12-28 22:23:30 +00:00
[SM-919] Add project people access policy management endpoints (#3285)
* Expose access policy discriminators * Add people policy model and auth handler * Add unit tests for authz handler * Add people policies support in repo * Add new endpoints and request/response models * Update tests
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
namespace Bit.Api.SecretsManager.Models.Request;
|
||||
|
||||
public class PeopleAccessPoliciesRequestModel
|
||||
{
|
||||
public IEnumerable<AccessPolicyRequest> UserAccessPolicyRequests { get; set; }
|
||||
|
||||
public IEnumerable<AccessPolicyRequest> GroupAccessPolicyRequests { get; set; }
|
||||
|
||||
private static void CheckForDistinctAccessPolicies(IReadOnlyCollection<BaseAccessPolicy> accessPolicies)
|
||||
{
|
||||
var distinctAccessPolicies = accessPolicies.DistinctBy(baseAccessPolicy =>
|
||||
{
|
||||
return baseAccessPolicy switch
|
||||
{
|
||||
UserProjectAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.OrganizationUserId, ap.GrantedProjectId),
|
||||
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();
|
||||
|
||||
if (accessPolicies.Count != distinctAccessPolicies.Count)
|
||||
{
|
||||
throw new BadRequestException("Resources must be unique");
|
||||
}
|
||||
}
|
||||
|
||||
public ProjectPeopleAccessPolicies ToProjectPeopleAccessPolicies(Guid grantedProjectId, Guid organizationId)
|
||||
{
|
||||
var userAccessPolicies = UserAccessPolicyRequests?
|
||||
.Select(x => x.ToUserProjectAccessPolicy(grantedProjectId, organizationId)).ToList();
|
||||
|
||||
var groupAccessPolicies = GroupAccessPolicyRequests?
|
||||
.Select(x => x.ToGroupProjectAccessPolicy(grantedProjectId, organizationId)).ToList();
|
||||
var policies = new List<BaseAccessPolicy>();
|
||||
if (userAccessPolicies != null)
|
||||
{
|
||||
policies.AddRange(userAccessPolicies);
|
||||
}
|
||||
|
||||
if (groupAccessPolicies != null)
|
||||
{
|
||||
policies.AddRange(groupAccessPolicies);
|
||||
}
|
||||
|
||||
CheckForDistinctAccessPolicies(policies);
|
||||
|
||||
return new ProjectPeopleAccessPolicies
|
||||
{
|
||||
Id = grantedProjectId,
|
||||
OrganizationId = organizationId,
|
||||
UserAccessPolicies = userAccessPolicies,
|
||||
GroupAccessPolicies = groupAccessPolicies
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -34,10 +34,13 @@ public class UserProjectAccessPolicyResponseModel : BaseAccessPolicyResponseMode
|
||||
|
||||
public UserProjectAccessPolicyResponseModel(UserProjectAccessPolicy accessPolicy) : base(accessPolicy, _objectName)
|
||||
{
|
||||
OrganizationUserId = accessPolicy.OrganizationUserId;
|
||||
GrantedProjectId = accessPolicy.GrantedProjectId;
|
||||
OrganizationUserName = GetUserDisplayName(accessPolicy.User);
|
||||
UserId = accessPolicy.User?.Id;
|
||||
SetProperties(accessPolicy);
|
||||
}
|
||||
|
||||
public UserProjectAccessPolicyResponseModel(UserProjectAccessPolicy accessPolicy, Guid currentUserId) : base(accessPolicy, _objectName)
|
||||
{
|
||||
CurrentUser = currentUserId == accessPolicy.User?.Id;
|
||||
SetProperties(accessPolicy);
|
||||
}
|
||||
|
||||
public UserProjectAccessPolicyResponseModel() : base(new UserProjectAccessPolicy(), _objectName)
|
||||
@@ -48,6 +51,15 @@ public class UserProjectAccessPolicyResponseModel : BaseAccessPolicyResponseMode
|
||||
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
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
namespace Bit.Api.SecretsManager.Models.Response;
|
||||
|
||||
@@ -9,31 +8,33 @@ public class PotentialGranteeResponseModel : ResponseModel
|
||||
{
|
||||
private const string _objectName = "potentialGrantee";
|
||||
|
||||
public PotentialGranteeResponseModel(Group group)
|
||||
public PotentialGranteeResponseModel(GroupGrantee grantee)
|
||||
: base(_objectName)
|
||||
{
|
||||
if (group == null)
|
||||
if (grantee == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(group));
|
||||
throw new ArgumentNullException(nameof(grantee));
|
||||
}
|
||||
|
||||
Id = group.Id;
|
||||
Name = group.Name;
|
||||
Type = "group";
|
||||
Id = grantee.GroupId;
|
||||
Name = grantee.Name;
|
||||
CurrentUserInGroup = grantee.CurrentUserInGroup;
|
||||
}
|
||||
|
||||
public PotentialGranteeResponseModel(OrganizationUserUserDetails user)
|
||||
public PotentialGranteeResponseModel(UserGrantee grantee)
|
||||
: base(_objectName)
|
||||
{
|
||||
if (user == null)
|
||||
if (grantee == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
throw new ArgumentNullException(nameof(grantee));
|
||||
}
|
||||
|
||||
Id = user.Id;
|
||||
Name = user.Name;
|
||||
Email = user.Email;
|
||||
Type = "user";
|
||||
Id = grantee.OrganizationUserId;
|
||||
Name = grantee.Name;
|
||||
Email = grantee.Email;
|
||||
CurrentUser = grantee.CurrentUser;
|
||||
}
|
||||
|
||||
public PotentialGranteeResponseModel(ServiceAccount serviceAccount)
|
||||
@@ -67,9 +68,9 @@ public class PotentialGranteeResponseModel : ResponseModel
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
public string Email { get; set; }
|
||||
public bool CurrentUserInGroup { get; set; }
|
||||
public bool CurrentUser { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
|
||||
namespace Bit.Api.SecretsManager.Models.Response;
|
||||
|
||||
public class ProjectPeopleAccessPoliciesResponseModel : ResponseModel
|
||||
{
|
||||
private const string _objectName = "projectPeopleAccessPolicies";
|
||||
|
||||
public ProjectPeopleAccessPoliciesResponseModel(IEnumerable<BaseAccessPolicy> baseAccessPolicies, Guid userId)
|
||||
: base(_objectName)
|
||||
{
|
||||
foreach (var baseAccessPolicy in baseAccessPolicies)
|
||||
{
|
||||
switch (baseAccessPolicy)
|
||||
{
|
||||
case UserProjectAccessPolicy accessPolicy:
|
||||
UserAccessPolicies.Add(new UserProjectAccessPolicyResponseModel(accessPolicy, userId));
|
||||
break;
|
||||
case GroupProjectAccessPolicy accessPolicy:
|
||||
GroupAccessPolicies.Add(new GroupProjectAccessPolicyResponseModel(accessPolicy));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ProjectPeopleAccessPoliciesResponseModel() : base(_objectName)
|
||||
{
|
||||
}
|
||||
|
||||
public List<UserProjectAccessPolicyResponseModel> UserAccessPolicies { get; set; } = new();
|
||||
|
||||
public List<GroupProjectAccessPolicyResponseModel> GroupAccessPolicies { get; set; } = new();
|
||||
}
|
||||
Reference in New Issue
Block a user