mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 07:36:14 -05:00
[SM-654] Individual secret permissions (#4160)
* Add new data and request models * Update authz handlers * Update secret commands to handle access policy updates * Update secret repository to handle access policy updates * Update secrets controller to handle access policy updates * Add tests * Add integration tests for secret create
This commit is contained in:
@ -10,6 +10,8 @@ using Bit.Core.SecretsManager.AuthorizationRequirements;
|
||||
using Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
using Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
using Bit.Core.SecretsManager.Queries.AccessPolicies.Interfaces;
|
||||
using Bit.Core.SecretsManager.Queries.Interfaces;
|
||||
using Bit.Core.SecretsManager.Queries.Secrets.Interfaces;
|
||||
using Bit.Core.SecretsManager.Repositories;
|
||||
@ -34,6 +36,7 @@ public class SecretsController : Controller
|
||||
private readonly IDeleteSecretCommand _deleteSecretCommand;
|
||||
private readonly IAccessClientQuery _accessClientQuery;
|
||||
private readonly ISecretsSyncQuery _secretsSyncQuery;
|
||||
private readonly ISecretAccessPoliciesUpdatesQuery _secretAccessPoliciesUpdatesQuery;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IEventService _eventService;
|
||||
private readonly IReferenceEventService _referenceEventService;
|
||||
@ -49,6 +52,7 @@ public class SecretsController : Controller
|
||||
IDeleteSecretCommand deleteSecretCommand,
|
||||
IAccessClientQuery accessClientQuery,
|
||||
ISecretsSyncQuery secretsSyncQuery,
|
||||
ISecretAccessPoliciesUpdatesQuery secretAccessPoliciesUpdatesQuery,
|
||||
IUserService userService,
|
||||
IEventService eventService,
|
||||
IReferenceEventService referenceEventService,
|
||||
@ -63,6 +67,7 @@ public class SecretsController : Controller
|
||||
_deleteSecretCommand = deleteSecretCommand;
|
||||
_accessClientQuery = accessClientQuery;
|
||||
_secretsSyncQuery = secretsSyncQuery;
|
||||
_secretAccessPoliciesUpdatesQuery = secretAccessPoliciesUpdatesQuery;
|
||||
_userService = userService;
|
||||
_eventService = eventService;
|
||||
_referenceEventService = referenceEventService;
|
||||
@ -88,7 +93,8 @@ public class SecretsController : Controller
|
||||
}
|
||||
|
||||
[HttpPost("organizations/{organizationId}/secrets")]
|
||||
public async Task<SecretResponseModel> CreateAsync([FromRoute] Guid organizationId, [FromBody] SecretCreateRequestModel createRequest)
|
||||
public async Task<SecretResponseModel> CreateAsync([FromRoute] Guid organizationId,
|
||||
[FromBody] SecretCreateRequestModel createRequest)
|
||||
{
|
||||
var secret = createRequest.ToSecret(organizationId);
|
||||
var authorizationResult = await _authorizationService.AuthorizeAsync(User, secret, SecretOperations.Create);
|
||||
@ -97,7 +103,22 @@ public class SecretsController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var result = await _createSecretCommand.CreateAsync(secret);
|
||||
SecretAccessPoliciesUpdates accessPoliciesUpdates = null;
|
||||
if (createRequest.AccessPoliciesRequests != null)
|
||||
{
|
||||
secret.SetNewId();
|
||||
accessPoliciesUpdates =
|
||||
new SecretAccessPoliciesUpdates(
|
||||
createRequest.AccessPoliciesRequests.ToSecretAccessPolicies(secret.Id, organizationId));
|
||||
var accessPolicyAuthorizationResult = await _authorizationService.AuthorizeAsync(User,
|
||||
accessPoliciesUpdates, SecretAccessPoliciesOperations.Create);
|
||||
if (!accessPolicyAuthorizationResult.Succeeded)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
}
|
||||
|
||||
var result = await _createSecretCommand.CreateAsync(secret, accessPoliciesUpdates);
|
||||
|
||||
// Creating a secret means you have read & write permission.
|
||||
return new SecretResponseModel(result, true, true);
|
||||
@ -162,14 +183,28 @@ public class SecretsController : Controller
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var updatedSecret = updateRequest.ToSecret(id, secret.OrganizationId);
|
||||
var updatedSecret = updateRequest.ToSecret(secret);
|
||||
var authorizationResult = await _authorizationService.AuthorizeAsync(User, updatedSecret, SecretOperations.Update);
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var result = await _updateSecretCommand.UpdateAsync(updatedSecret);
|
||||
SecretAccessPoliciesUpdates accessPoliciesUpdates = null;
|
||||
if (updateRequest.AccessPoliciesRequests != null)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User)!.Value;
|
||||
accessPoliciesUpdates = await _secretAccessPoliciesUpdatesQuery.GetAsync(updateRequest.AccessPoliciesRequests.ToSecretAccessPolicies(id, secret.OrganizationId), userId);
|
||||
|
||||
var accessPolicyAuthorizationResult = await _authorizationService.AuthorizeAsync(User, accessPoliciesUpdates, SecretAccessPoliciesOperations.Updates);
|
||||
if (!accessPolicyAuthorizationResult.Succeeded)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var result = await _updateSecretCommand.UpdateAsync(updatedSecret, accessPoliciesUpdates);
|
||||
|
||||
// Updating a secret means you have read & write permission.
|
||||
return new SecretResponseModel(result, true, true);
|
||||
|
@ -25,6 +25,16 @@ public class AccessPolicyRequest
|
||||
Write = Write
|
||||
};
|
||||
|
||||
public UserSecretAccessPolicy ToUserSecretAccessPolicy(Guid secretId, Guid organizationId) =>
|
||||
new()
|
||||
{
|
||||
OrganizationUserId = GranteeId,
|
||||
GrantedSecretId = secretId,
|
||||
GrantedSecret = new Secret { OrganizationId = organizationId, Id = secretId },
|
||||
Read = Read,
|
||||
Write = Write
|
||||
};
|
||||
|
||||
public GroupProjectAccessPolicy ToGroupProjectAccessPolicy(Guid projectId, Guid organizationId) =>
|
||||
new()
|
||||
{
|
||||
@ -35,6 +45,16 @@ public class AccessPolicyRequest
|
||||
Write = Write
|
||||
};
|
||||
|
||||
public GroupSecretAccessPolicy ToGroupSecretAccessPolicy(Guid secretId, Guid organizationId) =>
|
||||
new()
|
||||
{
|
||||
GroupId = GranteeId,
|
||||
GrantedSecretId = secretId,
|
||||
GrantedSecret = new Secret { OrganizationId = organizationId, Id = secretId },
|
||||
Read = Read,
|
||||
Write = Write
|
||||
};
|
||||
|
||||
public ServiceAccountProjectAccessPolicy ToServiceAccountProjectAccessPolicy(Guid projectId, Guid organizationId) =>
|
||||
new()
|
||||
{
|
||||
@ -45,6 +65,16 @@ public class AccessPolicyRequest
|
||||
Write = Write
|
||||
};
|
||||
|
||||
public ServiceAccountSecretAccessPolicy ToServiceAccountSecretAccessPolicy(Guid secretId, Guid organizationId) =>
|
||||
new()
|
||||
{
|
||||
ServiceAccountId = GranteeId,
|
||||
GrantedSecretId = secretId,
|
||||
GrantedSecret = new Secret { OrganizationId = organizationId, Id = secretId },
|
||||
Read = Read,
|
||||
Write = Write
|
||||
};
|
||||
|
||||
public UserServiceAccountAccessPolicy ToUserServiceAccountAccessPolicy(Guid id, Guid organizationId) =>
|
||||
new()
|
||||
{
|
||||
|
@ -0,0 +1,42 @@
|
||||
#nullable enable
|
||||
using Bit.Api.SecretsManager.Utilities;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
namespace Bit.Api.SecretsManager.Models.Request;
|
||||
|
||||
public class SecretAccessPoliciesRequestsModel
|
||||
{
|
||||
public required IEnumerable<AccessPolicyRequest> UserAccessPolicyRequests { get; set; }
|
||||
|
||||
public required IEnumerable<AccessPolicyRequest> GroupAccessPolicyRequests { get; set; }
|
||||
|
||||
public required IEnumerable<AccessPolicyRequest> ServiceAccountAccessPolicyRequests { get; set; }
|
||||
|
||||
public SecretAccessPolicies ToSecretAccessPolicies(Guid secretId, Guid organizationId)
|
||||
{
|
||||
var userAccessPolicies = UserAccessPolicyRequests
|
||||
.Select(x => x.ToUserSecretAccessPolicy(secretId, organizationId)).ToList();
|
||||
var groupAccessPolicies = GroupAccessPolicyRequests
|
||||
.Select(x => x.ToGroupSecretAccessPolicy(secretId, organizationId)).ToList();
|
||||
var serviceAccountAccessPolicies = ServiceAccountAccessPolicyRequests
|
||||
.Select(x => x.ToServiceAccountSecretAccessPolicy(secretId, organizationId)).ToList();
|
||||
|
||||
var policies = new List<BaseAccessPolicy>();
|
||||
policies.AddRange(userAccessPolicies);
|
||||
policies.AddRange(groupAccessPolicies);
|
||||
policies.AddRange(serviceAccountAccessPolicies);
|
||||
|
||||
AccessPolicyHelpers.CheckForDistinctAccessPolicies(policies);
|
||||
AccessPolicyHelpers.CheckAccessPoliciesHaveReadPermission(policies);
|
||||
|
||||
return new SecretAccessPolicies
|
||||
{
|
||||
SecretId = secretId,
|
||||
OrganizationId = organizationId,
|
||||
UserAccessPolicies = userAccessPolicies,
|
||||
GroupAccessPolicies = groupAccessPolicies,
|
||||
ServiceAccountAccessPolicies = serviceAccountAccessPolicies
|
||||
};
|
||||
}
|
||||
}
|
@ -23,6 +23,8 @@ public class SecretCreateRequestModel : IValidatableObject
|
||||
|
||||
public Guid[] ProjectIds { get; set; }
|
||||
|
||||
public SecretAccessPoliciesRequestsModel AccessPoliciesRequests { get; set; }
|
||||
|
||||
public Secret ToSecret(Guid organizationId)
|
||||
{
|
||||
return new Secret()
|
||||
|
@ -23,18 +23,27 @@ public class SecretUpdateRequestModel : IValidatableObject
|
||||
|
||||
public Guid[] ProjectIds { get; set; }
|
||||
|
||||
public Secret ToSecret(Guid id, Guid organizationId)
|
||||
public SecretAccessPoliciesRequestsModel AccessPoliciesRequests { get; set; }
|
||||
|
||||
public Secret ToSecret(Secret secret)
|
||||
{
|
||||
return new Secret()
|
||||
secret.Key = Key;
|
||||
secret.Value = Value;
|
||||
secret.Note = Note;
|
||||
secret.RevisionDate = DateTime.UtcNow;
|
||||
|
||||
if (secret.Projects?.FirstOrDefault()?.Id == ProjectIds?.FirstOrDefault())
|
||||
{
|
||||
Id = id,
|
||||
OrganizationId = organizationId,
|
||||
Key = Key,
|
||||
Value = Value,
|
||||
Note = Note,
|
||||
DeletedDate = null,
|
||||
Projects = ProjectIds != null && ProjectIds.Any() ? ProjectIds.Select(x => new Project() { Id = x }).ToList() : null,
|
||||
};
|
||||
secret.Projects = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
secret.Projects = ProjectIds != null && ProjectIds.Length != 0
|
||||
? ProjectIds.Select(x => new Project() { Id = x }).ToList()
|
||||
: [];
|
||||
}
|
||||
|
||||
return secret;
|
||||
}
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
|
@ -13,12 +13,16 @@ public static class AccessPolicyHelpers
|
||||
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),
|
||||
UserSecretAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.OrganizationUserId, ap.GrantedSecretId),
|
||||
UserServiceAccountAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.OrganizationUserId,
|
||||
ap.GrantedServiceAccountId),
|
||||
GroupProjectAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.GroupId, ap.GrantedProjectId),
|
||||
GroupSecretAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.GroupId, ap.GrantedSecretId),
|
||||
GroupServiceAccountAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.GroupId, ap.GrantedServiceAccountId),
|
||||
ServiceAccountProjectAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.ServiceAccountId,
|
||||
ap.GrantedProjectId),
|
||||
ServiceAccountSecretAccessPolicy ap => new Tuple<Guid?, Guid?>(ap.ServiceAccountId,
|
||||
ap.GrantedSecretId),
|
||||
_ => throw new ArgumentException("Unsupported access policy type provided.", nameof(baseAccessPolicy)),
|
||||
};
|
||||
}).ToList();
|
||||
|
@ -0,0 +1,13 @@
|
||||
using Microsoft.AspNetCore.Authorization.Infrastructure;
|
||||
|
||||
namespace Bit.Core.SecretsManager.AuthorizationRequirements;
|
||||
|
||||
public class SecretAccessPoliciesOperationRequirement : OperationAuthorizationRequirement
|
||||
{
|
||||
}
|
||||
|
||||
public static class SecretAccessPoliciesOperations
|
||||
{
|
||||
public static readonly SecretAccessPoliciesOperationRequirement Updates = new() { Name = nameof(Updates) };
|
||||
public static readonly SecretAccessPoliciesOperationRequirement Create = new() { Name = nameof(Create) };
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
#nullable enable
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
|
||||
|
||||
public interface ICreateSecretCommand
|
||||
{
|
||||
Task<Secret> CreateAsync(Secret secret);
|
||||
Task<Secret> CreateAsync(Secret secret, SecretAccessPoliciesUpdates? accessPoliciesUpdates);
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
#nullable enable
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
|
||||
|
||||
public interface IUpdateSecretCommand
|
||||
{
|
||||
Task<Secret> UpdateAsync(Secret secret);
|
||||
Task<Secret> UpdateAsync(Secret secret, SecretAccessPoliciesUpdates? accessPolicyUpdates);
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
#nullable enable
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Enums.AccessPolicies;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
|
||||
public class UserSecretAccessPolicyUpdate
|
||||
{
|
||||
public AccessPolicyOperation Operation { get; set; }
|
||||
public required UserSecretAccessPolicy AccessPolicy { get; set; }
|
||||
}
|
||||
|
||||
public class GroupSecretAccessPolicyUpdate
|
||||
{
|
||||
public AccessPolicyOperation Operation { get; set; }
|
||||
public required GroupSecretAccessPolicy AccessPolicy { get; set; }
|
||||
}
|
||||
|
||||
public class ServiceAccountSecretAccessPolicyUpdate
|
||||
{
|
||||
public AccessPolicyOperation Operation { get; set; }
|
||||
public required ServiceAccountSecretAccessPolicy AccessPolicy { get; set; }
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
#nullable enable
|
||||
using Bit.Core.SecretsManager.Enums.AccessPolicies;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
|
||||
public class SecretAccessPoliciesUpdates
|
||||
{
|
||||
public SecretAccessPoliciesUpdates(SecretAccessPolicies accessPolicies)
|
||||
{
|
||||
SecretId = accessPolicies.SecretId;
|
||||
OrganizationId = accessPolicies.OrganizationId;
|
||||
UserAccessPolicyUpdates =
|
||||
accessPolicies.UserAccessPolicies.Select(x =>
|
||||
new UserSecretAccessPolicyUpdate { Operation = AccessPolicyOperation.Create, AccessPolicy = x });
|
||||
|
||||
GroupAccessPolicyUpdates =
|
||||
accessPolicies.GroupAccessPolicies.Select(x =>
|
||||
new GroupSecretAccessPolicyUpdate { Operation = AccessPolicyOperation.Create, AccessPolicy = x });
|
||||
|
||||
ServiceAccountAccessPolicyUpdates = accessPolicies.ServiceAccountAccessPolicies.Select(x =>
|
||||
new ServiceAccountSecretAccessPolicyUpdate { Operation = AccessPolicyOperation.Create, AccessPolicy = x });
|
||||
}
|
||||
|
||||
public SecretAccessPoliciesUpdates() { }
|
||||
|
||||
public Guid SecretId { get; set; }
|
||||
public Guid OrganizationId { get; set; }
|
||||
public IEnumerable<UserSecretAccessPolicyUpdate> UserAccessPolicyUpdates { get; set; } = [];
|
||||
public IEnumerable<GroupSecretAccessPolicyUpdate> GroupAccessPolicyUpdates { get; set; } = [];
|
||||
public IEnumerable<ServiceAccountSecretAccessPolicyUpdate> ServiceAccountAccessPolicyUpdates { get; set; } = [];
|
||||
|
||||
public bool HasUpdates() =>
|
||||
UserAccessPolicyUpdates.Any() ||
|
||||
GroupAccessPolicyUpdates.Any() ||
|
||||
ServiceAccountAccessPolicyUpdates.Any();
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
#nullable enable
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Enums.AccessPolicies;
|
||||
using Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
@ -32,4 +34,113 @@ public class SecretAccessPolicies
|
||||
public IEnumerable<UserSecretAccessPolicy> UserAccessPolicies { get; set; } = [];
|
||||
public IEnumerable<GroupSecretAccessPolicy> GroupAccessPolicies { get; set; } = [];
|
||||
public IEnumerable<ServiceAccountSecretAccessPolicy> ServiceAccountAccessPolicies { get; set; } = [];
|
||||
|
||||
public SecretAccessPoliciesUpdates GetPolicyUpdates(SecretAccessPolicies requested) =>
|
||||
new()
|
||||
{
|
||||
SecretId = SecretId,
|
||||
OrganizationId = OrganizationId,
|
||||
UserAccessPolicyUpdates = GetUserPolicyUpdates(requested.UserAccessPolicies.ToList()),
|
||||
GroupAccessPolicyUpdates = GetGroupPolicyUpdates(requested.GroupAccessPolicies.ToList()),
|
||||
ServiceAccountAccessPolicyUpdates =
|
||||
GetServiceAccountPolicyUpdates(requested.ServiceAccountAccessPolicies.ToList())
|
||||
};
|
||||
|
||||
private static List<TPolicyUpdate> GetPolicyUpdates<TPolicy, TPolicyUpdate>(
|
||||
List<TPolicy> currentPolicies,
|
||||
List<TPolicy> requestedPolicies,
|
||||
Func<IEnumerable<TPolicy>, List<Guid>> getIds,
|
||||
Func<IEnumerable<TPolicy>, List<Guid>> getIdsToBeUpdated,
|
||||
Func<IEnumerable<TPolicy>, List<Guid>, AccessPolicyOperation, List<TPolicyUpdate>> createPolicyUpdates)
|
||||
where TPolicy : class
|
||||
where TPolicyUpdate : class
|
||||
{
|
||||
var currentIds = getIds(currentPolicies);
|
||||
var requestedIds = getIds(requestedPolicies);
|
||||
|
||||
var idsToBeDeleted = currentIds.Except(requestedIds).ToList();
|
||||
var idsToBeCreated = requestedIds.Except(currentIds).ToList();
|
||||
var idsToBeUpdated = getIdsToBeUpdated(requestedPolicies);
|
||||
|
||||
var policiesToBeDeleted = createPolicyUpdates(currentPolicies, idsToBeDeleted, AccessPolicyOperation.Delete);
|
||||
var policiesToBeCreated = createPolicyUpdates(requestedPolicies, idsToBeCreated, AccessPolicyOperation.Create);
|
||||
var policiesToBeUpdated = createPolicyUpdates(requestedPolicies, idsToBeUpdated, AccessPolicyOperation.Update);
|
||||
|
||||
return policiesToBeDeleted.Concat(policiesToBeCreated).Concat(policiesToBeUpdated).ToList();
|
||||
}
|
||||
|
||||
private static List<Guid> GetOrganizationUserIds(IEnumerable<UserSecretAccessPolicy> policies) =>
|
||||
policies.Select(ap => ap.OrganizationUserId!.Value).ToList();
|
||||
|
||||
private static List<Guid> GetGroupIds(IEnumerable<GroupSecretAccessPolicy> policies) =>
|
||||
policies.Select(ap => ap.GroupId!.Value).ToList();
|
||||
|
||||
private static List<Guid> GetServiceAccountIds(IEnumerable<ServiceAccountSecretAccessPolicy> policies) =>
|
||||
policies.Select(ap => ap.ServiceAccountId!.Value).ToList();
|
||||
|
||||
private static List<UserSecretAccessPolicyUpdate> CreateUserPolicyUpdates(
|
||||
IEnumerable<UserSecretAccessPolicy> policies, List<Guid> userIds,
|
||||
AccessPolicyOperation operation) =>
|
||||
policies
|
||||
.Where(ap => userIds.Contains(ap.OrganizationUserId!.Value))
|
||||
.Select(ap => new UserSecretAccessPolicyUpdate { Operation = operation, AccessPolicy = ap })
|
||||
.ToList();
|
||||
|
||||
private static List<GroupSecretAccessPolicyUpdate> CreateGroupPolicyUpdates(
|
||||
IEnumerable<GroupSecretAccessPolicy> policies, List<Guid> groupIds,
|
||||
AccessPolicyOperation operation) =>
|
||||
policies
|
||||
.Where(ap => groupIds.Contains(ap.GroupId!.Value))
|
||||
.Select(ap => new GroupSecretAccessPolicyUpdate { Operation = operation, AccessPolicy = ap })
|
||||
.ToList();
|
||||
|
||||
private static List<ServiceAccountSecretAccessPolicyUpdate> CreateServiceAccountPolicyUpdates(
|
||||
IEnumerable<ServiceAccountSecretAccessPolicy> policies, List<Guid> serviceAccountIds,
|
||||
AccessPolicyOperation operation) =>
|
||||
policies
|
||||
.Where(ap => serviceAccountIds.Contains(ap.ServiceAccountId!.Value))
|
||||
.Select(ap => new ServiceAccountSecretAccessPolicyUpdate { Operation = operation, AccessPolicy = ap })
|
||||
.ToList();
|
||||
|
||||
|
||||
private List<UserSecretAccessPolicyUpdate> GetUserPolicyUpdates(List<UserSecretAccessPolicy> requestedPolicies) =>
|
||||
GetPolicyUpdates(UserAccessPolicies.ToList(), requestedPolicies, GetOrganizationUserIds, GetUserIdsToBeUpdated,
|
||||
CreateUserPolicyUpdates);
|
||||
|
||||
private List<GroupSecretAccessPolicyUpdate>
|
||||
GetGroupPolicyUpdates(List<GroupSecretAccessPolicy> requestedPolicies) =>
|
||||
GetPolicyUpdates(GroupAccessPolicies.ToList(), requestedPolicies, GetGroupIds, GetGroupIdsToBeUpdated,
|
||||
CreateGroupPolicyUpdates);
|
||||
|
||||
private List<ServiceAccountSecretAccessPolicyUpdate> GetServiceAccountPolicyUpdates(
|
||||
List<ServiceAccountSecretAccessPolicy> requestedPolicies) =>
|
||||
GetPolicyUpdates(ServiceAccountAccessPolicies.ToList(), requestedPolicies, GetServiceAccountIds,
|
||||
GetServiceAccountIdsToBeUpdated, CreateServiceAccountPolicyUpdates);
|
||||
|
||||
private List<Guid> GetUserIdsToBeUpdated(IEnumerable<UserSecretAccessPolicy> requested) =>
|
||||
UserAccessPolicies
|
||||
.Where(currentAp => requested.Any(requestedAp =>
|
||||
requestedAp.GrantedSecretId == currentAp.GrantedSecretId &&
|
||||
requestedAp.OrganizationUserId == currentAp.OrganizationUserId &&
|
||||
(requestedAp.Write != currentAp.Write || requestedAp.Read != currentAp.Read)))
|
||||
.Select(ap => ap.OrganizationUserId!.Value)
|
||||
.ToList();
|
||||
|
||||
private List<Guid> GetGroupIdsToBeUpdated(IEnumerable<GroupSecretAccessPolicy> requested) =>
|
||||
GroupAccessPolicies
|
||||
.Where(currentAp => requested.Any(requestedAp =>
|
||||
requestedAp.GrantedSecretId == currentAp.GrantedSecretId &&
|
||||
requestedAp.GroupId == currentAp.GroupId &&
|
||||
(requestedAp.Write != currentAp.Write || requestedAp.Read != currentAp.Read)))
|
||||
.Select(ap => ap.GroupId!.Value)
|
||||
.ToList();
|
||||
|
||||
private List<Guid> GetServiceAccountIdsToBeUpdated(IEnumerable<ServiceAccountSecretAccessPolicy> requested) =>
|
||||
ServiceAccountAccessPolicies
|
||||
.Where(currentAp => requested.Any(requestedAp =>
|
||||
requestedAp.GrantedSecretId == currentAp.GrantedSecretId &&
|
||||
requestedAp.ServiceAccountId == currentAp.ServiceAccountId &&
|
||||
(requestedAp.Write != currentAp.Write || requestedAp.Read != currentAp.Read)))
|
||||
.Select(ap => ap.ServiceAccountId!.Value)
|
||||
.ToList();
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
#nullable enable
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
using Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Queries.AccessPolicies.Interfaces;
|
||||
|
||||
public interface ISecretAccessPoliciesUpdatesQuery
|
||||
{
|
||||
Task<SecretAccessPoliciesUpdates> GetAsync(SecretAccessPolicies accessPolicies, Guid userId);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
using Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Repositories;
|
||||
|
||||
@ -13,8 +14,8 @@ public interface ISecretRepository
|
||||
Task<IEnumerable<Secret>> GetManyByOrganizationIdInTrashByIdsAsync(Guid organizationId, IEnumerable<Guid> ids);
|
||||
Task<IEnumerable<Secret>> GetManyByIds(IEnumerable<Guid> ids);
|
||||
Task<Secret> GetByIdAsync(Guid id);
|
||||
Task<Secret> CreateAsync(Secret secret);
|
||||
Task<Secret> UpdateAsync(Secret secret);
|
||||
Task<Secret> CreateAsync(Secret secret, SecretAccessPoliciesUpdates accessPoliciesUpdates = null);
|
||||
Task<Secret> UpdateAsync(Secret secret, SecretAccessPoliciesUpdates accessPoliciesUpdates = null);
|
||||
Task SoftDeleteManyByIdAsync(IEnumerable<Guid> ids);
|
||||
Task HardDeleteManyByIdAsync(IEnumerable<Guid> ids);
|
||||
Task RestoreManyByIdAsync(IEnumerable<Guid> ids);
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
using Bit.Core.SecretsManager.Models.Data.AccessPolicyUpdates;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Repositories.Noop;
|
||||
|
||||
@ -45,12 +46,12 @@ public class NoopSecretRepository : ISecretRepository
|
||||
return Task.FromResult(null as Secret);
|
||||
}
|
||||
|
||||
public Task<Secret> CreateAsync(Secret secret)
|
||||
public Task<Secret> CreateAsync(Secret secret, SecretAccessPoliciesUpdates accessPoliciesUpdates)
|
||||
{
|
||||
return Task.FromResult(null as Secret);
|
||||
}
|
||||
|
||||
public Task<Secret> UpdateAsync(Secret secret)
|
||||
public Task<Secret> UpdateAsync(Secret secret, SecretAccessPoliciesUpdates accessPoliciesUpdates)
|
||||
{
|
||||
return Task.FromResult(null as Secret);
|
||||
}
|
||||
|
Reference in New Issue
Block a user