mirror of
https://github.com/bitwarden/server.git
synced 2024-11-21 12:05:42 +01: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:
parent
a1d609b208
commit
36705790ad
@ -47,6 +47,9 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
|
||||
case not null when requirement == SecretOperations.Delete:
|
||||
await CanDeleteSecretAsync(context, requirement, resource);
|
||||
break;
|
||||
case not null when requirement == SecretOperations.ReadAccessPolicies:
|
||||
await CanReadAccessPoliciesAsync(context, requirement, resource);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException("Unsupported operation requirement type provided.", nameof(requirement));
|
||||
}
|
||||
@ -152,6 +155,26 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CanReadAccessPoliciesAsync(AuthorizationHandlerContext context,
|
||||
SecretOperationRequirement requirement, Secret resource)
|
||||
{
|
||||
var (accessClient, userId) = await _accessClientQuery.GetAccessClientAsync(context.User, resource.OrganizationId);
|
||||
|
||||
// Only users and admins can read access policies
|
||||
if (accessClient != AccessClientType.User && accessClient != AccessClientType.NoAccessCheck)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var access = await _secretRepository.AccessToSecretAsync(resource.Id, userId, accessClient);
|
||||
|
||||
if (access.Write)
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task<bool> GetAccessToUpdateSecretAsync(Secret resource, Guid userId, AccessClientType accessClient)
|
||||
{
|
||||
var newProject = resource.Projects?.FirstOrDefault();
|
||||
|
@ -20,7 +20,8 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<List<Core.SecretsManager.Entities.BaseAccessPolicy>> CreateManyAsync(List<Core.SecretsManager.Entities.BaseAccessPolicy> baseAccessPolicies)
|
||||
public async Task<List<Core.SecretsManager.Entities.BaseAccessPolicy>> CreateManyAsync(
|
||||
List<Core.SecretsManager.Entities.BaseAccessPolicy> baseAccessPolicies)
|
||||
{
|
||||
await using var scope = ServiceScopeFactory.CreateAsyncScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
@ -39,6 +40,13 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.UserSecretAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity =
|
||||
Mapper.Map<UserSecretAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.UserServiceAccountAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity =
|
||||
@ -52,6 +60,12 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.GroupSecretAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity = Mapper.Map<GroupSecretAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.GroupServiceAccountAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity = Mapper.Map<GroupServiceAccountAccessPolicy>(accessPolicy);
|
||||
@ -65,6 +79,13 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
serviceAccountIds.Add(entity.ServiceAccountId!.Value);
|
||||
break;
|
||||
}
|
||||
case Core.SecretsManager.Entities.ServiceAccountSecretAccessPolicy accessPolicy:
|
||||
{
|
||||
var entity = Mapper.Map<ServiceAccountSecretAccessPolicy>(accessPolicy);
|
||||
await dbContext.AddAsync(entity);
|
||||
serviceAccountIds.Add(entity.ServiceAccountId!.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -395,6 +416,42 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
|
||||
public async Task<SecretAccessPolicies?> GetSecretAccessPoliciesAsync(
|
||||
Guid secretId,
|
||||
Guid userId)
|
||||
{
|
||||
await using var scope = ServiceScopeFactory.CreateAsyncScope();
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
|
||||
var entities = await dbContext.AccessPolicies.Where(ap =>
|
||||
((UserSecretAccessPolicy)ap).GrantedSecretId == secretId ||
|
||||
((GroupSecretAccessPolicy)ap).GrantedSecretId == secretId ||
|
||||
((ServiceAccountSecretAccessPolicy)ap).GrantedSecretId == secretId)
|
||||
.Include(ap => ((UserSecretAccessPolicy)ap).OrganizationUser.User)
|
||||
.Include(ap => ((GroupSecretAccessPolicy)ap).Group)
|
||||
.Include(ap => ((ServiceAccountSecretAccessPolicy)ap).ServiceAccount)
|
||||
.Select(ap => new
|
||||
{
|
||||
ap,
|
||||
CurrentUserInGroup = ap is GroupSecretAccessPolicy &&
|
||||
((GroupSecretAccessPolicy)ap).Group.GroupUsers.Any(g =>
|
||||
g.OrganizationUser.UserId == userId)
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
if (entities.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var organizationId = await dbContext.Secret.Where(s => s.Id == secretId)
|
||||
.Select(s => s.OrganizationId)
|
||||
.SingleAsync();
|
||||
|
||||
return new SecretAccessPolicies(secretId, organizationId,
|
||||
entities.Select(e => MapToCore(e.ap, e.CurrentUserInGroup)).ToList());
|
||||
}
|
||||
|
||||
private static async Task UpsertPeoplePoliciesAsync(DatabaseContext dbContext,
|
||||
List<BaseAccessPolicy> policies, IReadOnlyCollection<AccessPolicy> userPolicyEntities,
|
||||
IReadOnlyCollection<AccessPolicy> groupPolicyEntities)
|
||||
@ -466,13 +523,17 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
baseAccessPolicyEntity switch
|
||||
{
|
||||
UserProjectAccessPolicy ap => Mapper.Map<Core.SecretsManager.Entities.UserProjectAccessPolicy>(ap),
|
||||
GroupProjectAccessPolicy ap => Mapper.Map<Core.SecretsManager.Entities.GroupProjectAccessPolicy>(ap),
|
||||
ServiceAccountProjectAccessPolicy ap => Mapper
|
||||
.Map<Core.SecretsManager.Entities.ServiceAccountProjectAccessPolicy>(ap),
|
||||
UserSecretAccessPolicy ap => Mapper.Map<Core.SecretsManager.Entities.UserSecretAccessPolicy>(ap),
|
||||
UserServiceAccountAccessPolicy ap =>
|
||||
Mapper.Map<Core.SecretsManager.Entities.UserServiceAccountAccessPolicy>(ap),
|
||||
GroupProjectAccessPolicy ap => Mapper.Map<Core.SecretsManager.Entities.GroupProjectAccessPolicy>(ap),
|
||||
GroupSecretAccessPolicy ap => Mapper.Map<Core.SecretsManager.Entities.GroupSecretAccessPolicy>(ap),
|
||||
GroupServiceAccountAccessPolicy ap => Mapper
|
||||
.Map<Core.SecretsManager.Entities.GroupServiceAccountAccessPolicy>(ap),
|
||||
ServiceAccountProjectAccessPolicy ap => Mapper
|
||||
.Map<Core.SecretsManager.Entities.ServiceAccountProjectAccessPolicy>(ap),
|
||||
ServiceAccountSecretAccessPolicy ap => Mapper
|
||||
.Map<Core.SecretsManager.Entities.ServiceAccountSecretAccessPolicy>(ap),
|
||||
_ => throw new ArgumentException("Unsupported access policy type")
|
||||
};
|
||||
|
||||
@ -482,20 +543,26 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
{
|
||||
Core.SecretsManager.Entities.UserProjectAccessPolicy accessPolicy => Mapper.Map<UserProjectAccessPolicy>(
|
||||
accessPolicy),
|
||||
Core.SecretsManager.Entities.UserSecretAccessPolicy accessPolicy => Mapper.Map<UserSecretAccessPolicy>(
|
||||
accessPolicy),
|
||||
Core.SecretsManager.Entities.UserServiceAccountAccessPolicy accessPolicy => Mapper
|
||||
.Map<UserServiceAccountAccessPolicy>(accessPolicy),
|
||||
Core.SecretsManager.Entities.GroupProjectAccessPolicy accessPolicy => Mapper.Map<GroupProjectAccessPolicy>(
|
||||
accessPolicy),
|
||||
Core.SecretsManager.Entities.GroupSecretAccessPolicy accessPolicy => Mapper.Map<GroupSecretAccessPolicy>(
|
||||
accessPolicy),
|
||||
Core.SecretsManager.Entities.GroupServiceAccountAccessPolicy accessPolicy => Mapper
|
||||
.Map<GroupServiceAccountAccessPolicy>(accessPolicy),
|
||||
Core.SecretsManager.Entities.ServiceAccountProjectAccessPolicy accessPolicy => Mapper
|
||||
.Map<ServiceAccountProjectAccessPolicy>(accessPolicy),
|
||||
Core.SecretsManager.Entities.ServiceAccountSecretAccessPolicy accessPolicy => Mapper
|
||||
.Map<ServiceAccountSecretAccessPolicy>(accessPolicy),
|
||||
_ => throw new ArgumentException("Unsupported access policy type")
|
||||
};
|
||||
}
|
||||
|
||||
private Core.SecretsManager.Entities.BaseAccessPolicy MapToCore(
|
||||
BaseAccessPolicy baseAccessPolicyEntity, bool currentUserInGroup)
|
||||
BaseAccessPolicy baseAccessPolicyEntity, bool currentUserInGroup)
|
||||
{
|
||||
switch (baseAccessPolicyEntity)
|
||||
{
|
||||
@ -505,6 +572,12 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli
|
||||
mapped.CurrentUserInGroup = currentUserInGroup;
|
||||
return mapped;
|
||||
}
|
||||
case GroupSecretAccessPolicy ap:
|
||||
{
|
||||
var mapped = Mapper.Map<Core.SecretsManager.Entities.GroupSecretAccessPolicy>(ap);
|
||||
mapped.CurrentUserInGroup = currentUserInGroup;
|
||||
return mapped;
|
||||
}
|
||||
case GroupServiceAccountAccessPolicy ap:
|
||||
{
|
||||
var mapped = Mapper.Map<Core.SecretsManager.Entities.GroupServiceAccountAccessPolicy>(ap);
|
||||
|
@ -517,4 +517,85 @@ public class SecretAuthorizationHandlerTests
|
||||
|
||||
Assert.Equal(expected, authzContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CanReadAccessPolicies_AccessToSecretsManagerFalse_DoesNotSucceed(
|
||||
SutProvider<SecretAuthorizationHandler> sutProvider, Secret secret,
|
||||
ClaimsPrincipal claimsPrincipal)
|
||||
{
|
||||
var requirement = SecretOperations.ReadAccessPolicies;
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId)
|
||||
.Returns(false);
|
||||
var authzContext = new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement },
|
||||
claimsPrincipal, secret);
|
||||
|
||||
await sutProvider.Sut.HandleAsync(authzContext);
|
||||
|
||||
Assert.False(authzContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task CanReadAccessPolicies_NullResource_DoesNotSucceed(
|
||||
SutProvider<SecretAuthorizationHandler> sutProvider, Secret secret,
|
||||
ClaimsPrincipal claimsPrincipal,
|
||||
Guid userId)
|
||||
{
|
||||
var requirement = SecretOperations.ReadAccessPolicies;
|
||||
SetupPermission(sutProvider, PermissionType.RunAsAdmin, secret.OrganizationId, userId);
|
||||
var authzContext = new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement },
|
||||
claimsPrincipal, null);
|
||||
|
||||
await sutProvider.Sut.HandleAsync(authzContext);
|
||||
|
||||
Assert.False(authzContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(AccessClientType.ServiceAccount)]
|
||||
[BitAutoData(AccessClientType.Organization)]
|
||||
public async Task CanReadAccessPolicies_UnsupportedClient_DoesNotSucceed(
|
||||
AccessClientType clientType,
|
||||
SutProvider<SecretAuthorizationHandler> sutProvider, Secret secret,
|
||||
ClaimsPrincipal claimsPrincipal)
|
||||
{
|
||||
var requirement = SecretOperations.ReadAccessPolicies;
|
||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(secret.OrganizationId)
|
||||
.Returns(true);
|
||||
sutProvider.GetDependency<IAccessClientQuery>()
|
||||
.GetAccessClientAsync(Arg.Any<ClaimsPrincipal>(), secret.OrganizationId)
|
||||
.Returns((clientType, Guid.NewGuid()));
|
||||
var authzContext = new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement },
|
||||
claimsPrincipal, secret);
|
||||
|
||||
await sutProvider.Sut.HandleAsync(authzContext);
|
||||
|
||||
Assert.False(authzContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PermissionType.RunAsAdmin, true, true, true)]
|
||||
[BitAutoData(PermissionType.RunAsUserWithPermission, false, false, false)]
|
||||
[BitAutoData(PermissionType.RunAsUserWithPermission, false, true, true)]
|
||||
[BitAutoData(PermissionType.RunAsUserWithPermission, true, false, false)]
|
||||
[BitAutoData(PermissionType.RunAsUserWithPermission, true, true, true)]
|
||||
public async Task CanReadAccessPolicies_AccessCheck(PermissionType permissionType, bool read, bool write,
|
||||
bool expected,
|
||||
SutProvider<SecretAuthorizationHandler> sutProvider, Secret secret,
|
||||
ClaimsPrincipal claimsPrincipal,
|
||||
Guid userId)
|
||||
{
|
||||
var requirement = SecretOperations.ReadAccessPolicies;
|
||||
SetupPermission(sutProvider, permissionType, secret.OrganizationId, userId);
|
||||
sutProvider.GetDependency<ISecretRepository>()
|
||||
.AccessToSecretAsync(secret.Id, userId, Arg.Any<AccessClientType>())
|
||||
.Returns((read, write));
|
||||
var authzContext = new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement },
|
||||
claimsPrincipal, secret);
|
||||
|
||||
await sutProvider.Sut.HandleAsync(authzContext);
|
||||
|
||||
Assert.Equal(expected, authzContext.HasSucceeded);
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -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; }
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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; } = [];
|
||||
}
|
||||
|
@ -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; } = [];
|
||||
|
||||
}
|
@ -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; } =
|
||||
[];
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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; }
|
||||
}
|
@ -12,4 +12,5 @@ public static class SecretOperations
|
||||
public static readonly SecretOperationRequirement Read = new() { Name = nameof(Read) };
|
||||
public static readonly SecretOperationRequirement Update = new() { Name = nameof(Update) };
|
||||
public static readonly SecretOperationRequirement Delete = new() { Name = nameof(Delete) };
|
||||
public static readonly SecretOperationRequirement ReadAccessPolicies = new() { Name = nameof(ReadAccessPolicies) };
|
||||
}
|
||||
|
35
src/Core/SecretsManager/Models/Data/SecretAccessPolicies.cs
Normal file
35
src/Core/SecretsManager/Models/Data/SecretAccessPolicies.cs
Normal file
@ -0,0 +1,35 @@
|
||||
#nullable enable
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
public class SecretAccessPolicies
|
||||
{
|
||||
public SecretAccessPolicies(Guid secretId, Guid organizationId, List<BaseAccessPolicy> policies)
|
||||
{
|
||||
SecretId = secretId;
|
||||
OrganizationId = organizationId;
|
||||
|
||||
UserAccessPolicies = policies
|
||||
.OfType<UserSecretAccessPolicy>()
|
||||
.ToList();
|
||||
|
||||
GroupAccessPolicies = policies
|
||||
.OfType<GroupSecretAccessPolicy>()
|
||||
.ToList();
|
||||
|
||||
ServiceAccountAccessPolicies = policies
|
||||
.OfType<ServiceAccountSecretAccessPolicy>()
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public SecretAccessPolicies()
|
||||
{
|
||||
}
|
||||
|
||||
public Guid SecretId { get; set; }
|
||||
public Guid OrganizationId { get; set; }
|
||||
public IEnumerable<UserSecretAccessPolicy> UserAccessPolicies { get; set; } = [];
|
||||
public IEnumerable<GroupSecretAccessPolicy> GroupAccessPolicies { get; set; } = [];
|
||||
public IEnumerable<ServiceAccountSecretAccessPolicy> ServiceAccountAccessPolicies { get; set; } = [];
|
||||
}
|
@ -20,4 +20,5 @@ public interface IAccessPolicyRepository
|
||||
Task UpdateServiceAccountGrantedPoliciesAsync(ServiceAccountGrantedPoliciesUpdates policyUpdates);
|
||||
Task<ProjectServiceAccountsAccessPolicies?> GetProjectServiceAccountsAccessPoliciesAsync(Guid projectId);
|
||||
Task UpdateProjectServiceAccountsAccessPoliciesAsync(ProjectServiceAccountsAccessPoliciesUpdates updates);
|
||||
Task<SecretAccessPolicies?> GetSecretAccessPoliciesAsync(Guid secretId, Guid userId);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ public class AccessPoliciesControllerTests : IClassFixture<ApiApplicationFactory
|
||||
private readonly IGroupRepository _groupRepository;
|
||||
private readonly LoginHelper _loginHelper;
|
||||
private readonly IProjectRepository _projectRepository;
|
||||
private readonly ISecretRepository _secretRepository;
|
||||
private readonly IServiceAccountRepository _serviceAccountRepository;
|
||||
private string _email = null!;
|
||||
private SecretsManagerOrganizationHelper _organizationHelper = null!;
|
||||
@ -37,6 +38,7 @@ public class AccessPoliciesControllerTests : IClassFixture<ApiApplicationFactory
|
||||
_client = _factory.CreateClient();
|
||||
_accessPolicyRepository = _factory.GetService<IAccessPolicyRepository>();
|
||||
_serviceAccountRepository = _factory.GetService<IServiceAccountRepository>();
|
||||
_secretRepository = _factory.GetService<ISecretRepository>();
|
||||
_projectRepository = _factory.GetService<IProjectRepository>();
|
||||
_groupRepository = _factory.GetService<IGroupRepository>();
|
||||
_loginHelper = new LoginHelper(_factory, _client);
|
||||
@ -723,9 +725,8 @@ public class AccessPoliciesControllerTests : IClassFixture<ApiApplicationFactory
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.GrantedProjectPolicies);
|
||||
Assert.Equal(initData.ServiceAccountId, result.GrantedProjectPolicies.First().AccessPolicy.ServiceAccountId);
|
||||
Assert.NotNull(result.GrantedProjectPolicies.First().AccessPolicy.ServiceAccountName);
|
||||
Assert.NotNull(result.GrantedProjectPolicies.First().AccessPolicy.GrantedProjectName);
|
||||
Assert.NotNull(result.GrantedProjectPolicies.First().AccessPolicy.GrantedProjectId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -922,7 +923,6 @@ public class AccessPoliciesControllerTests : IClassFixture<ApiApplicationFactory
|
||||
Assert.NotEmpty(result.ServiceAccountAccessPolicies);
|
||||
Assert.Equal(initData.ServiceAccountId, result.ServiceAccountAccessPolicies.First().ServiceAccountId);
|
||||
Assert.NotNull(result.ServiceAccountAccessPolicies.First().ServiceAccountName);
|
||||
Assert.NotNull(result.ServiceAccountAccessPolicies.First().GrantedProjectName);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -1038,6 +1038,89 @@ public class AccessPoliciesControllerTests : IClassFixture<ApiApplicationFactory
|
||||
Assert.Single(result.ServiceAccountAccessPolicies);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, false, false)]
|
||||
[InlineData(false, false, true)]
|
||||
[InlineData(false, true, false)]
|
||||
[InlineData(false, true, true)]
|
||||
[InlineData(true, false, false)]
|
||||
[InlineData(true, false, true)]
|
||||
[InlineData(true, true, false)]
|
||||
public async Task GetSecretAccessPoliciesAsync_SmAccessDenied_ReturnsNotFound(bool useSecrets,
|
||||
bool accessSecrets, bool organizationEnabled)
|
||||
{
|
||||
var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled);
|
||||
await _loginHelper.LoginAsync(_email);
|
||||
var secret = await _secretRepository.CreateAsync(new Secret
|
||||
{
|
||||
OrganizationId = org.Id,
|
||||
Key = _mockEncryptedString,
|
||||
Value = _mockEncryptedString,
|
||||
Note = _mockEncryptedString
|
||||
});
|
||||
|
||||
var response = await _client.GetAsync($"/secrets/{secret.Id}/access-policies");
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSecretAccessPoliciesAsync_NoAccessPolicies_ReturnsEmpty()
|
||||
{
|
||||
var (secretId, _) = await SetupSecretAccessPoliciesTest(PermissionType.RunAsAdmin);
|
||||
|
||||
var response = await _client.GetAsync($"/secrets/{secretId}/access-policies");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content
|
||||
.ReadFromJsonAsync<SecretAccessPoliciesResponseModel>();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Empty(result.UserAccessPolicies);
|
||||
Assert.Empty(result.GroupAccessPolicies);
|
||||
Assert.Empty(result.ServiceAccountAccessPolicies);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSecretAccessPoliciesAsync_UserDoesntHavePermission_ReturnsNotFound()
|
||||
{
|
||||
var (secretId, _) = await SetupSecretAccessPoliciesTest(PermissionType.RunAsUserWithPermission);
|
||||
|
||||
var response = await _client.GetAsync($"/secrets/{secretId}/access-policies");
|
||||
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(PermissionType.RunAsAdmin)]
|
||||
public async Task GetSecretAccessPoliciesAsync_Success(PermissionType permissionType)
|
||||
{
|
||||
var (secretId, currentOrgUser) = await SetupSecretAccessPoliciesTest(permissionType);
|
||||
|
||||
var accessPolicies = new List<BaseAccessPolicy>
|
||||
{
|
||||
new UserSecretAccessPolicy
|
||||
{
|
||||
GrantedSecretId = secretId, OrganizationUserId = currentOrgUser.Id, Read = true, Write = true
|
||||
}
|
||||
};
|
||||
await _accessPolicyRepository.CreateManyAsync(accessPolicies);
|
||||
|
||||
var response = await _client.GetAsync($"/secrets/{secretId}/access-policies");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var result = await response.Content
|
||||
.ReadFromJsonAsync<SecretAccessPoliciesResponseModel>();
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.UserAccessPolicies);
|
||||
Assert.Empty(result.GroupAccessPolicies);
|
||||
Assert.Empty(result.ServiceAccountAccessPolicies);
|
||||
Assert.NotNull(result.UserAccessPolicies.First().OrganizationUserName);
|
||||
Assert.NotNull(result.UserAccessPolicies.First().OrganizationUserId);
|
||||
Assert.NotNull(result.UserAccessPolicies.First().CurrentUser);
|
||||
Assert.Equal(currentOrgUser.Id, result.UserAccessPolicies.First().OrganizationUserId);
|
||||
}
|
||||
|
||||
private async Task<(Guid ProjectId, Guid ServiceAccountId)> CreateServiceAccountProjectAccessPolicyAsync(
|
||||
Guid organizationId)
|
||||
{
|
||||
@ -1290,4 +1373,31 @@ public class AccessPoliciesControllerTests : IClassFixture<ApiApplicationFactory
|
||||
|
||||
return (project, request);
|
||||
}
|
||||
|
||||
private async Task<(Guid SecretId, OrganizationUser currentOrgUser)> SetupSecretAccessPoliciesTest(
|
||||
PermissionType permissionType)
|
||||
{
|
||||
var (org, orgAdmin) = await _organizationHelper.Initialize(true, true, true);
|
||||
var currentOrgUser = orgAdmin;
|
||||
if (permissionType == PermissionType.RunAsUserWithPermission)
|
||||
{
|
||||
var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true);
|
||||
await _loginHelper.LoginAsync(email);
|
||||
currentOrgUser = orgUser;
|
||||
}
|
||||
else
|
||||
{
|
||||
await _loginHelper.LoginAsync(_email);
|
||||
}
|
||||
|
||||
var secret = await _secretRepository.CreateAsync(new Secret
|
||||
{
|
||||
OrganizationId = org.Id,
|
||||
Key = _mockEncryptedString,
|
||||
Value = _mockEncryptedString,
|
||||
Note = _mockEncryptedString
|
||||
});
|
||||
|
||||
return (secret.Id, currentOrgUser);
|
||||
}
|
||||
}
|
||||
|
@ -827,7 +827,6 @@ public class AccessPoliciesControllerTests
|
||||
SutProvider<AccessPoliciesController> sutProvider,
|
||||
Project data)
|
||||
{
|
||||
// FIX ME
|
||||
SetupProjectAccessPoliciesTest(sutProvider, data, accessClientType);
|
||||
|
||||
sutProvider.GetDependency<IAccessPolicyRepository>()
|
||||
@ -953,6 +952,61 @@ public class AccessPoliciesControllerTests
|
||||
.UpdateAsync(Arg.Any<ProjectServiceAccountsAccessPoliciesUpdates>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetSecretAccessPoliciesAsync_NoAccess_ThrowsNotFound(
|
||||
SutProvider<AccessPoliciesController> sutProvider,
|
||||
Secret data)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(data.Id).Returns(data);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), data,
|
||||
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Failed());
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetSecretAccessPoliciesAsync(data.Id));
|
||||
|
||||
await sutProvider.GetDependency<IAccessPolicyRepository>().Received(0)
|
||||
.GetSecretAccessPoliciesAsync(Arg.Any<Guid>(), Arg.Any<Guid>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetSecretAccessPoliciesAsync_HasAccessNoPolicies_ReturnsEmptyList(
|
||||
SutProvider<AccessPoliciesController> sutProvider,
|
||||
Secret data)
|
||||
{
|
||||
SetupSecretAccessPoliciesTest(sutProvider, data);
|
||||
sutProvider.GetDependency<IAccessPolicyRepository>()
|
||||
.GetSecretAccessPoliciesAsync(Arg.Any<Guid>(), Arg.Any<Guid>())
|
||||
.ReturnsNull();
|
||||
|
||||
var result = await sutProvider.Sut.GetSecretAccessPoliciesAsync(data.Id);
|
||||
|
||||
Assert.Empty(result.UserAccessPolicies);
|
||||
Assert.Empty(result.GroupAccessPolicies);
|
||||
Assert.Empty(result.ServiceAccountAccessPolicies);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetSecretAccessPoliciesAsync_HasAccess_Success(
|
||||
SutProvider<AccessPoliciesController> sutProvider,
|
||||
SecretAccessPolicies policies,
|
||||
Secret data)
|
||||
{
|
||||
SetupSecretAccessPoliciesTest(sutProvider, data);
|
||||
sutProvider.GetDependency<IAccessPolicyRepository>()
|
||||
.GetSecretAccessPoliciesAsync(Arg.Any<Guid>(), Arg.Any<Guid>())
|
||||
.Returns(policies);
|
||||
|
||||
var result = await sutProvider.Sut.GetSecretAccessPoliciesAsync(data.Id);
|
||||
|
||||
Assert.NotEmpty(result.UserAccessPolicies);
|
||||
Assert.NotEmpty(result.GroupAccessPolicies);
|
||||
Assert.NotEmpty(result.ServiceAccountAccessPolicies);
|
||||
}
|
||||
|
||||
private static PeopleAccessPoliciesRequestModel SetRequestToCanReadWrite(PeopleAccessPoliciesRequestModel request)
|
||||
{
|
||||
foreach (var ap in request.UserAccessPolicyRequests)
|
||||
@ -1005,4 +1059,13 @@ public class AccessPoliciesControllerTests
|
||||
.GetAccessClientAsync(Arg.Any<ClaimsPrincipal>(), Arg.Any<Guid>())
|
||||
.ReturnsForAnyArgs((accessClientType, Guid.NewGuid()));
|
||||
}
|
||||
|
||||
private static void SetupSecretAccessPoliciesTest(SutProvider<AccessPoliciesController> sutProvider, Secret data)
|
||||
{
|
||||
sutProvider.GetDependency<ISecretRepository>().GetByIdAsync(data.Id).Returns(data);
|
||||
sutProvider.GetDependency<IAuthorizationService>()
|
||||
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), data,
|
||||
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Success());
|
||||
sutProvider.GetDependency<IUserService>().GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(Guid.NewGuid());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user