1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 05:00:19 -05:00
bitwarden/test/Core.Test/Vault/Queries/GetCipherPermissionsForUserQueryTests.cs
Shane Melton a99f82dddd
[PM-14378] SecurityTask Authorization Handler (#5039)
* [PM-14378] Introduce GetCipherPermissionsForOrganization query for Dapper CipherRepository

* [PM-14378] Introduce GetCipherPermissionsForOrganization method for Entity Framework

* [PM-14378] Add integration tests for new repository method

* [PM-14378] Introduce IGetCipherPermissionsForUserQuery CQRS query

* [PM-14378] Introduce SecurityTaskOperationRequirement

* [PM-14378] Introduce SecurityTaskAuthorizationHandler.cs

* [PM-14378] Introduce SecurityTaskOrganizationAuthorizationHandler.cs

* [PM-14378] Register new authorization handlers

* [PM-14378] Formatting

* [PM-14378] Add unit tests for GetCipherPermissionsForUserQuery

* [PM-15378] Cleanup SecurityTaskAuthorizationHandler and add tests

* [PM-14378] Add tests for SecurityTaskOrganizationAuthorizationHandler

* [PM-14378] Formatting

* [PM-14378] Update date in migration file

* [PM-14378] Add missing awaits

* [PM-14378] Bump migration script date

* [PM-14378] Remove Unassigned property from OrganizationCipherPermission as it was making the query too complicated

* [PM-14378] Update sproc to use Union All to improve query performance

* [PM-14378] Bump migration script date
2025-01-09 12:14:24 -08:00

239 lines
9.1 KiB
C#

using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Models.Data.Organizations;
using Bit.Core.Services;
using Bit.Core.Vault.Models.Data;
using Bit.Core.Vault.Queries;
using Bit.Core.Vault.Repositories;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Vault.Queries;
[SutProviderCustomize]
public class GetCipherPermissionsForUserQueryTests
{
private static Guid _noAccessCipherId = Guid.NewGuid();
private static Guid _readOnlyCipherId = Guid.NewGuid();
private static Guid _editCipherId = Guid.NewGuid();
private static Guid _manageCipherId = Guid.NewGuid();
private static Guid _readExceptPasswordCipherId = Guid.NewGuid();
private static Guid _unassignedCipherId = Guid.NewGuid();
private static List<Guid> _cipherIds = new[]
{
_noAccessCipherId,
_readOnlyCipherId,
_editCipherId,
_manageCipherId,
_readExceptPasswordCipherId,
_unassignedCipherId
}.ToList();
[Theory, BitAutoData]
public async Task GetCipherPermissionsForUserQuery_Base(Guid userId, CurrentContextOrganization org, SutProvider<GetCipherPermissionsForUserQuery> sutProvider
)
{
var organizationId = org.Id;
org.Type = OrganizationUserType.User;
org.Permissions.EditAnyCollection = false;
var cipherPermissions = CreateCipherPermissions();
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organizationId).Returns(org);
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
sutProvider.GetDependency<ICipherRepository>().GetCipherPermissionsForOrganizationAsync(organizationId, userId)
.Returns(cipherPermissions);
sutProvider.GetDependency<ICipherRepository>()
.GetManyUnassignedOrganizationDetailsByOrganizationIdAsync(organizationId)
.Returns(new List<CipherOrganizationDetails>
{
new() { Id = _unassignedCipherId }
});
var result = await sutProvider.Sut.GetByOrganization(organizationId);
Assert.Equal(6, result.Count);
Assert.All(result, x => Assert.Contains(x.Key, _cipherIds));
Assert.False(result[_noAccessCipherId].Read);
Assert.True(result[_readOnlyCipherId].Read);
Assert.False(result[_readOnlyCipherId].Edit);
Assert.True(result[_editCipherId].Edit);
Assert.True(result[_manageCipherId].Manage);
Assert.True(result[_readExceptPasswordCipherId].Read);
Assert.False(result[_readExceptPasswordCipherId].ViewPassword);
Assert.False(result[_unassignedCipherId].Read);
}
[Theory, BitAutoData]
public async Task GetCipherPermissionsForUserQuery_CanEditAllCiphers_CustomUser(Guid userId, CurrentContextOrganization org, SutProvider<GetCipherPermissionsForUserQuery> sutProvider
)
{
var organizationId = org.Id;
var cipherPermissions = CreateCipherPermissions();
org.Permissions.EditAnyCollection = true;
org.Type = OrganizationUserType.Custom;
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organizationId).Returns(org);
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
sutProvider.GetDependency<ICipherRepository>().GetCipherPermissionsForOrganizationAsync(organizationId, userId)
.Returns(cipherPermissions);
sutProvider.GetDependency<ICipherRepository>()
.GetManyUnassignedOrganizationDetailsByOrganizationIdAsync(organizationId)
.Returns(new List<CipherOrganizationDetails>
{
new() { Id = _unassignedCipherId }
});
var result = await sutProvider.Sut.GetByOrganization(organizationId);
Assert.Equal(6, result.Count);
Assert.All(result, x => Assert.Contains(x.Key, _cipherIds));
Assert.All(result, x => Assert.True(x.Value.Read && x.Value.Edit && x.Value.Manage && x.Value.ViewPassword));
}
[Theory, BitAutoData]
public async Task GetCipherPermissionsForUserQuery_CanEditAllCiphers_Admin(Guid userId, CurrentContextOrganization org, SutProvider<GetCipherPermissionsForUserQuery> sutProvider
)
{
var organizationId = org.Id;
var cipherPermissions = CreateCipherPermissions();
org.Permissions.EditAnyCollection = false;
org.Type = OrganizationUserType.Admin;
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organizationId).Returns(org);
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilityAsync(org.Id).Returns(new OrganizationAbility
{
AllowAdminAccessToAllCollectionItems = true
});
sutProvider.GetDependency<ICipherRepository>().GetCipherPermissionsForOrganizationAsync(organizationId, userId)
.Returns(cipherPermissions);
sutProvider.GetDependency<ICipherRepository>()
.GetManyUnassignedOrganizationDetailsByOrganizationIdAsync(organizationId)
.Returns(new List<CipherOrganizationDetails>
{
new() { Id = _unassignedCipherId }
});
var result = await sutProvider.Sut.GetByOrganization(organizationId);
Assert.Equal(6, result.Count);
Assert.All(result, x => Assert.Contains(x.Key, _cipherIds));
Assert.All(result, x => Assert.True(x.Value.Read && x.Value.Edit && x.Value.Manage && x.Value.ViewPassword));
}
[Theory, BitAutoData]
public async Task GetCipherPermissionsForUserQuery_CanEditUnassignedCiphers(Guid userId, CurrentContextOrganization org, SutProvider<GetCipherPermissionsForUserQuery> sutProvider
)
{
var organizationId = org.Id;
var cipherPermissions = CreateCipherPermissions();
org.Type = OrganizationUserType.Owner;
org.Permissions.EditAnyCollection = false;
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organizationId).Returns(org);
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
sutProvider.GetDependency<ICipherRepository>().GetCipherPermissionsForOrganizationAsync(organizationId, userId)
.Returns(cipherPermissions);
sutProvider.GetDependency<ICipherRepository>()
.GetManyUnassignedOrganizationDetailsByOrganizationIdAsync(organizationId)
.Returns(new List<CipherOrganizationDetails>
{
new() { Id = _unassignedCipherId }
});
var result = await sutProvider.Sut.GetByOrganization(organizationId);
Assert.Equal(6, result.Count);
Assert.All(result, x => Assert.Contains(x.Key, _cipherIds));
Assert.False(result[_noAccessCipherId].Read);
Assert.True(result[_readOnlyCipherId].Read);
Assert.False(result[_readOnlyCipherId].Edit);
Assert.True(result[_editCipherId].Edit);
Assert.True(result[_manageCipherId].Manage);
Assert.True(result[_readExceptPasswordCipherId].Read);
Assert.False(result[_readExceptPasswordCipherId].ViewPassword);
Assert.True(result[_unassignedCipherId].Read);
Assert.True(result[_unassignedCipherId].Edit);
Assert.True(result[_unassignedCipherId].ViewPassword);
Assert.True(result[_unassignedCipherId].Manage);
}
private List<OrganizationCipherPermission> CreateCipherPermissions()
{
// User has no relationship with the cipher
var noAccessCipher = new OrganizationCipherPermission
{
Id = _noAccessCipherId,
Read = false,
Edit = false,
Manage = false,
ViewPassword = false,
};
var readOnlyCipher = new OrganizationCipherPermission
{
Id = _readOnlyCipherId,
Read = true,
Edit = false,
Manage = false,
ViewPassword = true,
};
var editCipher = new OrganizationCipherPermission
{
Id = _editCipherId,
Read = true,
Edit = true,
Manage = false,
ViewPassword = true,
};
var manageCipher = new OrganizationCipherPermission
{
Id = _manageCipherId,
Read = true,
Edit = true,
Manage = true,
ViewPassword = true,
};
var readExceptPasswordCipher = new OrganizationCipherPermission
{
Id = _readExceptPasswordCipherId,
Read = true,
Edit = false,
Manage = false,
ViewPassword = false,
};
var unassignedCipher = new OrganizationCipherPermission
{
Id = _unassignedCipherId,
Read = false,
Edit = false,
Manage = false,
ViewPassword = false,
};
return new List<OrganizationCipherPermission>
{
noAccessCipher,
readOnlyCipher,
editCipher,
manageCipher,
readExceptPasswordCipher,
unassignedCipher
};
}
}