1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-03 00:52:49 -05:00

[AC-1139] Updated CollectionsController GetManyWithDetails and Get to check for flexible collections flag

This commit is contained in:
Rui Tome
2023-10-19 20:58:01 +01:00
parent 8c1a3a6e2d
commit 1e2908ba5e
4 changed files with 51 additions and 4 deletions

View File

@ -95,7 +95,9 @@ public class CollectionsController : Controller
[HttpGet("details")]
public async Task<ListResponseModel<CollectionAccessDetailsResponseModel>> GetManyWithDetails(Guid orgId)
{
if (!await ViewAtLeastOneCollectionAsync(orgId) && !await _currentContext.ManageUsers(orgId) &&
if (!FlexibleCollectionsIsEnabled &&
!await ViewAtLeastOneCollectionAsync(orgId) &&
!await _currentContext.ManageUsers(orgId) &&
!await _currentContext.ManageGroups(orgId))
{
throw new NotFoundException();
@ -130,7 +132,22 @@ public class CollectionsController : Controller
[HttpGet("")]
public async Task<ListResponseModel<CollectionResponseModel>> Get(Guid orgId)
{
IEnumerable<Collection> orgCollections = await _collectionService.GetOrganizationCollectionsAsync(orgId);
IEnumerable<Collection> orgCollections;
if (FlexibleCollectionsIsEnabled)
{
orgCollections = await _collectionRepository.GetManyByOrganizationIdAsync(orgId);
var readAllAuthorized = (await _authorizationService.AuthorizeAsync(User, orgCollections, CollectionOperations.ReadAll)).Succeeded;
if (!readAllAuthorized)
{
var collections = await _collectionRepository.GetManyByUserIdAsync(_currentContext.UserId.Value);
orgCollections = collections.Where(c => c.OrganizationId == orgId);
}
}
else
{
orgCollections = await _collectionService.GetOrganizationCollectionsAsync(orgId);
}
var responses = orgCollections.Select(c => new CollectionResponseModel(c));
return new ListResponseModel<CollectionResponseModel>(responses);

View File

@ -20,6 +20,8 @@ public class CollectionAuthorizationHandler : BulkAuthorizationHandler<Collectio
private readonly ICollectionRepository _collectionRepository;
private readonly IFeatureService _featureService;
private bool FlexibleCollectionsIsEnabled => _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
public CollectionAuthorizationHandler(ICurrentContext currentContext, ICollectionRepository collectionRepository,
IFeatureService featureService)
{
@ -31,14 +33,14 @@ public class CollectionAuthorizationHandler : BulkAuthorizationHandler<Collectio
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
CollectionOperationRequirement requirement, ICollection<Collection> resources)
{
if (!_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext))
if (!FlexibleCollectionsIsEnabled)
{
// Flexible collections is OFF, should not be using this handler
throw new FeatureUnavailableException("Flexible collections is OFF when it should be ON.");
}
// Establish pattern of authorization handler null checking passed resources
if (resources == null || !resources.Any())
if (resources == null)
{
context.Fail();
return;
@ -72,6 +74,10 @@ public class CollectionAuthorizationHandler : BulkAuthorizationHandler<Collectio
await CanCreateAsync(context, requirement, org);
break;
case not null when requirement.Name == nameof(CollectionOperations.ReadAll):
await CanReadAllAsync(context, requirement, org);
break;
case not null when requirement == CollectionOperations.Delete:
await CanDeleteAsync(context, requirement, resources, org);
break;
@ -79,6 +85,10 @@ public class CollectionAuthorizationHandler : BulkAuthorizationHandler<Collectio
case not null when requirement == CollectionOperations.ModifyAccess:
await CanManageCollectionAccessAsync(context, requirement, resources, org);
break;
default:
context.Fail();
break;
}
}
@ -105,6 +115,23 @@ public class CollectionAuthorizationHandler : BulkAuthorizationHandler<Collectio
context.Fail();
}
private async Task CanReadAllAsync(AuthorizationHandlerContext context, CollectionOperationRequirement requirement,
CurrentContextOrganization org)
{
if (org.Type is OrganizationUserType.Owner or OrganizationUserType.Admin ||
org.Permissions.ManageGroups ||
org.Permissions.ManageUsers ||
org.Permissions.EditAnyCollection ||
org.Permissions.DeleteAnyCollection ||
org.Permissions.AccessImportExport)
{
context.Succeed(requirement);
return;
}
context.Fail();
}
private async Task CanDeleteAsync(AuthorizationHandlerContext context, CollectionOperationRequirement requirement,
ICollection<Collection> resources, CurrentContextOrganization org)
{

View File

@ -7,6 +7,8 @@ public class CollectionOperationRequirement : OperationAuthorizationRequirement
public static class CollectionOperations
{
public static readonly CollectionOperationRequirement Create = new() { Name = nameof(Create) };
public static readonly CollectionOperationRequirement ReadAll = new() { Name = nameof(ReadAll) };
public static readonly CollectionOperationRequirement Update = new() { Name = nameof(Update) };
public static readonly CollectionOperationRequirement Delete = new() { Name = nameof(Delete) };
/// <summary>
/// The operation that represents creating, updating, or removing collection access.

View File

@ -7,5 +7,6 @@ public interface ICollectionService
{
Task SaveAsync(Collection collection, IEnumerable<CollectionAccessSelection> groups = null, IEnumerable<CollectionAccessSelection> users = null);
Task DeleteUserAsync(Collection collection, Guid organizationUserId);
[Obsolete("Pre-Flexible Collections logic.")]
Task<IEnumerable<Collection>> GetOrganizationCollectionsAsync(Guid organizationId);
}