mirror of
https://github.com/bitwarden/server.git
synced 2025-04-06 21:48:12 -05:00
[AC-1443] Update manager permission to only see collections they have access to (#3071)
* [AC-1443] Changed CurrentContext.ViewAllCollections to only check if the user can edit or delete any collection * [AC-1443] Renamed ICollectionService.GetOrganizationCollections to GetOrganizationCollectionsAsync * [AC-1443] Changed CollectionService.GetOrganizationCollectionsAsync to first check CurrentContext.ViewAssignedCollections instead Added unit tests * [AC-1443] Added new unit test to check for Exception when user does not have permission
This commit is contained in:
parent
5275f22f12
commit
95b7652ca9
@ -112,7 +112,7 @@ public class CollectionsController : Controller
|
|||||||
[HttpGet("")]
|
[HttpGet("")]
|
||||||
public async Task<ListResponseModel<CollectionResponseModel>> Get(Guid orgId)
|
public async Task<ListResponseModel<CollectionResponseModel>> Get(Guid orgId)
|
||||||
{
|
{
|
||||||
IEnumerable<Collection> orgCollections = await _collectionService.GetOrganizationCollections(orgId);
|
IEnumerable<Collection> orgCollections = await _collectionService.GetOrganizationCollectionsAsync(orgId);
|
||||||
|
|
||||||
var responses = orgCollections.Select(c => new CollectionResponseModel(c));
|
var responses = orgCollections.Select(c => new CollectionResponseModel(c));
|
||||||
return new ListResponseModel<CollectionResponseModel>(responses);
|
return new ListResponseModel<CollectionResponseModel>(responses);
|
||||||
@ -209,7 +209,7 @@ public class CollectionsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
var userCollections = await _collectionService.GetOrganizationCollections(orgId);
|
var userCollections = await _collectionService.GetOrganizationCollectionsAsync(orgId);
|
||||||
var filteredCollections = userCollections.Where(c => collectionIds.Contains(c.Id) && c.OrganizationId == orgId);
|
var filteredCollections = userCollections.Where(c => collectionIds.Contains(c.Id) && c.OrganizationId == orgId);
|
||||||
|
|
||||||
if (!filteredCollections.Any())
|
if (!filteredCollections.Any())
|
||||||
|
@ -40,7 +40,7 @@ public class OrganizationExportController : Controller
|
|||||||
{
|
{
|
||||||
var userId = _userService.GetProperUserId(User).Value;
|
var userId = _userService.GetProperUserId(User).Value;
|
||||||
|
|
||||||
IEnumerable<Collection> orgCollections = await _collectionService.GetOrganizationCollections(organizationId);
|
IEnumerable<Collection> orgCollections = await _collectionService.GetOrganizationCollectionsAsync(organizationId);
|
||||||
(IEnumerable<CipherOrganizationDetails> orgCiphers, Dictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphersGroupDict) = await _cipherService.GetOrganizationCiphers(userId, organizationId);
|
(IEnumerable<CipherOrganizationDetails> orgCiphers, Dictionary<Guid, IGrouping<Guid, CollectionCipher>> collectionCiphersGroupDict) = await _cipherService.GetOrganizationCiphers(userId, organizationId);
|
||||||
|
|
||||||
if (_currentContext.ClientVersion == null || _currentContext.ClientVersion >= new Version("2023.1.0"))
|
if (_currentContext.ClientVersion == null || _currentContext.ClientVersion >= new Version("2023.1.0"))
|
||||||
|
@ -341,7 +341,7 @@ public class CurrentContext : ICurrentContext
|
|||||||
|
|
||||||
public async Task<bool> ViewAllCollections(Guid orgId)
|
public async Task<bool> ViewAllCollections(Guid orgId)
|
||||||
{
|
{
|
||||||
return await CreateNewCollections(orgId) || await EditAnyCollection(orgId) || await DeleteAnyCollection(orgId);
|
return await EditAnyCollection(orgId) || await DeleteAnyCollection(orgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> EditAssignedCollections(Guid orgId)
|
public async Task<bool> EditAssignedCollections(Guid orgId)
|
||||||
|
@ -7,5 +7,5 @@ public interface ICollectionService
|
|||||||
{
|
{
|
||||||
Task SaveAsync(Collection collection, IEnumerable<CollectionAccessSelection> groups = null, IEnumerable<CollectionAccessSelection> users = null, Guid? assignUserId = null);
|
Task SaveAsync(Collection collection, IEnumerable<CollectionAccessSelection> groups = null, IEnumerable<CollectionAccessSelection> users = null, Guid? assignUserId = null);
|
||||||
Task DeleteUserAsync(Collection collection, Guid organizationUserId);
|
Task DeleteUserAsync(Collection collection, Guid organizationUserId);
|
||||||
Task<IEnumerable<Collection>> GetOrganizationCollections(Guid organizationId);
|
Task<IEnumerable<Collection>> GetOrganizationCollectionsAsync(Guid organizationId);
|
||||||
}
|
}
|
||||||
|
@ -96,9 +96,9 @@ public class CollectionService : ICollectionService
|
|||||||
await _eventService.LogOrganizationUserEventAsync(orgUser, Enums.EventType.OrganizationUser_Updated);
|
await _eventService.LogOrganizationUserEventAsync(orgUser, Enums.EventType.OrganizationUser_Updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<Collection>> GetOrganizationCollections(Guid organizationId)
|
public async Task<IEnumerable<Collection>> GetOrganizationCollectionsAsync(Guid organizationId)
|
||||||
{
|
{
|
||||||
if (!await _currentContext.ViewAllCollections(organizationId) && !await _currentContext.ManageUsers(organizationId) && !await _currentContext.ManageGroups(organizationId) && !await _currentContext.AccessImportExport(organizationId))
|
if (!await _currentContext.ViewAssignedCollections(organizationId) && !await _currentContext.ManageUsers(organizationId) && !await _currentContext.ManageGroups(organizationId) && !await _currentContext.AccessImportExport(organizationId))
|
||||||
{
|
{
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
@ -171,7 +171,7 @@ public class CollectionsControllerTests
|
|||||||
.Returns(user.Id);
|
.Returns(user.Id);
|
||||||
|
|
||||||
sutProvider.GetDependency<ICollectionService>()
|
sutProvider.GetDependency<ICollectionService>()
|
||||||
.GetOrganizationCollections(orgId)
|
.GetOrganizationCollectionsAsync(orgId)
|
||||||
.Returns(collections);
|
.Returns(collections);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@ -237,7 +237,7 @@ public class CollectionsControllerTests
|
|||||||
.Returns(user.Id);
|
.Returns(user.Id);
|
||||||
|
|
||||||
sutProvider.GetDependency<ICollectionService>()
|
sutProvider.GetDependency<ICollectionService>()
|
||||||
.GetOrganizationCollections(orgId)
|
.GetOrganizationCollectionsAsync(orgId)
|
||||||
.Returns(collections);
|
.Returns(collections);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Context;
|
||||||
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Data;
|
using Bit.Core.Models.Data;
|
||||||
@ -185,4 +186,56 @@ public class CollectionServiceTest
|
|||||||
.LogOrganizationUserEventAsync(default, default);
|
.LogOrganizationUserEventAsync(default, default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetOrganizationCollectionsAsync_WithViewAssignedCollectionsTrue_ReturnsAssignedCollections(
|
||||||
|
CollectionDetails collectionDetails, Guid organizationId, Guid userId, SutProvider<CollectionService> sutProvider)
|
||||||
|
{
|
||||||
|
collectionDetails.OrganizationId = organizationId;
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>()
|
||||||
|
.GetManyByUserIdAsync(userId)
|
||||||
|
.Returns(new List<CollectionDetails> { collectionDetails });
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ViewAssignedCollections(organizationId).Returns(true);
|
||||||
|
|
||||||
|
var result = await sutProvider.Sut.GetOrganizationCollectionsAsync(organizationId);
|
||||||
|
|
||||||
|
Assert.Single(result);
|
||||||
|
Assert.Equal(collectionDetails, result.First());
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().GetManyByOrganizationIdAsync(default);
|
||||||
|
await sutProvider.GetDependency<ICollectionRepository>().Received(1).GetManyByUserIdAsync(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetOrganizationCollectionsAsync_WithViewAllCollectionsTrue_ReturnsAllOrganizationCollections(
|
||||||
|
Collection collection, Guid organizationId, Guid userId, SutProvider<CollectionService> sutProvider)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>()
|
||||||
|
.GetManyByOrganizationIdAsync(organizationId)
|
||||||
|
.Returns(new List<Collection> { collection });
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ViewAssignedCollections(organizationId).Returns(true);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ViewAllCollections(organizationId).Returns(true);
|
||||||
|
|
||||||
|
var result = await sutProvider.Sut.GetOrganizationCollectionsAsync(organizationId);
|
||||||
|
|
||||||
|
Assert.Single(result);
|
||||||
|
Assert.Equal(collection, result.First());
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<ICollectionRepository>().Received(1).GetManyByOrganizationIdAsync(organizationId);
|
||||||
|
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().GetManyByUserIdAsync(default);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task GetOrganizationCollectionsAsync_WithViewAssignedCollectionsFalse_ThrowsBadRequestException(
|
||||||
|
Guid organizationId, SutProvider<CollectionService> sutProvider)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ViewAssignedCollections(organizationId).Returns(false);
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetOrganizationCollectionsAsync(organizationId));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().GetManyByOrganizationIdAsync(default);
|
||||||
|
await sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs().GetManyByUserIdAsync(default);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user