1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-21 12:05:42 +01:00

[AC-2605] Restrict collection access for some custom users (#4096)

* Make custom users subject to collection settings
  Affects ManageUsers and ManageGroups
This commit is contained in:
Thomas Rittson 2024-05-21 10:44:57 +10:00 committed by GitHub
parent 489f6246b1
commit 98b7866c95
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 151 additions and 46 deletions

View File

@ -217,12 +217,22 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
private async Task<bool> CanUpdateUserAccessAsync(ICollection<Collection> resources, CurrentContextOrganization? org) private async Task<bool> CanUpdateUserAccessAsync(ICollection<Collection> resources, CurrentContextOrganization? org)
{ {
return await CanUpdateCollectionAsync(resources, org) || org?.Permissions.ManageUsers == true; if (await AllowAdminAccessToAllCollectionItems(org) && org?.Permissions.ManageUsers == true)
{
return true;
}
return await CanUpdateCollectionAsync(resources, org);
} }
private async Task<bool> CanUpdateGroupAccessAsync(ICollection<Collection> resources, CurrentContextOrganization? org) private async Task<bool> CanUpdateGroupAccessAsync(ICollection<Collection> resources, CurrentContextOrganization? org)
{ {
return await CanUpdateCollectionAsync(resources, org) || org?.Permissions.ManageGroups == true; if (await AllowAdminAccessToAllCollectionItems(org) && org?.Permissions.ManageGroups == true)
{
return true;
}
return await CanUpdateCollectionAsync(resources, org);
} }
private async Task<bool> CanDeleteAsync(ICollection<Collection> resources, CurrentContextOrganization? org) private async Task<bool> CanDeleteAsync(ICollection<Collection> resources, CurrentContextOrganization? org)
@ -313,4 +323,11 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
return await _applicationCacheService.GetOrganizationAbilityAsync(organization.Id); return await _applicationCacheService.GetOrganizationAbilityAsync(organization.Id);
} }
private async Task<bool> AllowAdminAccessToAllCollectionItems(CurrentContextOrganization? org)
{
var organizationAbility = await GetOrganizationAbilityAsync(org);
return !_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1) ||
organizationAbility is { AllowAdminAccessToAllCollectionItems: true };
}
} }

View File

