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

[AC-1139] Created BulkCollectionOperations.ReadWithAccess

This commit is contained in:
Rui Tome
2023-11-29 16:29:14 +00:00
parent bad95c50df
commit e7dc0a4b8a
4 changed files with 30 additions and 34 deletions

View File

@ -509,7 +509,7 @@ public class CollectionsController : Controller
{
// New flexible collections logic
var (collection, access) = await _collectionRepository.GetByIdWithAccessAsync(id);
var authorized = (await _authorizationService.AuthorizeAsync(User, collection, BulkCollectionOperations.Read)).Succeeded;
var authorized = (await _authorizationService.AuthorizeAsync(User, collection, BulkCollectionOperations.ReadWithAccess)).Succeeded;
if (!authorized)
{
throw new NotFoundException();

View File

@ -74,16 +74,17 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
break;
case not null when requirement == BulkCollectionOperations.Read:
case not null when requirement == BulkCollectionOperations.ReadAccess:
await CanReadAsync(context, requirement, resources, org);
break;
case not null when requirement == BulkCollectionOperations.ReadAccess:
await CanReadAccessAsync(context, requirement, resources, org);
case not null when requirement == BulkCollectionOperations.ReadWithAccess:
await CanReadWithAccessAsync(context, requirement, resources, org);
break;
case not null when requirement == BulkCollectionOperations.Update:
case not null when requirement == BulkCollectionOperations.ModifyAccess:
await CanManageCollectionAccessAsync(context, requirement, resources, org);
await CanUpdateCollection(context, requirement, resources, org);
break;
case not null when requirement == BulkCollectionOperations.Delete:
@ -122,8 +123,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
{ Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
{ Permissions.EditAnyCollection: true } or
{ Permissions.DeleteAnyCollection: true } or
{ Permissions.CreateNewCollections: true } or
{ Permissions.ManageUsers: true })
{ Permissions.CreateNewCollections: true })
{
context.Succeed(requirement);
return;
@ -133,7 +133,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
// ensure they have access for the collection being read
if (org is not null)
{
var canManageCollections = await HasCollectionAccessAsync(resources, org, requireManagePermission: false);
var canManageCollections = await CanManageCollectionsAsync(resources, org);
if (canManageCollections)
{
context.Succeed(requirement);
@ -148,7 +148,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
}
}
private async Task CanReadAccessAsync(AuthorizationHandlerContext context, IAuthorizationRequirement requirement,
private async Task CanReadWithAccessAsync(AuthorizationHandlerContext context, IAuthorizationRequirement requirement,
ICollection<Collection> resources, CurrentContextOrganization? org)
{
// Owners, Admins, and users with EditAnyCollection or DeleteAnyCollection permission can always read a collection
@ -157,7 +157,8 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
{ Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
{ Permissions.EditAnyCollection: true } or
{ Permissions.DeleteAnyCollection: true } or
{ Permissions.CreateNewCollections: true })
{ Permissions.CreateNewCollections: true } or
{ Permissions.ManageUsers: true })
{
context.Succeed(requirement);
return;
@ -167,7 +168,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
// ensure they have access for the collection being read
if (org is not null)
{
var canManageCollections = await HasCollectionAccessAsync(resources, org, requireManagePermission: false);
var canManageCollections = await CanManageCollectionsAsync(resources, org);
if (canManageCollections)
{
context.Succeed(requirement);
@ -183,9 +184,9 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
}
/// <summary>
/// Ensures the acting user is allowed to manage access permissions for the target collections.
/// Ensures the acting user is allowed to update the target collections or manage access permissions for them.
/// </summary>
private async Task CanManageCollectionAccessAsync(AuthorizationHandlerContext context,
private async Task CanUpdateCollection(AuthorizationHandlerContext context,
IAuthorizationRequirement requirement, ICollection<Collection> resources,
CurrentContextOrganization? org)
{
@ -202,7 +203,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
// ensure they have manage permission for the collection being managed
if (org is not null)
{
var canManageCollections = await HasCollectionAccessAsync(resources, org, requireManagePermission: true);
var canManageCollections = await CanManageCollectionsAsync(resources, org);
if (canManageCollections)
{
context.Succeed(requirement);
@ -233,7 +234,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
// ensure acting user has manage permissions for all collections being deleted
if (org is { LimitCollectionCreationDeletion: false })
{
var canManageCollections = await HasCollectionAccessAsync(resources, org, requireManagePermission: true);
var canManageCollections = await CanManageCollectionsAsync(resources, org);
if (canManageCollections)
{
context.Succeed(requirement);
@ -248,18 +249,16 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
}
}
private async Task<bool> HasCollectionAccessAsync(
private async Task<bool> CanManageCollectionsAsync(
ICollection<Collection> targetCollections,
CurrentContextOrganization org,
bool requireManagePermission)
CurrentContextOrganization org)
{
// List of collection Ids the acting user has access to
var manageableCollectionIds =
(await _collectionRepository.GetManyByUserIdAsync(_currentContext.UserId!.Value))
.Where(c =>
// If requireManagePermission is true, check Collections with Manage permission
(!requireManagePermission || c.Manage)
&& c.OrganizationId == org.Id)
// Check Collections with Manage permission
c.Manage && c.OrganizationId == org.Id)
.Select(c => c.Id)
.ToHashSet();

View File

@ -9,6 +9,7 @@ public static class BulkCollectionOperations
public static readonly BulkCollectionOperationRequirement Create = new() { Name = nameof(Create) };
public static readonly BulkCollectionOperationRequirement Read = new() { Name = nameof(Read) };
public static readonly BulkCollectionOperationRequirement ReadAccess = new() { Name = nameof(ReadAccess) };
public static readonly BulkCollectionOperationRequirement ReadWithAccess = new() { Name = nameof(ReadWithAccess) };
public static readonly BulkCollectionOperationRequirement Update = new() { Name = nameof(Update) };
/// <summary>
/// The operation that represents creating, updating, or removing collection access.

View File

@ -158,14 +158,13 @@ public class BulkCollectionAuthorizationHandlerTests
}
[Theory, CollectionCustomization]
[BitAutoData(true, false, false, false, true)]
[BitAutoData(false, true, false, false, true)]
[BitAutoData(false, false, true, false, true)]
[BitAutoData(false, false, false, true, true)]
[BitAutoData(false, false, false, false, false)]
[BitAutoData(true, false, false, true)]
[BitAutoData(false, true, false, true)]
[BitAutoData(false, false, true, true)]
[BitAutoData(false, false, false, false)]
public async Task CanReadAsync_WhenCustomUserWithRequiredPermissions_Success(
bool manageUsers, bool editAnyCollection, bool deleteAnyCollection,
bool editAnyCollection, bool deleteAnyCollection,
bool createNewCollections, bool limitCollectionCreationDeletion,
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
ICollection<Collection> collections,
@ -177,7 +176,6 @@ public class BulkCollectionAuthorizationHandlerTests
organization.LimitCollectionCreationDeletion = limitCollectionCreationDeletion;
organization.Permissions = new Permissions
{
ManageUsers = manageUsers,
EditAnyCollection = editAnyCollection,
DeleteAnyCollection = deleteAnyCollection,
CreateNewCollections = createNewCollections
@ -421,12 +419,10 @@ public class BulkCollectionAuthorizationHandlerTests
Assert.False(context.HasSucceeded);
}
//
[Theory, CollectionCustomization]
[BitAutoData(OrganizationUserType.Admin)]
[BitAutoData(OrganizationUserType.Owner)]
public async Task CanManageCollectionAccessAsync_WhenAdminOrOwner_Success(
public async Task CanUpdateCollection_WhenAdminOrOwner_Success(
OrganizationUserType userType,
Guid userId, SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
ICollection<Collection> collections,
@ -461,7 +457,7 @@ public class BulkCollectionAuthorizationHandlerTests
}
[Theory, BitAutoData, CollectionCustomization]
public async Task CanManageCollectionAccessAsync_WithEditAnyCollectionPermission_Success(
public async Task CanUpdateCollection_WithEditAnyCollectionPermission_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
ICollection<Collection> collections,
CurrentContextOrganization organization)
@ -499,7 +495,7 @@ public class BulkCollectionAuthorizationHandlerTests
}
[Theory, BitAutoData, CollectionCustomization]
public async Task CanManageCollectionAccessAsync_WithManageCollectionPermission_Success(
public async Task CanUpdateCollection_WithManageCollectionPermission_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
ICollection<CollectionDetails> collections,
CurrentContextOrganization organization)
@ -542,7 +538,7 @@ public class BulkCollectionAuthorizationHandlerTests
[Theory, CollectionCustomization]
[BitAutoData(OrganizationUserType.User)]
[BitAutoData(OrganizationUserType.Custom)]
public async Task CanManageCollectionAccessAsync_WhenMissingPermissions_NoSuccess(
public async Task CanUpdateCollection_WhenMissingPermissions_NoSuccess(
OrganizationUserType userType,
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
ICollection<CollectionDetails> collections,
@ -592,7 +588,7 @@ public class BulkCollectionAuthorizationHandlerTests
}
[Theory, BitAutoData, CollectionCustomization]
public async Task CanManageCollectionAccessAsync_WhenMissingOrgAccess_NoSuccess(
public async Task CanUpdateCollection_WhenMissingOrgAccess_NoSuccess(
Guid userId,
ICollection<Collection> collections,
SutProvider<BulkCollectionAuthorizationHandler> sutProvider)