You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
744 lines
31 KiB
744 lines
31 KiB
using System.Security.Claims; |
|
using AutoFixture; |
|
using Bit.Api.Models.Request; |
|
using Bit.Api.Tools.Controllers; |
|
using Bit.Api.Tools.Models.Request.Accounts; |
|
using Bit.Api.Tools.Models.Request.Organizations; |
|
using Bit.Api.Vault.AuthorizationHandlers.Collections; |
|
using Bit.Api.Vault.Models.Request; |
|
using Bit.Core.Context; |
|
using Bit.Core.Entities; |
|
using Bit.Core.Exceptions; |
|
using Bit.Core.Repositories; |
|
using Bit.Core.Tools.ImportFeatures.Interfaces; |
|
using Bit.Core.Vault.Entities; |
|
using Bit.Core.Vault.Models.Data; |
|
using Bit.Test.Common.AutoFixture; |
|
using Bit.Test.Common.AutoFixture.Attributes; |
|
using Microsoft.AspNetCore.Authorization; |
|
using NSubstitute; |
|
using NSubstitute.ClearExtensions; |
|
using Xunit; |
|
using GlobalSettings = Bit.Core.Settings.GlobalSettings; |
|
|
|
namespace Bit.Api.Test.Tools.Controllers; |
|
|
|
[ControllerCustomize(typeof(ImportCiphersController))] |
|
[SutProviderCustomize] |
|
public class ImportCiphersControllerTests |
|
{ |
|
|
|
/************************* |
|
* PostImport - Individual |
|
*************************/ |
|
[Theory, BitAutoData] |
|
public async Task PostImportIndividual_ImportCiphersRequestModel_BadRequestException(SutProvider<ImportCiphersController> sutProvider, IFixture fixture) |
|
{ |
|
// Arrange |
|
sutProvider.GetDependency<Core.Settings.GlobalSettings>() |
|
.SelfHosted = false; |
|
var ciphers = fixture.CreateMany<CipherRequestModel>(7001).ToArray(); |
|
var model = new ImportCiphersRequestModel |
|
{ |
|
Ciphers = ciphers, |
|
FolderRelationships = null, |
|
Folders = null |
|
}; |
|
|
|
// Act |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.PostImport(model)); |
|
|
|
// Assert |
|
Assert.Equal("You cannot import this much data at once.", exception.Message); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportIndividual_ImportCiphersRequestModel_Success(User user, |
|
IFixture fixture, SutProvider<ImportCiphersController> sutProvider) |
|
{ |
|
// Arrange |
|
sutProvider.GetDependency<GlobalSettings>() |
|
.SelfHosted = false; |
|
|
|
sutProvider.GetDependency<Bit.Core.Services.IUserService>() |
|
.GetProperUserId(Arg.Any<ClaimsPrincipal>()) |
|
.Returns(user.Id); |
|
|
|
var request = fixture.Build<ImportCiphersRequestModel>() |
|
.With(x => x.Ciphers, fixture.Build<CipherRequestModel>() |
|
.With(c => c.OrganizationId, Guid.NewGuid().ToString()) |
|
.With(c => c.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(1).ToArray()) |
|
.Create(); |
|
|
|
// Act |
|
await sutProvider.Sut.PostImport(request); |
|
|
|
// Assert |
|
await sutProvider.GetDependency<IImportCiphersCommand>() |
|
.Received() |
|
.ImportIntoIndividualVaultAsync( |
|
Arg.Any<List<Folder>>(), |
|
Arg.Any<List<CipherDetails>>(), |
|
Arg.Any<IEnumerable<KeyValuePair<int, int>>>(), |
|
user.Id |
|
); |
|
} |
|
|
|
/**************************** |
|
* PostImport - Organization |
|
****************************/ |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_ImportOrganizationCiphersRequestModel_BadRequestException(SutProvider<ImportCiphersController> sutProvider, IFixture fixture) |
|
{ |
|
// Arrange |
|
var globalSettings = sutProvider.GetDependency<Core.Settings.GlobalSettings>(); |
|
globalSettings.SelfHosted = false; |
|
|
|
var userService = sutProvider.GetDependency<Bit.Core.Services.IUserService>(); |
|
userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()) |
|
.Returns(null as Guid?); |
|
|
|
globalSettings.ImportCiphersLimitation = new GlobalSettings.ImportCiphersLimitationSettings() |
|
{ // limits are set in appsettings.json, making values small for test to run faster. |
|
CiphersLimit = 200, |
|
CollectionsLimit = 400, |
|
CollectionRelationshipsLimit = 20 |
|
}; |
|
|
|
var ciphers = fixture.CreateMany<CipherRequestModel>(201).ToArray(); |
|
var model = new ImportOrganizationCiphersRequestModel |
|
{ |
|
Collections = null, |
|
Ciphers = ciphers, |
|
CollectionRelationships = null |
|
}; |
|
|
|
// Act |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.PostImport(Arg.Any<string>(), model)); |
|
|
|
// Assert |
|
Assert.Equal("You cannot import this much data at once.", exception.Message); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_ImportOrganizationCiphersRequestModel_Succeeds( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = "AD89E6F8-4E84-4CFE-A978-256CC0DBF974"; |
|
var orgIdGuid = Guid.Parse(orgId); |
|
var existingCollections = fixture.CreateMany<CollectionWithIdRequestModel>(2).ToArray(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
|
|
sutProvider.GetDependency<Bit.Core.Services.IUserService>() |
|
.GetProperUserId(Arg.Any<ClaimsPrincipal>()) |
|
.Returns(user.Id); |
|
|
|
var request = fixture.Build<ImportOrganizationCiphersRequestModel>() |
|
.With(x => x.Ciphers, fixture.Build<CipherRequestModel>() |
|
.With(c => c.OrganizationId, Guid.NewGuid().ToString()) |
|
.With(c => c.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(1).ToArray()) |
|
.With(y => y.Collections, fixture.Build<CollectionWithIdRequestModel>() |
|
.With(c => c.Id, orgIdGuid) |
|
.CreateMany(1).ToArray()) |
|
.Create(); |
|
|
|
// AccessImportExport permission setup |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission setup |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
// BulkCollectionOperations.Create permission setup |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgIdGuid) |
|
.Returns(existingCollections.Select(c => new Collection { Id = orgIdGuid }).ToList()); |
|
|
|
// Act |
|
await sutProvider.Sut.PostImport(orgId, request); |
|
|
|
// Assert |
|
await sutProvider.GetDependency<IImportCiphersCommand>() |
|
.Received(1) |
|
.ImportIntoOrganizationalVaultAsync( |
|
Arg.Any<List<Collection>>(), |
|
Arg.Any<List<CipherDetails>>(), |
|
Arg.Any<IEnumerable<KeyValuePair<int, int>>>(), |
|
Arg.Any<Guid>()); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_WithAccessImportExport_Succeeds( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = "AD89E6F8-4E84-4CFE-A978-256CC0DBF974"; |
|
var orgIdGuid = Guid.Parse(orgId); |
|
var existingCollections = fixture.CreateMany<CollectionWithIdRequestModel>(2).ToArray(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
|
|
sutProvider.GetDependency<Bit.Core.Services.IUserService>() |
|
.GetProperUserId(Arg.Any<ClaimsPrincipal>()) |
|
.Returns(user.Id); |
|
|
|
var request = fixture.Build<ImportOrganizationCiphersRequestModel>() |
|
.With(x => x.Ciphers, fixture.Build<CipherRequestModel>() |
|
.With(c => c.OrganizationId, Guid.NewGuid().ToString()) |
|
.With(c => c.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(1).ToArray()) |
|
.With(y => y.Collections, fixture.Build<CollectionWithIdRequestModel>() |
|
.With(c => c.Id, orgIdGuid) |
|
.CreateMany(1).ToArray()) |
|
.Create(); |
|
|
|
// AccessImportExport permission setup |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission setup |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
// BulkCollectionOperations.Create permission setup |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgIdGuid) |
|
.Returns(existingCollections.Select(c => new Collection { Id = orgIdGuid }).ToList()); |
|
|
|
// Act |
|
await sutProvider.Sut.PostImport(orgId, request); |
|
|
|
// Assert |
|
await sutProvider.GetDependency<IImportCiphersCommand>() |
|
.Received(1) |
|
.ImportIntoOrganizationalVaultAsync( |
|
Arg.Any<List<Collection>>(), |
|
Arg.Any<List<CipherDetails>>(), |
|
Arg.Any<IEnumerable<KeyValuePair<int, int>>>(), |
|
Arg.Any<Guid>()); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_WithExistingCollectionsAndWithoutImportCiphersPermissions_ThrowsException( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = "AD89E6F8-4E84-4CFE-A978-256CC0DBF974"; |
|
var orgIdGuid = Guid.Parse(orgId); |
|
var existingCollections = fixture.CreateMany<CollectionWithIdRequestModel>(2).ToArray(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
|
|
SetupUserService(sutProvider, user); |
|
|
|
var request = fixture.Build<ImportOrganizationCiphersRequestModel>() |
|
.With(x => x.Ciphers, fixture.Build<CipherRequestModel>() |
|
.With(c => c.OrganizationId, Guid.NewGuid().ToString()) |
|
.With(c => c.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(1).ToArray()) |
|
.With(y => y.Collections, fixture.Build<CollectionWithIdRequestModel>() |
|
.With(c => c.Id, orgIdGuid) |
|
.CreateMany(1).ToArray()) |
|
.Create(); |
|
|
|
// AccessImportExport permission setup |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission setup |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Failed()); |
|
|
|
// BulkCollectionOperations.Create permission setup |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Failed()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgIdGuid) |
|
.Returns(existingCollections.Select(c => new Collection { Id = orgIdGuid }).ToList()); |
|
|
|
// Act |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
sutProvider.Sut.PostImport(orgId, request)); |
|
|
|
// Assert |
|
Assert.IsType<Bit.Core.Exceptions.BadRequestException>(exception); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_WithoutCreatePermissions_ThrowsException( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = "AD89E6F8-4E84-4CFE-A978-256CC0DBF974"; |
|
var orgIdGuid = Guid.Parse(orgId); |
|
var existingCollections = fixture.CreateMany<CollectionWithIdRequestModel>(2).ToArray(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
|
|
sutProvider.GetDependency<Bit.Core.Services.IUserService>() |
|
.GetProperUserId(Arg.Any<ClaimsPrincipal>()) |
|
.Returns(user.Id); |
|
|
|
var request = fixture.Build<ImportOrganizationCiphersRequestModel>() |
|
.With(x => x.Ciphers, fixture.Build<CipherRequestModel>() |
|
.With(c => c.OrganizationId, Guid.NewGuid().ToString()) |
|
.With(c => c.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(1).ToArray()) |
|
.With(y => y.Collections, fixture.Build<CollectionWithIdRequestModel>() |
|
.With(c => c.Id, orgIdGuid) |
|
.CreateMany(1).ToArray()) |
|
.Create(); |
|
|
|
// AccessImportExport permission setup |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission setup |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Failed()); |
|
|
|
// BulkCollectionOperations.Create permission setup |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Failed()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgIdGuid) |
|
.Returns(existingCollections.Select(c => new Collection { Id = orgIdGuid }).ToList()); |
|
|
|
// Act |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => |
|
sutProvider.Sut.PostImport(orgId, request)); |
|
|
|
// Assert |
|
Assert.IsType<Bit.Core.Exceptions.BadRequestException>(exception); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_CanCreateChildCollectionsWithCreateAndImportPermissionsAsync( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = Guid.NewGuid(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
|
|
SetupUserService(sutProvider, user); |
|
|
|
// Create new collections |
|
var newCollections = fixture.Build<CollectionWithIdRequestModel>() |
|
.CreateMany(2).ToArray(); |
|
|
|
// define existing collections |
|
var existingCollections = fixture.CreateMany<CollectionWithIdRequestModel>(2).ToArray(); |
|
|
|
// import model includes new and existing collection |
|
var request = new ImportOrganizationCiphersRequestModel |
|
{ |
|
Collections = newCollections.Concat(existingCollections).ToArray(), |
|
Ciphers = fixture.Build<CipherRequestModel>() |
|
.With(_ => _.OrganizationId, orgId.ToString()) |
|
.With(_ => _.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(2).ToArray(), |
|
CollectionRelationships = new List<KeyValuePair<int, int>>().ToArray(), |
|
}; |
|
|
|
// AccessImportExport permission - false |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission - true |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
// BulkCollectionOperations.Create permission - true |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgId) |
|
.Returns(existingCollections.Select(c => |
|
new Collection { OrganizationId = orgId, Id = c.Id.GetValueOrDefault() }) |
|
.ToList()); |
|
|
|
// Act |
|
// User imports into collections and creates new collections |
|
// User has ImportCiphers and Create ciphers permission |
|
await sutProvider.Sut.PostImport(orgId.ToString(), request); |
|
|
|
// Assert |
|
await sutProvider.GetDependency<IImportCiphersCommand>() |
|
.Received(1) |
|
.ImportIntoOrganizationalVaultAsync( |
|
Arg.Any<List<Collection>>(), |
|
Arg.Any<List<CipherDetails>>(), |
|
Arg.Any<IEnumerable<KeyValuePair<int, int>>>(), |
|
Arg.Any<Guid>()); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_CannotCreateChildCollectionsWithoutCreatePermissionsAsync( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = Guid.NewGuid(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
|
|
SetupUserService(sutProvider, user); |
|
|
|
// Create new collections |
|
var newCollections = fixture.Build<CollectionWithIdRequestModel>() |
|
.CreateMany(2).ToArray(); |
|
|
|
// define existing collections |
|
var existingCollections = fixture.CreateMany<CollectionWithIdRequestModel>(2).ToArray(); |
|
|
|
// import model includes new and existing collection |
|
var request = new ImportOrganizationCiphersRequestModel |
|
{ |
|
Collections = newCollections.Concat(existingCollections).ToArray(), |
|
Ciphers = fixture.Build<CipherRequestModel>() |
|
.With(_ => _.OrganizationId, orgId.ToString()) |
|
.With(_ => _.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(2).ToArray(), |
|
CollectionRelationships = new List<KeyValuePair<int, int>>().ToArray(), |
|
}; |
|
|
|
// AccessImportExport permission - false |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission - true |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
// BulkCollectionOperations.Create permission - FALSE |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Failed()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgId) |
|
.Returns(existingCollections.Select(c => |
|
new Collection { OrganizationId = orgId, Id = c.Id.GetValueOrDefault() }) |
|
.ToList()); |
|
|
|
// Act |
|
// User imports into an existing collection and creates new collections |
|
// User has ImportCiphers permission only and doesn't have Create permission |
|
var exception = await Assert.ThrowsAsync<BadRequestException>(async () => |
|
{ |
|
await sutProvider.Sut.PostImport(orgId.ToString(), request); |
|
}); |
|
|
|
// Assert |
|
Assert.IsType<BadRequestException>(exception); |
|
await sutProvider.GetDependency<IImportCiphersCommand>() |
|
.DidNotReceive() |
|
.ImportIntoOrganizationalVaultAsync( |
|
Arg.Any<List<Collection>>(), |
|
Arg.Any<List<CipherDetails>>(), |
|
Arg.Any<IEnumerable<KeyValuePair<int, int>>>(), |
|
Arg.Any<Guid>()); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_ImportIntoNewCollectionWithCreatePermissionsOnlyAsync( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = Guid.NewGuid(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
SetupUserService(sutProvider, user); |
|
|
|
// Create new collections |
|
var newCollections = fixture.CreateMany<CollectionWithIdRequestModel>(1).ToArray(); |
|
|
|
// Define existing collections |
|
var existingCollections = new List<CollectionWithIdRequestModel>(); |
|
|
|
// Import model includes new and existing collection |
|
var request = new ImportOrganizationCiphersRequestModel |
|
{ |
|
Collections = newCollections.Concat(existingCollections).ToArray(), |
|
Ciphers = fixture.Build<CipherRequestModel>() |
|
.With(_ => _.OrganizationId, orgId.ToString()) |
|
.With(_ => _.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(2).ToArray(), |
|
CollectionRelationships = new List<KeyValuePair<int, int>>().ToArray(), |
|
}; |
|
|
|
// AccessImportExport permission - false |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission - FALSE |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Failed()); |
|
|
|
// BulkCollectionOperations.Create permission - TRUE |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgId) |
|
.Returns(new List<Collection>()); |
|
|
|
// Act |
|
// User imports/creates a new collection - existing collections not affected |
|
// User has create permissions and doesn't need import permissions |
|
await sutProvider.Sut.PostImport(orgId.ToString(), request); |
|
|
|
// Assert |
|
await sutProvider.GetDependency<IImportCiphersCommand>() |
|
.Received(1) |
|
.ImportIntoOrganizationalVaultAsync( |
|
Arg.Any<List<Collection>>(), |
|
Arg.Any<List<CipherDetails>>(), |
|
Arg.Any<IEnumerable<KeyValuePair<int, int>>>(), |
|
Arg.Any<Guid>()); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_ImportIntoExistingCollectionWithImportPermissionsOnlySuccessAsync( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = Guid.NewGuid(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
|
|
SetupUserService(sutProvider, user); |
|
|
|
// No new collections |
|
var newCollections = new List<CollectionWithIdRequestModel>(); |
|
|
|
// Define existing collections |
|
var existingCollections = fixture.CreateMany<CollectionWithIdRequestModel>(1).ToArray(); |
|
|
|
// Import model includes new and existing collection |
|
var request = new ImportOrganizationCiphersRequestModel |
|
{ |
|
Collections = newCollections.Concat(existingCollections).ToArray(), |
|
Ciphers = fixture.Build<CipherRequestModel>() |
|
.With(_ => _.OrganizationId, orgId.ToString()) |
|
.With(_ => _.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(2).ToArray(), |
|
CollectionRelationships = new List<KeyValuePair<int, int>>().ToArray(), |
|
}; |
|
|
|
// AccessImportExport permission - false |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission - true |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
// BulkCollectionOperations.Create permission - FALSE |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Failed()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgId) |
|
.Returns(existingCollections.Select(c => |
|
new Collection { OrganizationId = orgId, Id = c.Id.GetValueOrDefault() }) |
|
.ToList()); |
|
|
|
// Act |
|
// User import into existing collection |
|
// User has ImportCiphers permission only and doesn't need create permission |
|
await sutProvider.Sut.PostImport(orgId.ToString(), request); |
|
|
|
// Assert |
|
await sutProvider.GetDependency<IImportCiphersCommand>() |
|
.Received(1) |
|
.ImportIntoOrganizationalVaultAsync( |
|
Arg.Any<List<Collection>>(), |
|
Arg.Any<List<CipherDetails>>(), |
|
Arg.Any<IEnumerable<KeyValuePair<int, int>>>(), |
|
Arg.Any<Guid>()); |
|
} |
|
|
|
[Theory, BitAutoData] |
|
public async Task PostImportOrganization_ImportWithNoCollectionsWithCreatePermissionsOnlySuccessAsync( |
|
SutProvider<ImportCiphersController> sutProvider, |
|
IFixture fixture, |
|
User user) |
|
{ |
|
// Arrange |
|
var orgId = Guid.NewGuid(); |
|
|
|
sutProvider.GetDependency<GlobalSettings>().SelfHosted = false; |
|
|
|
SetupUserService(sutProvider, user); |
|
|
|
// Import model includes new and existing collection |
|
var request = new ImportOrganizationCiphersRequestModel |
|
{ |
|
Collections = new List<CollectionWithIdRequestModel>().ToArray(), // No collections |
|
Ciphers = fixture.Build<CipherRequestModel>() |
|
.With(_ => _.OrganizationId, orgId.ToString()) |
|
.With(_ => _.FolderId, Guid.NewGuid().ToString()) |
|
.CreateMany(2).ToArray(), |
|
CollectionRelationships = new List<KeyValuePair<int, int>>().ToArray(), |
|
}; |
|
|
|
// AccessImportExport permission - false |
|
sutProvider.GetDependency<ICurrentContext>() |
|
.AccessImportExport(Arg.Any<Guid>()) |
|
.Returns(false); |
|
|
|
// BulkCollectionOperations.ImportCiphers permission - false |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.ImportCiphers))) |
|
.Returns(AuthorizationResult.Failed()); |
|
|
|
// BulkCollectionOperations.Create permission - TRUE |
|
sutProvider.GetDependency<IAuthorizationService>() |
|
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), |
|
Arg.Any<IEnumerable<Collection>>(), |
|
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs => |
|
reqs.Contains(BulkCollectionOperations.Create))) |
|
.Returns(AuthorizationResult.Success()); |
|
|
|
sutProvider.GetDependency<ICollectionRepository>() |
|
.GetManyByOrganizationIdAsync(orgId) |
|
.Returns(new List<Collection>()); |
|
|
|
// Act |
|
// import ciphers only and no collections |
|
// User has Create permissions |
|
// expected to be successful |
|
await sutProvider.Sut.PostImport(orgId.ToString(), request); |
|
|
|
// Assert |
|
await sutProvider.GetDependency<IImportCiphersCommand>() |
|
.Received(1) |
|
.ImportIntoOrganizationalVaultAsync( |
|
Arg.Any<List<Collection>>(), |
|
Arg.Any<List<CipherDetails>>(), |
|
Arg.Any<IEnumerable<KeyValuePair<int, int>>>(), |
|
Arg.Any<Guid>()); |
|
} |
|
|
|
private static void SetupUserService(SutProvider<ImportCiphersController> sutProvider, User user) |
|
{ |
|
// This is a workaround for the NSubstitute issue with ambiguous arguments |
|
// when using Arg.Any<ClaimsPrincipal>() in the GetProperUserId method |
|
// It clears the previous calls to the userService and sets up a new call |
|
// with the same argument |
|
var userService = sutProvider.GetDependency<Bit.Core.Services.IUserService>(); |
|
try |
|
{ |
|
// in order to fix the Ambiguous Arguments error in NSubstitute |
|
// we need to clear the previous calls |
|
userService.ClearSubstitute(); |
|
userService.ClearReceivedCalls(); |
|
userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()); |
|
} |
|
catch { } |
|
|
|
userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(user.Id); |
|
} |
|
}
|
|
|