using Bit.Core.AdminConsole.Models.Data; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Requests; using Bit.Core.Enums; using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; using NSubstitute; using Xunit; namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationUsers; [SutProviderCustomize] public class RevokeNonCompliantOrganizationUserCommandTests { [Theory, BitAutoData] public async Task RevokeNonCompliantOrganizationUsersAsync_GivenUnrecognizedUserType_WhenAttemptingToRevoke_ThenErrorShouldBeReturned( Guid organizationId, SutProvider sutProvider) { var command = new RevokeOrganizationUsersRequest(organizationId, [], new InvalidUser()); var result = await sutProvider.Sut.RevokeNonCompliantOrganizationUsersAsync(command); Assert.True(result.HasErrors); Assert.Contains(RevokeNonCompliantOrganizationUserCommand.ErrorRequestedByWasNotValid, result.ErrorMessages); } [Theory, BitAutoData] public async Task RevokeNonCompliantOrganizationUsersAsync_GivenPopulatedRequest_WhenUserAttemptsToRevokeThemselves_ThenErrorShouldBeReturned( Guid organizationId, OrganizationUserUserDetails revokingUser, SutProvider sutProvider) { var command = new RevokeOrganizationUsersRequest(organizationId, revokingUser, new StandardUser(revokingUser?.UserId ?? Guid.NewGuid(), true)); var result = await sutProvider.Sut.RevokeNonCompliantOrganizationUsersAsync(command); Assert.True(result.HasErrors); Assert.Contains(RevokeNonCompliantOrganizationUserCommand.ErrorCannotRevokeSelf, result.ErrorMessages); } [Theory, BitAutoData] public async Task RevokeNonCompliantOrganizationUsersAsync_GivenPopulatedRequest_WhenUserAttemptsToRevokeOrgUsersFromAnotherOrg_ThenErrorShouldBeReturned( Guid organizationId, OrganizationUserUserDetails userFromAnotherOrg, SutProvider sutProvider) { userFromAnotherOrg.OrganizationId = Guid.NewGuid(); var command = new RevokeOrganizationUsersRequest(organizationId, userFromAnotherOrg, new StandardUser(Guid.NewGuid(), true)); var result = await sutProvider.Sut.RevokeNonCompliantOrganizationUsersAsync(command); Assert.True(result.HasErrors); Assert.Contains(RevokeNonCompliantOrganizationUserCommand.ErrorInvalidUsers, result.ErrorMessages); } [Theory, BitAutoData] public async Task RevokeNonCompliantOrganizationUsersAsync_GivenPopulatedRequest_WhenUserAttemptsToRevokeAllOwnersFromOrg_ThenErrorShouldBeReturned( Guid organizationId, OrganizationUserUserDetails userToRevoke, SutProvider sutProvider) { userToRevoke.OrganizationId = organizationId; var command = new RevokeOrganizationUsersRequest(organizationId, userToRevoke, new StandardUser(Guid.NewGuid(), true)); sutProvider.GetDependency() .HasConfirmedOwnersExceptAsync(organizationId, Arg.Any>()) .Returns(false); var result = await sutProvider.Sut.RevokeNonCompliantOrganizationUsersAsync(command); Assert.True(result.HasErrors); Assert.Contains(RevokeNonCompliantOrganizationUserCommand.ErrorOrgMustHaveAtLeastOneOwner, result.ErrorMessages); } [Theory, BitAutoData] public async Task RevokeNonCompliantOrganizationUsersAsync_GivenPopulatedRequest_WhenUserAttemptsToRevokeOwnerWhenNotAnOwner_ThenErrorShouldBeReturned( Guid organizationId, OrganizationUserUserDetails userToRevoke, SutProvider sutProvider) { userToRevoke.OrganizationId = organizationId; userToRevoke.Type = OrganizationUserType.Owner; var command = new RevokeOrganizationUsersRequest(organizationId, userToRevoke, new StandardUser(Guid.NewGuid(), false)); sutProvider.GetDependency() .HasConfirmedOwnersExceptAsync(organizationId, Arg.Any>()) .Returns(true); var result = await sutProvider.Sut.RevokeNonCompliantOrganizationUsersAsync(command); Assert.True(result.HasErrors); Assert.Contains(RevokeNonCompliantOrganizationUserCommand.ErrorOnlyOwnersCanRevokeOtherOwners, result.ErrorMessages); } [Theory, BitAutoData] public async Task RevokeNonCompliantOrganizationUsersAsync_GivenPopulatedRequest_WhenUserAttemptsToRevokeUserWhoIsAlreadyRevoked_ThenErrorShouldBeReturned( Guid organizationId, OrganizationUserUserDetails userToRevoke, SutProvider sutProvider) { userToRevoke.OrganizationId = organizationId; userToRevoke.Status = OrganizationUserStatusType.Revoked; var command = new RevokeOrganizationUsersRequest(organizationId, userToRevoke, new StandardUser(Guid.NewGuid(), true)); sutProvider.GetDependency() .HasConfirmedOwnersExceptAsync(organizationId, Arg.Any>()) .Returns(true); var result = await sutProvider.Sut.RevokeNonCompliantOrganizationUsersAsync(command); Assert.True(result.HasErrors); Assert.Contains($"{RevokeNonCompliantOrganizationUserCommand.ErrorUserAlreadyRevoked} Id: {userToRevoke.Id}", result.ErrorMessages); } [Theory, BitAutoData] public async Task RevokeNonCompliantOrganizationUsersAsync_GivenPopulatedRequest_WhenUserHasMultipleInvalidUsers_ThenErrorShouldBeReturned( Guid organizationId, IEnumerable usersToRevoke, SutProvider sutProvider) { var revocableUsers = usersToRevoke.ToList(); revocableUsers.ForEach(user => user.OrganizationId = organizationId); revocableUsers[0].Type = OrganizationUserType.Owner; revocableUsers[1].Status = OrganizationUserStatusType.Revoked; var command = new RevokeOrganizationUsersRequest(organizationId, revocableUsers, new StandardUser(Guid.NewGuid(), false)); sutProvider.GetDependency() .HasConfirmedOwnersExceptAsync(organizationId, Arg.Any>()) .Returns(true); var result = await sutProvider.Sut.RevokeNonCompliantOrganizationUsersAsync(command); Assert.True(result.HasErrors); Assert.True(result.ErrorMessages.Count > 1); } [Theory, BitAutoData] public async Task RevokeNonCompliantOrganizationUsersAsync_GivenValidPopulatedRequest_WhenUserAttemptsToRevokeAUser_ThenUserShouldBeRevoked( Guid organizationId, OrganizationUserUserDetails userToRevoke, SutProvider sutProvider) { userToRevoke.OrganizationId = organizationId; userToRevoke.Type = OrganizationUserType.Admin; var command = new RevokeOrganizationUsersRequest(organizationId, userToRevoke, new StandardUser(Guid.NewGuid(), false)); sutProvider.GetDependency() .HasConfirmedOwnersExceptAsync(organizationId, Arg.Any>()) .Returns(true); var result = await sutProvider.Sut.RevokeNonCompliantOrganizationUsersAsync(command); await sutProvider.GetDependency() .Received(1) .RevokeManyByIdAsync(Arg.Is>(x => x.Count() == 1 && x.Contains(userToRevoke.Id))); Assert.True(result.Success); await sutProvider.GetDependency() .Received(1) .LogOrganizationUserEventsAsync( Arg.Is>( x => x.Any(y => y.organizationUser.Id == userToRevoke.Id && y.eventType == EventType.OrganizationUser_Revoked) )); } public class InvalidUser : IActingUser { public Guid? UserId => Guid.Empty; public bool IsOrganizationOwnerOrProvider => false; public EventSystemUser? SystemUserType => null; } }