1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-28 14:46:14 -05:00
This commit is contained in:
Brandon 2025-05-14 14:59:55 -04:00
parent 31b7dcd0f3
commit 04383a82a1
No known key found for this signature in database
GPG Key ID: A0E0EF0B207BA40D

View File

@ -1,20 +1,18 @@
using Bit.Core.AdminConsole.Models.Business; using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers.Models;
using Bit.Core.AdminConsole.Utilities.Commands;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Test.AutoFixture.OrganizationFixtures; using Bit.Core.Test.AutoFixture.OrganizationFixtures;
using Bit.Core.Tokens; using Bit.Core.Tokens;
using Bit.Core.Tools.Enums;
using Bit.Core.Tools.Models.Business; using Bit.Core.Tools.Models.Business;
using Bit.Core.Tools.Services; using Bit.Core.Tools.Services;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
@ -36,41 +34,48 @@ public class ImportOrganizationUserCommandTests
SutProvider<ImportOrganizationUserCommand> sutProvider, SutProvider<ImportOrganizationUserCommand> sutProvider,
Organization org, Organization org,
List<OrganizationUserUserDetails> existingUsers, List<OrganizationUserUserDetails> existingUsers,
List<ImportedOrganizationUser> newUsers List<ImportedOrganizationUser> newUsers,
) List<ImportedGroup> newGroups)
{ {
// Setup FakeDataProtectorTokenFactory for creating new tokens - this must come first in order to avoid resetting mocks SetupOrganizationConfigForImport(sutProvider, org, existingUsers, newUsers);
sutProvider.SetDependency(_orgUserInviteTokenDataFactory, "orgUserInviteTokenDataFactory");
sutProvider.Create(); var expectedNewUsersCount = newUsers.Count - 1;
var invitedOrganizationUsers = new List<OrganizationUser>();
var invites = new List<OrganizationUserInviteCommandModel>();
foreach (var u in newUsers)
{
invitedOrganizationUsers.Add(new OrganizationUser { Email = u.Email + "@test.com", ExternalId = u.ExternalId });
invites.Add(new OrganizationUserInviteCommandModel(u.Email + "@test.com", u.ExternalId));
}
var inviteCommandModel = new InviteOrganizationUsersRequest(invites.ToArray(), new InviteOrganization(org, null), Guid.Empty, DateTimeOffset.UtcNow);
org.UseDirectory = true;
org.Seats = 10;
newUsers.Add(new ImportedOrganizationUser newUsers.Add(new ImportedOrganizationUser
{ {
Email = existingUsers.First().Email, Email = existingUsers.First().Email,
ExternalId = existingUsers.First().ExternalId ExternalId = existingUsers.First().ExternalId
}); });
var expectedNewUsersCount = newUsers.Count - 1;
existingUsers.First().Type = OrganizationUserType.Owner; existingUsers.First().Type = OrganizationUserType.Owner;
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org); sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
sutProvider.GetDependency<IPaymentService>().HasSecretsManagerStandalone(org).Returns(false);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>(); sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(org.Id).Returns(existingUsers);
SetupOrgUserRepositoryCreateManyAsyncMock(organizationUserRepository); sutProvider.GetDependency<IOrganizationUserRepository>().GetCountByOrganizationIdAsync(org.Id).Returns(existingUsers.Count);
organizationUserRepository.GetManyDetailsByOrganizationAsync(org.Id)
.Returns(existingUsers);
organizationUserRepository.GetCountByOrganizationIdAsync(org.Id)
.Returns(existingUsers.Count);
sutProvider.GetDependency<IHasConfirmedOwnersExceptQuery>()
.HasConfirmedOwnersExceptAsync(org.Id, Arg.Any<IEnumerable<Guid>>())
.Returns(true);
sutProvider.GetDependency<ICurrentContext>().ManageUsers(org.Id).Returns(true); sutProvider.GetDependency<ICurrentContext>().ManageUsers(org.Id).Returns(true);
// Use the arranged command model
sutProvider.GetDependency<IInviteOrganizationUsersCommand>().InviteImportedOrganizationUsersAsync(inviteCommandModel, org.Id)
// assert against this returned CommandResult response
.Returns(new Success<InviteOrganizationUsersResponse>(new InviteOrganizationUsersResponse(invitedOrganizationUsers, org.Id)));
await sutProvider.Sut.ImportAsync(org.Id, newGroups, newUsers, new List<string>(), false, EventSystemUser.PublicApi);
await sutProvider.Sut.ImportAsync(org.Id, null, newUsers, null, false, EventSystemUser.PublicApi); await sutProvider.GetDependency<IInviteOrganizationUsersCommand>().Received(1)
.InviteImportedOrganizationUsersAsync(Arg.Is<InviteOrganizationUsersRequest>(
// These are the invites that should get populated from the CommandResult response above
request => request.Invites.Count() == 0
), org.Id);
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
.UpsertAsync(default); .UpsertAsync(default);
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1) await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
@ -78,36 +83,23 @@ public class ImportOrganizationUserCommandTests
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
.CreateAsync(default); .CreateAsync(default);
// Create new users
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
.CreateManyAsync(Arg.Is<IEnumerable<OrganizationUser>>(users => users.Count() == expectedNewUsersCount));
await sutProvider.GetDependency<ISendOrganizationInvitesCommand>().Received(1)
.SendInvitesAsync(
Arg.Is<SendInvitesRequest>(
info => info.Users.Length == expectedNewUsersCount &&
info.Organization == org));
// Send events // Send events
await sutProvider.GetDependency<IEventService>().Received(1) await sutProvider.GetDependency<IEventService>().Received(1)
.LogOrganizationUserEventsAsync(Arg.Is<IEnumerable<(OrganizationUser, EventType, EventSystemUser, DateTime?)>>(events => .LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUserUserDetails, EventType, EventSystemUser, DateTime?)>>());
events.Count() == expectedNewUsersCount));
await sutProvider.GetDependency<IReferenceEventService>().Received(1) await sutProvider.GetDependency<IReferenceEventService>().Received(1)
.RaiseEventAsync(Arg.Is<ReferenceEvent>(referenceEvent => .RaiseEventAsync(Arg.Any<ReferenceEvent>());
referenceEvent.Type == ReferenceEventType.InvitedUsers && referenceEvent.Id == org.Id &&
referenceEvent.Users == expectedNewUsersCount));
} }
[Theory, PaidOrganizationCustomize, BitAutoData] [Theory, PaidOrganizationCustomize, BitAutoData]
public async Task OrgImportCreateNewUsersAndMarryExistingUser(SutProvider<ImportOrganizationUserCommand> sutProvider, Organization org, List<OrganizationUserUserDetails> existingUsers, public async Task OrgImportCreateNewUsersAndMarryExistingUser(
List<ImportedOrganizationUser> newUsers) SutProvider<ImportOrganizationUserCommand> sutProvider,
Organization org,
List<OrganizationUserUserDetails> existingUsers,
List<ImportedOrganizationUser> newUsers,
List<ImportedGroup> newGroups)
{ {
// Setup FakeDataProtectorTokenFactory for creating new tokens - this must come first in order to avoid resetting mocks SetupOrganizationConfigForImport(sutProvider, org, existingUsers, newUsers);
sutProvider.SetDependency(_orgUserInviteTokenDataFactory, "orgUserInviteTokenDataFactory");
sutProvider.Create();
org.UseDirectory = true;
org.Seats = newUsers.Count + existingUsers.Count + 1;
var reInvitedUser = existingUsers.First(); var reInvitedUser = existingUsers.First();
reInvitedUser.ExternalId = null; reInvitedUser.ExternalId = null;
newUsers.Add(new ImportedOrganizationUser newUsers.Add(new ImportedOrganizationUser
@ -115,24 +107,16 @@ public class ImportOrganizationUserCommandTests
Email = reInvitedUser.Email, Email = reInvitedUser.Email,
ExternalId = reInvitedUser.Email, ExternalId = reInvitedUser.Email,
}); });
var expectedNewUsersCount = newUsers.Count - 1;
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org); sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(org.Id).Returns(org);
sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(org.Id) sutProvider.GetDependency<IOrganizationUserRepository>().GetManyDetailsByOrganizationAsync(org.Id).Returns(existingUsers);
.Returns(existingUsers); sutProvider.GetDependency<IOrganizationUserRepository>().GetCountByOrganizationIdAsync(org.Id).Returns(existingUsers.Count);
sutProvider.GetDependency<IOrganizationUserRepository>().GetCountByOrganizationIdAsync(org.Id) sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(reInvitedUser.Id).Returns(new OrganizationUser { Id = reInvitedUser.Id });
.Returns(existingUsers.Count); sutProvider.GetDependency<IInviteOrganizationUsersCommand>().InviteImportedOrganizationUsersAsync(Arg.Any<InviteOrganizationUsersRequest>(), org.Id)
sutProvider.GetDependency<IOrganizationUserRepository>().GetByIdAsync(reInvitedUser.Id) .Returns(new Success<InviteOrganizationUsersResponse>(new InviteOrganizationUsersResponse(org.Id)));
.Returns(new OrganizationUser { Id = reInvitedUser.Id });
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
SetupOrgUserRepositoryCreateManyAsyncMock(organizationUserRepository); await sutProvider.Sut.ImportAsync(org.Id, newGroups, newUsers, new List<string>(), false, EventSystemUser.PublicApi);
var currentContext = sutProvider.GetDependency<ICurrentContext>();
currentContext.ManageUsers(org.Id).Returns(true);
await sutProvider.Sut.ImportAsync(org.Id, null, newUsers, null, false, EventSystemUser.PublicApi);
await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs() await sutProvider.GetDependency<IOrganizationUserRepository>().DidNotReceiveWithAnyArgs()
.UpsertAsync(default); .UpsertAsync(default);
@ -145,47 +129,28 @@ public class ImportOrganizationUserCommandTests
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1) await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1)
.UpsertManyAsync(Arg.Is<IEnumerable<OrganizationUser>>(users => users.Count() == 1)); .UpsertManyAsync(Arg.Is<IEnumerable<OrganizationUser>>(users => users.Count() == 1));
// Created and invited new users await sutProvider.GetDependency<IInviteOrganizationUsersCommand>().Received(1)
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1) .InviteImportedOrganizationUsersAsync(Arg.Any<InviteOrganizationUsersRequest>(), org.Id);
.CreateManyAsync(Arg.Is<IEnumerable<OrganizationUser>>(users => users.Count() == expectedNewUsersCount));
await sutProvider.GetDependency<ISendOrganizationInvitesCommand>().Received(1) // Send events
.SendInvitesAsync(Arg.Is<SendInvitesRequest>(request =>
request.Users.Length == expectedNewUsersCount &&
request.Organization == org));
// Sent events
await sutProvider.GetDependency<IEventService>().Received(1) await sutProvider.GetDependency<IEventService>().Received(1)
.LogOrganizationUserEventsAsync(Arg.Is<IEnumerable<(OrganizationUser, EventType, EventSystemUser, DateTime?)>>(events => .LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUserUserDetails, EventType, EventSystemUser, DateTime?)>>());
events.Count(e => e.Item2 == EventType.OrganizationUser_Invited) == expectedNewUsersCount));
await sutProvider.GetDependency<IReferenceEventService>().Received(1) await sutProvider.GetDependency<IReferenceEventService>().Received(1)
.RaiseEventAsync(Arg.Is<ReferenceEvent>(referenceEvent => .RaiseEventAsync(Arg.Any<ReferenceEvent>());
referenceEvent.Type == ReferenceEventType.InvitedUsers && referenceEvent.Id == org.Id &&
referenceEvent.Users == expectedNewUsersCount));
} }
private void SetupOrgUserRepositoryCreateManyAsyncMock(IOrganizationUserRepository organizationUserRepository) private void SetupOrganizationConfigForImport(
SutProvider<ImportOrganizationUserCommand> sutProvider,
Organization org,
List<OrganizationUserUserDetails> existingUsers,
List<ImportedOrganizationUser> newUsers)
{ {
organizationUserRepository.CreateManyAsync(Arg.Any<IEnumerable<OrganizationUser>>()).Returns( // Setup FakeDataProtectorTokenFactory for creating new tokens - this must come first in order to avoid resetting mocks
info => sutProvider.SetDependency(_orgUserInviteTokenDataFactory, "orgUserInviteTokenDataFactory");
{ sutProvider.Create();
var orgUsers = info.Arg<IEnumerable<OrganizationUser>>();
foreach (var orgUser in orgUsers)
{
orgUser.Id = Guid.NewGuid();
}
return Task.FromResult<ICollection<Guid>>(orgUsers.Select(u => u.Id).ToList()); org.UseDirectory = true;
} org.Seats = newUsers.Count + existingUsers.Count + 1;
);
organizationUserRepository.CreateAsync(Arg.Any<OrganizationUser>(), Arg.Any<IEnumerable<CollectionAccessSelection>>()).Returns(
info =>
{
var orgUser = info.Arg<OrganizationUser>();
orgUser.Id = Guid.NewGuid();
return Task.FromResult<Guid>(orgUser.Id);
}
);
} }
} }