1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-05 05:00:19 -05:00

[PM-17168] Sync organization user revoked/restored status immediately via push notification (#5330)

* [PM-17168] Add push notification for revoked and restored organization users

* Add feature flag for push notification on user revoke/restore actions

* Add tests for user revocation and restoration with push sync feature flag enabled
This commit is contained in:
Rui Tomé 2025-02-06 10:28:12 +00:00 committed by GitHub
parent 1c3ea1151c
commit a12b61cc9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 230 additions and 66 deletions

View File

@ -1951,6 +1951,11 @@ public class OrganizationService : IOrganizationService
await RepositoryRevokeUserAsync(organizationUser);
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked);
if (_featureService.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore) && organizationUser.UserId.HasValue)
{
await _pushNotificationService.PushSyncOrgKeysAsync(organizationUser.UserId.Value);
}
}
public async Task RevokeUserAsync(OrganizationUser organizationUser,
@ -1958,6 +1963,11 @@ public class OrganizationService : IOrganizationService
{
await RepositoryRevokeUserAsync(organizationUser);
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked, systemUser);
if (_featureService.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore) && organizationUser.UserId.HasValue)
{
await _pushNotificationService.PushSyncOrgKeysAsync(organizationUser.UserId.Value);
}
}
private async Task RepositoryRevokeUserAsync(OrganizationUser organizationUser)
@ -2023,6 +2033,10 @@ public class OrganizationService : IOrganizationService
await _organizationUserRepository.RevokeAsync(organizationUser.Id);
organizationUser.Status = OrganizationUserStatusType.Revoked;
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked);
if (_featureService.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore) && organizationUser.UserId.HasValue)
{
await _pushNotificationService.PushSyncOrgKeysAsync(organizationUser.UserId.Value);
}
result.Add(Tuple.Create(organizationUser, ""));
}
@ -2050,12 +2064,22 @@ public class OrganizationService : IOrganizationService
await RepositoryRestoreUserAsync(organizationUser);
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
if (_featureService.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore) && organizationUser.UserId.HasValue)
{
await _pushNotificationService.PushSyncOrgKeysAsync(organizationUser.UserId.Value);
}
}
public async Task RestoreUserAsync(OrganizationUser organizationUser, EventSystemUser systemUser)
{
await RepositoryRestoreUserAsync(organizationUser);
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored, systemUser);
if (_featureService.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore) && organizationUser.UserId.HasValue)
{
await _pushNotificationService.PushSyncOrgKeysAsync(organizationUser.UserId.Value);
}
}
private async Task RepositoryRestoreUserAsync(OrganizationUser organizationUser)
@ -2147,6 +2171,10 @@ public class OrganizationService : IOrganizationService
await _organizationUserRepository.RestoreAsync(organizationUser.Id, status);
organizationUser.Status = status;
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
if (_featureService.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore) && organizationUser.UserId.HasValue)
{
await _pushNotificationService.PushSyncOrgKeysAsync(organizationUser.UserId.Value);
}
result.Add(Tuple.Create(organizationUser, ""));
}

View File

@ -108,6 +108,7 @@ public static class FeatureFlagKeys
public const string IntegrationPage = "pm-14505-admin-console-integration-page";
public const string DeviceApprovalRequestAdminNotifications = "pm-15637-device-approval-request-admin-notifications";
public const string LimitItemDeletion = "pm-15493-restrict-item-deletion-to-can-manage-permission";
public const string PushSyncOrgKeysOnRevokeRestore = "pm-17168-push-sync-org-keys-on-revoke-restore";
/* Tools Team */
public const string ItemShare = "item-share";

View File

