1
0
mirror of https://github.com/bitwarden/server.git synced 2024-11-25 12:45:18 +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)
{
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)
{
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)
@ -313,4 +323,11 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
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]
public async Task CanUpdateUsers_WithManageUsersCustomPermission_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
ICollection<Collection> collections,
CurrentContextOrganization organization)
public async Task CanUpdateUsers_WithManageUsersCustomPermission_V1Disabled_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider, ICollection<Collection> collections,
CurrentContextOrganization organization, Guid actingUserId)
{
var actingUserId = Guid.NewGuid();
organization.Type = OrganizationUserType.Custom;
organization.Permissions = new Permissions
{
ManageUsers = true
};
var operationsToTest = new[]
{
BulkCollectionOperations.ModifyUserAccess,
};
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1)
.Returns(false);
foreach (var op in operationsToTest)
{
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
var context = new AuthorizationHandlerContext(
new[] { BulkCollectionOperations.ModifyUserAccess },
new ClaimsPrincipal(),
collections);
var context = new AuthorizationHandlerContext(
new[] { op },
new ClaimsPrincipal(),
collections);
await sutProvider.Sut.HandleAsync(context);
await sutProvider.Sut.HandleAsync(context);
Assert.True(context.HasSucceeded);
// Recreate the SUT to reset the mocks/dependencies between tests
sutProvider.Recreate();
}
Assert.True(context.HasSucceeded);
}
[Theory, BitAutoData, CollectionCustomization]
public async Task CanUpdateGroups_WithManageGroupsCustomPermission_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
ICollection<Collection> collections,
CurrentContextOrganization organization)
public async Task CanUpdateUsers_WithManageUsersCustomPermission_AllowAdminAccessIsTrue_Success(
SutProvider<BulkCollectionAuthorizationHandler> sutProvider, ICollection<Collection> collections,
CurrentContextOrganization organization, Guid actingUserId)
{
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.Permissions = new Permissions
{
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);
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
ManageGroups = true
};
var context = new AuthorizationHandlerContext(
new[] { op },
new ClaimsPrincipal(),
collections);
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 });
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
sutProvider.Recreate();
}
Assert.False(context.HasSucceeded);
}
[Theory, BitAutoData, CollectionCustomization]