@ -828,79 +828,167 @@ public class BulkCollectionAuthorizationHandlerTests
} }
[Theory, BitAutoData, CollectionCustomization] [Theory, BitAutoData, CollectionCustomization]
public async Task CanUpdateUsers_WithManageUsersCustomPermission_Success( public async Task CanUpdateUsers_WithManageUsersCustomPermission_V1Disabled_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider, SutProvider<BulkCollectionAuthorizationHandler> sutProvider, ICollection<Collection> collections,
ICollection<Collection> collections, CurrentContextOrganization organization, Guid actingUserId)
CurrentContextOrganization organization)
{ {
var actingUserId = Guid.NewGuid();
organization.Type = OrganizationUserType.Custom; organization.Type = OrganizationUserType.Custom;
organization.Permissions = new Permissions organization.Permissions = new Permissions
{ {
ManageUsers = true ManageUsers = true
}; };
var operationsToTest = new[] sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
{ sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
BulkCollectionOperations.ModifyUserAccess, sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1)
}; .Returns(false);
foreach (var op in operationsToTest) var context = new AuthorizationHandlerContext(
{ new[] { BulkCollectionOperations.ModifyUserAccess },
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId); new ClaimsPrincipal(),
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization); collections);
var context = new AuthorizationHandlerContext( await sutProvider.Sut.HandleAsync(context);
new[] { op },
new ClaimsPrincipal(),
collections);
await sutProvider.Sut.HandleAsync(context); Assert.True(context.HasSucceeded);
Assert.True(context.HasSucceeded);
// Recreate the SUT to reset the mocks/dependencies between tests
sutProvider.Recreate();
}
} }
[Theory, BitAutoData, CollectionCustomization] [Theory, BitAutoData, CollectionCustomization]
public async Task CanUpdateGroups_WithManageGroupsCustomPermission_Success( public async Task CanUpdateUsers_WithManageUsersCustomPermission_AllowAdminAccessIsTrue_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider, SutProvider<BulkCollectionAuthorizationHandler> sutProvider, ICollection<Collection> collections,
ICollection<Collection> collections, CurrentContextOrganization organization, Guid actingUserId)
CurrentContextOrganization organization)
{ {
var actingUserId = Guid.NewGuid(); organization.Type = OrganizationUserType.Custom;
organization.Permissions = new Permissions
{
ManageUsers = true
};
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1)
.Returns(true);
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilityAsync(organization.Id)
.Returns(new OrganizationAbility { AllowAdminAccessToAllCollectionItems = true });
var context = new AuthorizationHandlerContext(
new[] { BulkCollectionOperations.ModifyUserAccess },
new ClaimsPrincipal(),
collections);
await sutProvider.Sut.HandleAsync(context);
Assert.True(context.HasSucceeded);
}
[Theory, BitAutoData, CollectionCustomization]
public async Task CanUpdateUsers_WithManageUsersCustomPermission_AllowAdminAccessIsFalse_Failure(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider, ICollection<Collection> collections,
CurrentContextOrganization organization, Guid actingUserId)
{
organization.Type = OrganizationUserType.Custom;
organization.Permissions = new Permissions
{
ManageUsers = true
};
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1)
.Returns(true);
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilityAsync(organization.Id)
.Returns(new OrganizationAbility { AllowAdminAccessToAllCollectionItems = false });
var context = new AuthorizationHandlerContext(
new[] { BulkCollectionOperations.ModifyUserAccess },
new ClaimsPrincipal(),
collections);
await sutProvider.Sut.HandleAsync(context);
Assert.False(context.HasSucceeded);
}
[Theory, BitAutoData, CollectionCustomization]
public async Task CanUpdateGroups_WithManageGroupsCustomPermission_V1Disabled_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider, ICollection<Collection> collections,
CurrentContextOrganization organization, Guid actingUserId)
{
organization.Type = OrganizationUserType.Custom; organization.Type = OrganizationUserType.Custom;
organization.Permissions = new Permissions organization.Permissions = new Permissions
{ {
ManageGroups = true ManageGroups = true
}; };
var operationsToTest = new[] sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1)
.Returns(false);
var context = new AuthorizationHandlerContext(
new[] { BulkCollectionOperations.ModifyGroupAccess },
new ClaimsPrincipal(),
collections);
await sutProvider.Sut.HandleAsync(context);
Assert.True(context.HasSucceeded);
}
[Theory, BitAutoData, CollectionCustomization]
public async Task CanUpdateGroups_WithManageGroupsCustomPermission_AllowAdminAccessIsTrue_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider, ICollection<Collection> collections,
CurrentContextOrganization organization, Guid actingUserId)
{
organization.Type = OrganizationUserType.Custom;
organization.Permissions = new Permissions
{ {
BulkCollectionOperations.ModifyGroupAccess, ManageGroups = true
}; };
foreach (var op in operationsToTest) sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1)
.Returns(true);
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilityAsync(organization.Id)
.Returns(new OrganizationAbility { AllowAdminAccessToAllCollectionItems = true });
var context = new AuthorizationHandlerContext(
new[] { BulkCollectionOperations.ModifyGroupAccess },
new ClaimsPrincipal(),
collections);
await sutProvider.Sut.HandleAsync(context);
Assert.True(context.HasSucceeded);
}
[Theory, BitAutoData, CollectionCustomization]
public async Task CanUpdateGroups_WithManageGroupsCustomPermission_AllowAdminAccessIsFalse_Failure(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider, ICollection<Collection> collections,
CurrentContextOrganization organization, Guid actingUserId)
{
organization.Type = OrganizationUserType.Custom;
organization.Permissions = new Permissions
{ {
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId); ManageGroups = true
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization); };
var context = new AuthorizationHandlerContext( sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
new[] { op }, sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
new ClaimsPrincipal(), sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1)
collections); .Returns(true);
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilityAsync(organization.Id)
.Returns(new OrganizationAbility { AllowAdminAccessToAllCollectionItems = false });
await sutProvider.Sut.HandleAsync(context); var context = new AuthorizationHandlerContext(
new[] { BulkCollectionOperations.ModifyGroupAccess },
new ClaimsPrincipal(),
collections);
Assert.True(context.HasSucceeded); await sutProvider.Sut.HandleAsync(context);
// Recreate the SUT to reset the mocks/dependencies between tests Assert.False(context.HasSucceeded);
sutProvider.Recreate();
}
} }
[Theory, BitAutoData, CollectionCustomization] [Theory, BitAutoData, CollectionCustomization]