1
0
mirror of https://github.com/bitwarden/server synced 2026-01-28 23:36:12 +00:00

remove archive preservation across org import to enforce per user archive status

This commit is contained in:
John Harrington
2026-01-27 07:58:41 -07:00
parent a789b75acd
commit 05dc452d17
4 changed files with 12 additions and 73 deletions

View File

@@ -74,11 +74,6 @@ public class ImportCiphersController : Controller
throw new BadRequestException("You cannot import this much data at once.");
}
if (model.Ciphers.Any(c => c.ArchivedDate.HasValue))
{
throw new BadRequestException("You cannot import archived items into an organization.");
}
var orgId = new Guid(organizationId);
var collections = model.Collections.Select(c => c.ToCollection(orgId)).ToList();

View File

@@ -146,13 +146,10 @@ public class ImportCiphersCommand : IImportCiphersCommand
// Init. ids for ciphers
cipher.SetNewId();
// Preserve archived status for organizational ciphers
// Archives are stored per-user even for org ciphers
if (cipher.ArchivedDate.HasValue)
{
cipher.Archives = $"{{\"{importingUserId.ToString().ToUpperInvariant()}\":\"" +
$"{cipher.ArchivedDate.Value:yyyy-MM-ddTHH:mm:ss.fffffffZ}\"}}";
}
/*
* Archive functionality is a per-user function and should only ever be presented to the user who set the archive
* bit to ON for the item. No admin, other user or task should mark items as archived for other users.
*/
}
var organizationCollectionsIds = (await _collectionRepository.GetManyByOrganizationIdAsync(org.Id)).Select(c => c.Id).ToList();

View File

@@ -806,63 +806,6 @@ public class ImportCiphersControllerTests
Arg.Any<Guid>());
}
[Theory, BitAutoData]
public async Task PostImportOrganization_ThrowsException_WhenAnyCipherIsArchived(
SutProvider<ImportCiphersController> sutProvider,
IFixture fixture,
User user
)
{
var orgId = Guid.NewGuid();
sutProvider.GetDependency<GlobalSettings>()
.SelfHosted = false;
sutProvider.GetDependency<GlobalSettings>()
.ImportCiphersLimitation = _organizationCiphersLimitations;
SetupUserService(sutProvider, user);
var ciphers = fixture.Build<CipherRequestModel>()
.With(_ => _.ArchivedDate, DateTime.UtcNow)
.CreateMany(2).ToArray();
var request = new ImportOrganizationCiphersRequestModel
{
Collections = new List<CollectionWithIdRequestModel>().ToArray(),
Ciphers = ciphers,
CollectionRelationships = new List<KeyValuePair<int, int>>().ToArray(),
};
sutProvider.GetDependency<ICurrentContext>()
.AccessImportExport(Arg.Any<Guid>())
.Returns(false);
sutProvider.GetDependency<IAuthorizationService>()
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(),
Arg.Any<IEnumerable<Collection>>(),
Arg.Is<IEnumerable<IAuthorizationRequirement>>(reqs =>
reqs.Contains(BulkCollectionOperations.ImportCiphers)))
.Returns(AuthorizationResult.Failed());
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>());
var exception = await Assert.ThrowsAsync<BadRequestException>(async () =>
{
await sutProvider.Sut.PostImportOrganization(orgId.ToString(), request);
});
Assert.Equal("You cannot import archived items into an organization.", exception.Message);
}
private static void SetupUserService(SutProvider<ImportCiphersController> sutProvider, User user)
{
// This is a workaround for the NSubstitute issue with ambiguous arguments

View File

@@ -360,8 +360,12 @@ public class ImportCiphersAsyncCommandTests
Arg.Any<List<Folder>>());
}
/*
* Archive functionality is a per-user function and should only ever be presented to the user who set the archive
* bit to ON for the item. No admin, other user or task should mark items as archived for other users
*/
[Theory, BitAutoData]
public async Task ImportIntoOrganizationalVaultAsync_WithArchivedCiphers_PreservesArchiveStatus(
public async Task ImportIntoOrganizationalVaultAsync_WithArchivedCiphers_DoesNotSetArchives(
Organization organization,
Guid importingUserId,
OrganizationUser importingOrganizationUser,
@@ -384,6 +388,7 @@ public class ImportCiphersAsyncCommandTests
}
ciphers[0].ArchivedDate = archivedDate;
ciphers[0].Archives = null;
KeyValuePair<int, int>[] collectionRelationships = {
new(0, 0),
@@ -409,9 +414,8 @@ public class ImportCiphersAsyncCommandTests
.Received(1)
.CreateAsync(
Arg.Is<List<CipherDetails>>(c =>
c[0].Archives != null &&
c[0].Archives.Contains(importingUserId.ToString().ToUpperInvariant()) &&
c[0].Archives.Contains(archivedDate.ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ"))),
c[0].ArchivedDate == archivedDate &&
c[0].Archives == null),
Arg.Any<IEnumerable<Collection>>(),
Arg.Any<IEnumerable<CollectionCipher>>(),
Arg.Any<IEnumerable<CollectionUser>>());