mirror of
https://github.com/bitwarden/server
synced 2025-12-10 05:13:48 +00:00
PM-27248 [Defect] An unhandled error is returned when a MSP tries to import data (#6563)
* Revert previous commits and implement logic to avoid null references: • reverted previous commits and force pushed to remove inconsistent formatting • implemented logic to avoid null reference access (with comments) * fix typo in comment * fix logical error and add test coverage * extracted logic common to all code paths per review comment
This commit is contained in:
@@ -150,17 +150,34 @@ public class ImportCiphersCommand : IImportCiphersCommand
|
|||||||
|
|
||||||
foreach (var collection in collections)
|
foreach (var collection in collections)
|
||||||
{
|
{
|
||||||
if (!organizationCollectionsIds.Contains(collection.Id))
|
// If the collection already exists, skip it
|
||||||
|
if (organizationCollectionsIds.Contains(collection.Id))
|
||||||
{
|
{
|
||||||
collection.SetNewId();
|
continue;
|
||||||
newCollections.Add(collection);
|
|
||||||
newCollectionUsers.Add(new CollectionUser
|
|
||||||
{
|
|
||||||
CollectionId = collection.Id,
|
|
||||||
OrganizationUserId = importingOrgUser.Id,
|
|
||||||
Manage = true
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create new collections if not already present
|
||||||
|
collection.SetNewId();
|
||||||
|
newCollections.Add(collection);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the organization was created by a Provider, the organization may have zero members (users)
|
||||||
|
* In this situation importingOrgUser will be null, and accessing importingOrgUser.Id will
|
||||||
|
* result in a null reference exception.
|
||||||
|
*
|
||||||
|
* Avoid user assignment, but proceed with adding the collection.
|
||||||
|
*/
|
||||||
|
if (importingOrgUser == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newCollectionUsers.Add(new CollectionUser
|
||||||
|
{
|
||||||
|
CollectionId = collection.Id,
|
||||||
|
OrganizationUserId = importingOrgUser.Id,
|
||||||
|
Manage = true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create associations based on the newly assigned ids
|
// Create associations based on the newly assigned ids
|
||||||
|
|||||||
@@ -238,4 +238,55 @@ public class ImportCiphersAsyncCommandTests
|
|||||||
Assert.Equal("This organization can only have a maximum of " +
|
Assert.Equal("This organization can only have a maximum of " +
|
||||||
$"{organization.MaxCollections} collections.", exception.Message);
|
$"{organization.MaxCollections} collections.", exception.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData]
|
||||||
|
public async Task ImportIntoOrganizationalVaultAsync_WithNullImportingOrgUser_SkipsCollectionUserCreation(
|
||||||
|
Organization organization,
|
||||||
|
Guid importingUserId,
|
||||||
|
List<Collection> collections,
|
||||||
|
List<CipherDetails> ciphers,
|
||||||
|
SutProvider<ImportCiphersCommand> sutProvider)
|
||||||
|
{
|
||||||
|
organization.MaxCollections = null;
|
||||||
|
|
||||||
|
foreach (var collection in collections)
|
||||||
|
{
|
||||||
|
collection.OrganizationId = organization.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var cipher in ciphers)
|
||||||
|
{
|
||||||
|
cipher.OrganizationId = organization.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyValuePair<int, int>[] collectionRelationships = {
|
||||||
|
new(0, 0),
|
||||||
|
new(1, 1),
|
||||||
|
new(2, 2)
|
||||||
|
};
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IOrganizationRepository>()
|
||||||
|
.GetByIdAsync(organization.Id)
|
||||||
|
.Returns(organization);
|
||||||
|
|
||||||
|
// Simulate provider-created org with no members - importing user is NOT an org member
|
||||||
|
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||||
|
.GetByOrganizationAsync(organization.Id, importingUserId)
|
||||||
|
.Returns((OrganizationUser)null);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>()
|
||||||
|
.GetManyByOrganizationIdAsync(organization.Id)
|
||||||
|
.Returns(new List<Collection>());
|
||||||
|
|
||||||
|
await sutProvider.Sut.ImportIntoOrganizationalVaultAsync(collections, ciphers, collectionRelationships, importingUserId);
|
||||||
|
|
||||||
|
// Verify ciphers were created but no CollectionUser entries were created (because the organization user (importingUserId) is null)
|
||||||
|
await sutProvider.GetDependency<ICipherRepository>().Received(1).CreateAsync(
|
||||||
|
ciphers,
|
||||||
|
Arg.Is<IEnumerable<Collection>>(cols => cols.Count() == collections.Count),
|
||||||
|
Arg.Is<IEnumerable<CollectionCipher>>(cc => cc.Count() == ciphers.Count),
|
||||||
|
Arg.Is<IEnumerable<CollectionUser>>(cus => !cus.Any()));
|
||||||
|
|
||||||
|
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user