@ -19,6 +19,7 @@ using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Models.Mail;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.Platform.Push;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
@ -1450,76 +1451,174 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
[OrganizationUser] OrganizationUser organizationUser, SutProvider<OrganizationService> sutProvider)
{
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
await sutProvider.Sut.RevokeUserAsync(organizationUser, owner.Id);
await organizationUserRepository.Received().RevokeAsync(organizationUser.Id);
await eventService.Received()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RevokeAsync(organizationUser.Id);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked);
}
[Theory, BitAutoData]
public async Task RevokeUser_WithPushSyncOrgKeysOnRevokeRestoreEnabled_Success(Organization organization, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
[OrganizationUser] OrganizationUser organizationUser, SutProvider<OrganizationService> sutProvider)
{
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore)
.Returns(true);
await sutProvider.Sut.RevokeUserAsync(organizationUser, owner.Id);
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RevokeAsync(organizationUser.Id);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked);
await sutProvider.GetDependency<IPushNotificationService>()
.Received(1)
.PushSyncOrgKeysAsync(organizationUser.UserId!.Value);
}
[Theory, BitAutoData]
public async Task RevokeUser_WithEventSystemUser_Success(Organization organization, [OrganizationUser] OrganizationUser organizationUser, EventSystemUser eventSystemUser, SutProvider<OrganizationService> sutProvider)
{
RestoreRevokeUser_Setup(organization, null, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
await sutProvider.Sut.RevokeUserAsync(organizationUser, eventSystemUser);
await organizationUserRepository.Received().RevokeAsync(organizationUser.Id);
await eventService.Received()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RevokeAsync(organizationUser.Id);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked, eventSystemUser);
}
[Theory, BitAutoData]
public async Task RevokeUser_WithEventSystemUser_WithPushSyncOrgKeysOnRevokeRestoreEnabled_Success(Organization organization, [OrganizationUser] OrganizationUser organizationUser, EventSystemUser eventSystemUser, SutProvider<OrganizationService> sutProvider)
{
RestoreRevokeUser_Setup(organization, null, organizationUser, sutProvider);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore)
.Returns(true);
await sutProvider.Sut.RevokeUserAsync(organizationUser, eventSystemUser);
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RevokeAsync(organizationUser.Id);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Revoked, eventSystemUser);
await sutProvider.GetDependency<IPushNotificationService>()
.Received(1)
.PushSyncOrgKeysAsync(organizationUser.UserId!.Value);
}
[Theory, BitAutoData]
public async Task RestoreUser_Success(Organization organization, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser, SutProvider<OrganizationService> sutProvider)
{
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
await organizationUserRepository.Received().RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Invited);
await eventService.Received()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Invited);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
}
[Theory, BitAutoData]
public async Task RestoreUser_WithPushSyncOrgKeysOnRevokeRestoreEnabled_Success(Organization organization, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser, SutProvider<OrganizationService> sutProvider)
{
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore)
.Returns(true);
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Invited);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
await sutProvider.GetDependency<IPushNotificationService>()
.Received(1)
.PushSyncOrgKeysAsync(organizationUser.UserId!.Value);
}
[Theory, BitAutoData]
public async Task RestoreUser_WithEventSystemUser_Success(Organization organization, [OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser, EventSystemUser eventSystemUser, SutProvider<OrganizationService> sutProvider)
{
RestoreRevokeUser_Setup(organization, null, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
await sutProvider.Sut.RestoreUserAsync(organizationUser, eventSystemUser);
await organizationUserRepository.Received().RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Invited);
await eventService.Received()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Invited);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored, eventSystemUser);
}
[Theory, BitAutoData]
public async Task RestoreUser_WithEventSystemUser_WithPushSyncOrgKeysOnRevokeRestoreEnabled_Success(Organization organization, [OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser, EventSystemUser eventSystemUser, SutProvider<OrganizationService> sutProvider)
{
RestoreRevokeUser_Setup(organization, null, organizationUser, sutProvider);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PushSyncOrgKeysOnRevokeRestore)
.Returns(true);
await sutProvider.Sut.RestoreUserAsync(organizationUser, eventSystemUser);
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Invited);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored, eventSystemUser);
await sutProvider.GetDependency<IPushNotificationService>()
.Received(1)
.PushSyncOrgKeysAsync(organizationUser.UserId!.Value);
}
[Theory, BitAutoData]
public async Task RestoreUser_RestoreThemselves_Fails(Organization organization, [OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
[OrganizationUser(OrganizationUserStatusType.Revoked)] OrganizationUser organizationUser, SutProvider<OrganizationService> sutProvider)
{
organizationUser.UserId = owner.Id;
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
Assert.Contains("you cannot restore yourself", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory]
@ -1531,17 +1630,21 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
{
restoringUser.Type = restoringUserType;
RestoreRevokeUser_Setup(organization, restoringUser, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.RestoreUserAsync(organizationUser, restoringUser.Id));
Assert.Contains("only owners can restore other owners", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory]
@ -1553,17 +1656,21 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
{
organizationUser.Status = userStatus;
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id));
Assert.Contains("already active", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory, BitAutoData]
@ -1575,8 +1682,6 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
{
organizationUser.Email = null; // this is required to mock that the user as had already been confirmed before the revoke
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
sutProvider.GetDependency<IPolicyService>()
.AnyPoliciesApplicableToUserAsync(organizationUser.UserId.Value, PolicyType.SingleOrg, Arg.Any<OrganizationUserStatusType>())
@ -1591,9 +1696,15 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
Assert.Contains("test@bitwarden.com belongs to an organization that doesn't allow them to join multiple organizations", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory, BitAutoData]
@ -1610,8 +1721,6 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>() { (organizationUser.UserId.Value, false) });
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
sutProvider.GetDependency<IPolicyService>()
.GetPoliciesApplicableToUserAsync(organizationUser.UserId.Value, PolicyType.TwoFactorAuthentication, Arg.Any<OrganizationUserStatusType>())
@ -1626,9 +1735,15 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
Assert.Contains("test@bitwarden.com is not compliant with the two-step login policy", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory, BitAutoData]
@ -1640,8 +1755,6 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
{
organizationUser.Email = null; // this is required to mock that the user as had already been confirmed before the revoke
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
sutProvider.GetDependency<IPolicyService>()
.GetPoliciesApplicableToUserAsync(organizationUser.UserId.Value, PolicyType.TwoFactorAuthentication, Arg.Any<OrganizationUserStatusType>())
@ -1652,8 +1765,11 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
await organizationUserRepository.Received().RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Confirmed);
await eventService.Received()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Confirmed);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
}
@ -1668,10 +1784,10 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
organizationUser.Email = null; // this is required to mock that the user as had already been confirmed before the revoke
secondOrganizationUser.UserId = organizationUser.UserId;
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
organizationUserRepository.GetManyByUserAsync(organizationUser.UserId.Value).Returns(new[] { organizationUser, secondOrganizationUser });
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(organizationUser.UserId.Value)
.Returns(new[] { organizationUser, secondOrganizationUser });
sutProvider.GetDependency<IPolicyService>()
.GetPoliciesApplicableToUserAsync(organizationUser.UserId.Value, PolicyType.SingleOrg, Arg.Any<OrganizationUserStatusType>())
.Returns(new[]
@ -1688,9 +1804,15 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
Assert.Contains("test@bitwarden.com is not compliant with the single organization policy", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory, BitAutoData]
@ -1704,11 +1826,8 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
organizationUser.Email = null; // this is required to mock that the user as had already been confirmed before the revoke
secondOrganizationUser.UserId = organizationUser.UserId;
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
var twoFactorIsEnabledQuery = sutProvider.GetDependency<ITwoFactorIsEnabledQuery>();
twoFactorIsEnabledQuery
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(organizationUser.UserId.Value)))
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>() { (organizationUser.UserId.Value, true) });
@ -1725,9 +1844,15 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
Assert.Contains("test@bitwarden.com belongs to an organization that doesn't allow them to join multiple organizations", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory, BitAutoData]
@ -1741,10 +1866,10 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
organizationUser.Email = null; // this is required to mock that the user as had already been confirmed before the revoke
secondOrganizationUser.UserId = organizationUser.UserId;
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
organizationUserRepository.GetManyByUserAsync(organizationUser.UserId.Value).Returns(new[] { organizationUser, secondOrganizationUser });
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetManyByUserAsync(organizationUser.UserId.Value)
.Returns(new[] { organizationUser, secondOrganizationUser });
sutProvider.GetDependency<IPolicyService>()
.GetPoliciesApplicableToUserAsync(organizationUser.UserId.Value, PolicyType.SingleOrg, Arg.Any<OrganizationUserStatusType>())
.Returns(new[]
@ -1768,9 +1893,15 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
Assert.Contains("test@bitwarden.com is not compliant with the single organization and two-step login polciy", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory, BitAutoData]
@ -1783,8 +1914,6 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
organizationUser.Email = null;
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
sutProvider.GetDependency<IPolicyService>()
.GetPoliciesApplicableToUserAsync(organizationUser.UserId.Value, PolicyType.TwoFactorAuthentication, Arg.Any<OrganizationUserStatusType>())
@ -1799,9 +1928,15 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
Assert.Contains("test@bitwarden.com is not compliant with the two-step login policy", exception.Message.ToLowerInvariant());
await organizationUserRepository.DidNotReceiveWithAnyArgs().RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await eventService.DidNotReceiveWithAnyArgs()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.DidNotReceiveWithAnyArgs()
.RestoreAsync(Arg.Any<Guid>(), Arg.Any<OrganizationUserStatusType>());
await sutProvider.GetDependency<IEventService>()
.DidNotReceiveWithAnyArgs()
.LogOrganizationUserEventAsync(Arg.Any<OrganizationUser>(), Arg.Any<EventType>(), Arg.Any<EventSystemUser>());
await sutProvider.GetDependency<IPushNotificationService>()
.DidNotReceiveWithAnyArgs()
.PushSyncOrgKeysAsync(Arg.Any<Guid>());
}
[Theory, BitAutoData]
@ -1813,22 +1948,22 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
{
organizationUser.Email = null; // this is required to mock that the user as had already been confirmed before the revoke
RestoreRevokeUser_Setup(organization, owner, organizationUser, sutProvider);
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
var twoFactorIsEnabledQuery = sutProvider.GetDependency<ITwoFactorIsEnabledQuery>();
sutProvider.GetDependency<IPolicyService>()
.GetPoliciesApplicableToUserAsync(organizationUser.UserId.Value, PolicyType.TwoFactorAuthentication, Arg.Any<OrganizationUserStatusType>())
.Returns(new[] { new OrganizationUserPolicyDetails { OrganizationId = organizationUser.OrganizationId, PolicyType = PolicyType.TwoFactorAuthentication } });
twoFactorIsEnabledQuery
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(i => i.Contains(organizationUser.UserId.Value)))
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>() { (organizationUser.UserId.Value, true) });
await sutProvider.Sut.RestoreUserAsync(organizationUser, owner.Id);
await organizationUserRepository.Received().RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Confirmed);
await eventService.Received()
await sutProvider.GetDependency<IOrganizationUserRepository>()
.Received(1)
.RestoreAsync(organizationUser.Id, OrganizationUserStatusType.Confirmed);
await sutProvider.GetDependency<IEventService>()
.Received(1)
.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Restored);
}