mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
[AC-1139] Created BulkCollectionOperations.ReadWithAccess
This commit is contained in:
@ -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();
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
Reference in New Issue
Block a user