mirror of
https://github.com/bitwarden/server.git
synced 2025-04-28 08:12:22 -05:00
Finish feature flag removal
This commit is contained in:
parent
4ffeab7921
commit
44ed044c39
@ -23,8 +23,6 @@ public class TwoFactorAuthenticationPolicyValidator : IPolicyValidator
|
|||||||
private readonly IOrganizationRepository _organizationRepository;
|
private readonly IOrganizationRepository _organizationRepository;
|
||||||
private readonly ICurrentContext _currentContext;
|
private readonly ICurrentContext _currentContext;
|
||||||
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
|
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
|
||||||
private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand;
|
|
||||||
private readonly IFeatureService _featureService;
|
|
||||||
private readonly IRevokeNonCompliantOrganizationUserCommand _revokeNonCompliantOrganizationUserCommand;
|
private readonly IRevokeNonCompliantOrganizationUserCommand _revokeNonCompliantOrganizationUserCommand;
|
||||||
|
|
||||||
public const string NonCompliantMembersWillLoseAccessMessage = "Policy could not be enabled. Non-compliant members will lose access to their accounts. Identify members without two-step login from the policies column in the members page.";
|
public const string NonCompliantMembersWillLoseAccessMessage = "Policy could not be enabled. Non-compliant members will lose access to their accounts. Identify members without two-step login from the policies column in the members page.";
|
||||||
@ -38,8 +36,6 @@ public class TwoFactorAuthenticationPolicyValidator : IPolicyValidator
|
|||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
ICurrentContext currentContext,
|
ICurrentContext currentContext,
|
||||||
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
|
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
|
||||||
IRemoveOrganizationUserCommand removeOrganizationUserCommand,
|
|
||||||
IFeatureService featureService,
|
|
||||||
IRevokeNonCompliantOrganizationUserCommand revokeNonCompliantOrganizationUserCommand)
|
IRevokeNonCompliantOrganizationUserCommand revokeNonCompliantOrganizationUserCommand)
|
||||||
{
|
{
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
@ -47,8 +43,6 @@ public class TwoFactorAuthenticationPolicyValidator : IPolicyValidator
|
|||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
_currentContext = currentContext;
|
_currentContext = currentContext;
|
||||||
_twoFactorIsEnabledQuery = twoFactorIsEnabledQuery;
|
_twoFactorIsEnabledQuery = twoFactorIsEnabledQuery;
|
||||||
_removeOrganizationUserCommand = removeOrganizationUserCommand;
|
|
||||||
_featureService = featureService;
|
|
||||||
_revokeNonCompliantOrganizationUserCommand = revokeNonCompliantOrganizationUserCommand;
|
_revokeNonCompliantOrganizationUserCommand = revokeNonCompliantOrganizationUserCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,40 +108,6 @@ public class TwoFactorAuthenticationPolicyValidator : IPolicyValidator
|
|||||||
_mailService.SendOrganizationUserRevokedForTwoFactorPolicyEmailAsync(organization.DisplayName(), x.Email)));
|
_mailService.SendOrganizationUserRevokedForTwoFactorPolicyEmailAsync(organization.DisplayName(), x.Email)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RemoveNonCompliantUsersAsync(Guid organizationId)
|
|
||||||
{
|
|
||||||
var org = await _organizationRepository.GetByIdAsync(organizationId);
|
|
||||||
var savingUserId = _currentContext.UserId;
|
|
||||||
|
|
||||||
var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId);
|
|
||||||
var organizationUsersTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(orgUsers);
|
|
||||||
var removableOrgUsers = orgUsers.Where(ou =>
|
|
||||||
ou.Status != OrganizationUserStatusType.Invited && ou.Status != OrganizationUserStatusType.Revoked &&
|
|
||||||
ou.Type != OrganizationUserType.Owner && ou.Type != OrganizationUserType.Admin &&
|
|
||||||
ou.UserId != savingUserId);
|
|
||||||
|
|
||||||
// Reorder by HasMasterPassword to prioritize checking users without a master if they have 2FA enabled
|
|
||||||
foreach (var orgUser in removableOrgUsers.OrderBy(ou => ou.HasMasterPassword))
|
|
||||||
{
|
|
||||||
var userTwoFactorEnabled = organizationUsersTwoFactorEnabled.FirstOrDefault(u => u.user.Id == orgUser.Id)
|
|
||||||
.twoFactorIsEnabled;
|
|
||||||
if (!userTwoFactorEnabled)
|
|
||||||
{
|
|
||||||
if (!orgUser.HasMasterPassword)
|
|
||||||
{
|
|
||||||
throw new BadRequestException(
|
|
||||||
"Policy could not be enabled. Non-compliant members will lose access to their accounts. Identify members without two-step login from the policies column in the members page.");
|
|
||||||
}
|
|
||||||
|
|
||||||
await _removeOrganizationUserCommand.RemoveUserAsync(organizationId, orgUser.Id,
|
|
||||||
savingUserId);
|
|
||||||
|
|
||||||
await _mailService.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(
|
|
||||||
org!.DisplayName(), orgUser.Email);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool MembersWithNoMasterPasswordWillLoseAccess(
|
private static bool MembersWithNoMasterPasswordWillLoseAccess(
|
||||||
IEnumerable<OrganizationUserUserDetails> orgUserDetails,
|
IEnumerable<OrganizationUserUserDetails> orgUserDetails,
|
||||||
IEnumerable<(OrganizationUserUserDetails user, bool isTwoFactorEnabled)> organizationUsersTwoFactorEnabled) =>
|
IEnumerable<(OrganizationUserUserDetails user, bool isTwoFactorEnabled)> organizationUsersTwoFactorEnabled) =>
|
||||||
|
@ -191,32 +191,6 @@ public class VerifyOrganizationDomainCommandTests
|
|||||||
x.PerformedBy.UserId == userId));
|
x.PerformedBy.UserId == userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task UserVerifyOrganizationDomainAsync_GivenOrganizationDomainWithAccountDeprovisioningDisabled_WhenDomainIsVerified_ThenSingleOrgPolicyShouldBeNotBeEnabled(
|
|
||||||
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
|
||||||
{
|
|
||||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
|
||||||
.GetClaimedDomainsByDomainNameAsync(domain.DomainName)
|
|
||||||
.Returns([]);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IDnsResolverService>()
|
|
||||||
.ResolveAsync(domain.DomainName, domain.Txt)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>()
|
|
||||||
.UserId.Returns(Guid.NewGuid());
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(false);
|
|
||||||
|
|
||||||
_ = await sutProvider.Sut.UserVerifyOrganizationDomainAsync(domain);
|
|
||||||
|
|
||||||
await sutProvider.GetDependency<ISavePolicyCommand>()
|
|
||||||
.DidNotReceive()
|
|
||||||
.SaveAsync(Arg.Any<PolicyUpdate>());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task UserVerifyOrganizationDomainAsync_WhenDomainIsNotVerified_ThenSingleOrgPolicyShouldNotBeEnabled(
|
public async Task UserVerifyOrganizationDomainAsync_WhenDomainIsNotVerified_ThenSingleOrgPolicyShouldNotBeEnabled(
|
||||||
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||||
|
@ -122,9 +122,6 @@ public class SingleOrgPolicyValidatorTests
|
|||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(savingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(savingUserId);
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(policyUpdate.OrganizationId).Returns(organization);
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(policyUpdate.OrganizationId).Returns(organization);
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IRevokeNonCompliantOrganizationUserCommand>()
|
sutProvider.GetDependency<IRevokeNonCompliantOrganizationUserCommand>()
|
||||||
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
|
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
|
||||||
.Returns(new CommandResult());
|
.Returns(new CommandResult());
|
||||||
@ -148,161 +145,4 @@ public class SingleOrgPolicyValidatorTests
|
|||||||
.Received(1)
|
.Received(1)
|
||||||
.SendOrganizationUserRevokedForPolicySingleOrgEmailAsync(organization.DisplayName(), nonCompliantUser.Email);
|
.SendOrganizationUserRevokedForPolicySingleOrgEmailAsync(organization.DisplayName(), nonCompliantUser.Email);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_RemovesNonCompliantUsers(
|
|
||||||
[PolicyUpdate(PolicyType.SingleOrg)] PolicyUpdate policyUpdate,
|
|
||||||
[Policy(PolicyType.SingleOrg, false)] Policy policy,
|
|
||||||
Guid savingUserId,
|
|
||||||
Guid nonCompliantUserId,
|
|
||||||
Organization organization, SutProvider<SingleOrgPolicyValidator> sutProvider)
|
|
||||||
{
|
|
||||||
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var compliantUser1 = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
OrganizationId = organization.Id,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
UserId = new Guid(),
|
|
||||||
Email = "user1@example.com"
|
|
||||||
};
|
|
||||||
|
|
||||||
var compliantUser2 = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
OrganizationId = organization.Id,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
UserId = new Guid(),
|
|
||||||
Email = "user2@example.com"
|
|
||||||
};
|
|
||||||
|
|
||||||
var nonCompliantUser = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
OrganizationId = organization.Id,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
UserId = nonCompliantUserId,
|
|
||||||
Email = "user3@example.com"
|
|
||||||
};
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns([compliantUser1, compliantUser2, nonCompliantUser]);
|
|
||||||
|
|
||||||
var otherOrganizationUser = new OrganizationUser
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
OrganizationId = new Guid(),
|
|
||||||
UserId = nonCompliantUserId,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed
|
|
||||||
};
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetManyByManyUsersAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(nonCompliantUserId)))
|
|
||||||
.Returns([otherOrganizationUser]);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(savingUserId);
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(policyUpdate.OrganizationId).Returns(organization);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(false);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IRevokeNonCompliantOrganizationUserCommand>()
|
|
||||||
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
|
|
||||||
.Returns(new CommandResult());
|
|
||||||
|
|
||||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, policy);
|
|
||||||
|
|
||||||
await sutProvider.GetDependency<IRemoveOrganizationUserCommand>()
|
|
||||||
.DidNotReceive()
|
|
||||||
.RemoveUserAsync(policyUpdate.OrganizationId, compliantUser1.Id, savingUserId);
|
|
||||||
await sutProvider.GetDependency<IRemoveOrganizationUserCommand>()
|
|
||||||
.DidNotReceive()
|
|
||||||
.RemoveUserAsync(policyUpdate.OrganizationId, compliantUser2.Id, savingUserId);
|
|
||||||
await sutProvider.GetDependency<IRemoveOrganizationUserCommand>()
|
|
||||||
.Received(1)
|
|
||||||
.RemoveUserAsync(policyUpdate.OrganizationId, nonCompliantUser.Id, savingUserId);
|
|
||||||
await sutProvider.GetDependency<IMailService>()
|
|
||||||
.DidNotReceive()
|
|
||||||
.SendOrganizationUserRemovedForPolicySingleOrgEmailAsync(organization.DisplayName(), compliantUser1.Email);
|
|
||||||
await sutProvider.GetDependency<IMailService>()
|
|
||||||
.DidNotReceive()
|
|
||||||
.SendOrganizationUserRemovedForPolicySingleOrgEmailAsync(organization.DisplayName(), compliantUser2.Email);
|
|
||||||
await sutProvider.GetDependency<IMailService>()
|
|
||||||
.Received(1)
|
|
||||||
.SendOrganizationUserRemovedForPolicySingleOrgEmailAsync(organization.DisplayName(), nonCompliantUser.Email);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_WhenAccountDeprovisioningIsEnabled_ThenUsersAreRevoked(
|
|
||||||
[PolicyUpdate(PolicyType.SingleOrg)] PolicyUpdate policyUpdate,
|
|
||||||
[Policy(PolicyType.SingleOrg, false)] Policy policy,
|
|
||||||
Guid savingUserId,
|
|
||||||
Guid nonCompliantUserId,
|
|
||||||
Organization organization, SutProvider<SingleOrgPolicyValidator> sutProvider)
|
|
||||||
{
|
|
||||||
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var compliantUser1 = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
OrganizationId = organization.Id,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
UserId = new Guid(),
|
|
||||||
Email = "user1@example.com"
|
|
||||||
};
|
|
||||||
|
|
||||||
var compliantUser2 = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
OrganizationId = organization.Id,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
UserId = new Guid(),
|
|
||||||
Email = "user2@example.com"
|
|
||||||
};
|
|
||||||
|
|
||||||
var nonCompliantUser = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
OrganizationId = organization.Id,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
UserId = nonCompliantUserId,
|
|
||||||
Email = "user3@example.com"
|
|
||||||
};
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns([compliantUser1, compliantUser2, nonCompliantUser]);
|
|
||||||
|
|
||||||
var otherOrganizationUser = new OrganizationUser
|
|
||||||
{
|
|
||||||
OrganizationId = new Guid(),
|
|
||||||
UserId = nonCompliantUserId,
|
|
||||||
Status = OrganizationUserStatusType.Confirmed
|
|
||||||
};
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetManyByManyUsersAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(nonCompliantUserId)))
|
|
||||||
.Returns([otherOrganizationUser]);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(savingUserId);
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns(organization);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IRevokeNonCompliantOrganizationUserCommand>()
|
|
||||||
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
|
|
||||||
.Returns(new CommandResult());
|
|
||||||
|
|
||||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, policy);
|
|
||||||
|
|
||||||
await sutProvider.GetDependency<IRevokeNonCompliantOrganizationUserCommand>()
|
|
||||||
.Received()
|
|
||||||
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Requests;
|
|||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
|
||||||
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||||
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
|
||||||
using Bit.Core.Context;
|
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Exceptions;
|
using Bit.Core.Exceptions;
|
||||||
using Bit.Core.Models.Commands;
|
using Bit.Core.Models.Commands;
|
||||||
@ -24,7 +23,7 @@ namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyValidat
|
|||||||
public class TwoFactorAuthenticationPolicyValidatorTests
|
public class TwoFactorAuthenticationPolicyValidatorTests
|
||||||
{
|
{
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task OnSaveSideEffectsAsync_RemovesNonCompliantUsers(
|
public async Task OnSaveSideEffectsAsync_GivenNonCompliantUsersWithoutMasterPassword_Throws(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
[PolicyUpdate(PolicyType.TwoFactorAuthentication)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.TwoFactorAuthentication)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.TwoFactorAuthentication, false)] Policy policy,
|
[Policy(PolicyType.TwoFactorAuthentication, false)] Policy policy,
|
||||||
@ -33,249 +32,6 @@ public class TwoFactorAuthenticationPolicyValidatorTests
|
|||||||
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
|
||||||
var orgUserDetailUserInvited = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Invited,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
|
||||||
Email = "user1@test.com",
|
|
||||||
Name = "TEST",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = false
|
|
||||||
};
|
|
||||||
var orgUserDetailUserAcceptedWith2FA = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Accepted,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
|
||||||
Email = "user2@test.com",
|
|
||||||
Name = "TEST",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = true
|
|
||||||
};
|
|
||||||
var orgUserDetailUserAcceptedWithout2FA = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Accepted,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
|
||||||
Email = "user3@test.com",
|
|
||||||
Name = "TEST",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = true
|
|
||||||
};
|
|
||||||
var orgUserDetailAdmin = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
Type = OrganizationUserType.Admin,
|
|
||||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
|
||||||
Email = "admin@test.com",
|
|
||||||
Name = "ADMIN",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = false
|
|
||||||
};
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns(new List<OrganizationUserUserDetails>
|
|
||||||
{
|
|
||||||
orgUserDetailUserInvited,
|
|
||||||
orgUserDetailUserAcceptedWith2FA,
|
|
||||||
orgUserDetailUserAcceptedWithout2FA,
|
|
||||||
orgUserDetailAdmin
|
|
||||||
});
|
|
||||||
|
|
||||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
|
||||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<OrganizationUserUserDetails>>())
|
|
||||||
.Returns(new List<(OrganizationUserUserDetails user, bool hasTwoFactor)>()
|
|
||||||
{
|
|
||||||
(orgUserDetailUserInvited, false),
|
|
||||||
(orgUserDetailUserAcceptedWith2FA, true),
|
|
||||||
(orgUserDetailUserAcceptedWithout2FA, false),
|
|
||||||
(orgUserDetailAdmin, false),
|
|
||||||
});
|
|
||||||
|
|
||||||
var savingUserId = Guid.NewGuid();
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(savingUserId);
|
|
||||||
|
|
||||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, policy);
|
|
||||||
|
|
||||||
var removeOrganizationUserCommand = sutProvider.GetDependency<IRemoveOrganizationUserCommand>();
|
|
||||||
|
|
||||||
await removeOrganizationUserCommand.Received()
|
|
||||||
.RemoveUserAsync(policy.OrganizationId, orgUserDetailUserAcceptedWithout2FA.Id, savingUserId);
|
|
||||||
await sutProvider.GetDependency<IMailService>().Received()
|
|
||||||
.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(organization.DisplayName(), orgUserDetailUserAcceptedWithout2FA.Email);
|
|
||||||
|
|
||||||
await removeOrganizationUserCommand.DidNotReceive()
|
|
||||||
.RemoveUserAsync(policy.OrganizationId, orgUserDetailUserInvited.Id, savingUserId);
|
|
||||||
await sutProvider.GetDependency<IMailService>().DidNotReceive()
|
|
||||||
.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(organization.DisplayName(), orgUserDetailUserInvited.Email);
|
|
||||||
await removeOrganizationUserCommand.DidNotReceive()
|
|
||||||
.RemoveUserAsync(policy.OrganizationId, orgUserDetailUserAcceptedWith2FA.Id, savingUserId);
|
|
||||||
await sutProvider.GetDependency<IMailService>().DidNotReceive()
|
|
||||||
.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(organization.DisplayName(), orgUserDetailUserAcceptedWith2FA.Email);
|
|
||||||
await removeOrganizationUserCommand.DidNotReceive()
|
|
||||||
.RemoveUserAsync(policy.OrganizationId, orgUserDetailAdmin.Id, savingUserId);
|
|
||||||
await sutProvider.GetDependency<IMailService>().DidNotReceive()
|
|
||||||
.SendOrganizationUserRemovedForPolicyTwoStepEmailAsync(organization.DisplayName(), orgUserDetailAdmin.Email);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_UsersToBeRemovedDontHaveMasterPasswords_Throws(
|
|
||||||
Organization organization,
|
|
||||||
[PolicyUpdate(PolicyType.TwoFactorAuthentication)] PolicyUpdate policyUpdate,
|
|
||||||
[Policy(PolicyType.TwoFactorAuthentication, false)] Policy policy,
|
|
||||||
SutProvider<TwoFactorAuthenticationPolicyValidator> sutProvider)
|
|
||||||
{
|
|
||||||
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
|
||||||
|
|
||||||
var orgUserDetailUserWith2FAAndMP = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
|
||||||
Email = "user1@test.com",
|
|
||||||
Name = "TEST",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = true
|
|
||||||
};
|
|
||||||
var orgUserDetailUserWith2FANoMP = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
|
||||||
Email = "user2@test.com",
|
|
||||||
Name = "TEST",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = false
|
|
||||||
};
|
|
||||||
var orgUserDetailUserWithout2FA = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
|
||||||
Email = "user3@test.com",
|
|
||||||
Name = "TEST",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = false
|
|
||||||
};
|
|
||||||
var orgUserDetailAdmin = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Confirmed,
|
|
||||||
Type = OrganizationUserType.Admin,
|
|
||||||
// Needs to be different from what is passed in as the savingUserId to Sut.SaveAsync
|
|
||||||
Email = "admin@test.com",
|
|
||||||
Name = "ADMIN",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = false
|
|
||||||
};
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(false);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetManyDetailsByOrganizationAsync(policy.OrganizationId)
|
|
||||||
.Returns(new List<OrganizationUserUserDetails>
|
|
||||||
{
|
|
||||||
orgUserDetailUserWith2FAAndMP,
|
|
||||||
orgUserDetailUserWith2FANoMP,
|
|
||||||
orgUserDetailUserWithout2FA,
|
|
||||||
orgUserDetailAdmin
|
|
||||||
});
|
|
||||||
|
|
||||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
|
||||||
.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(ids =>
|
|
||||||
ids.Contains(orgUserDetailUserWith2FANoMP.UserId.Value)
|
|
||||||
&& ids.Contains(orgUserDetailUserWithout2FA.UserId.Value)
|
|
||||||
&& ids.Contains(orgUserDetailAdmin.UserId.Value)))
|
|
||||||
.Returns(new List<(Guid userId, bool hasTwoFactor)>()
|
|
||||||
{
|
|
||||||
(orgUserDetailUserWith2FANoMP.UserId.Value, true),
|
|
||||||
(orgUserDetailUserWithout2FA.UserId.Value, false),
|
|
||||||
(orgUserDetailAdmin.UserId.Value, false),
|
|
||||||
});
|
|
||||||
|
|
||||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
|
||||||
() => sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, policy));
|
|
||||||
|
|
||||||
Assert.Equal(TwoFactorAuthenticationPolicyValidator.NonCompliantMembersWillLoseAccessMessage, badRequestException.Message);
|
|
||||||
|
|
||||||
await sutProvider.GetDependency<IRemoveOrganizationUserCommand>().DidNotReceiveWithAnyArgs()
|
|
||||||
.RemoveUserAsync(organizationId: default, organizationUserId: default, deletingUserId: default);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_GivenUpdateTo2faPolicy_WhenAccountProvisioningIsDisabled_ThenRevokeUserCommandShouldNotBeCalled(
|
|
||||||
Organization organization,
|
|
||||||
[PolicyUpdate(PolicyType.TwoFactorAuthentication)]
|
|
||||||
PolicyUpdate policyUpdate,
|
|
||||||
[Policy(PolicyType.TwoFactorAuthentication, false)]
|
|
||||||
Policy policy,
|
|
||||||
SutProvider<TwoFactorAuthenticationPolicyValidator> sutProvider)
|
|
||||||
{
|
|
||||||
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(false);
|
|
||||||
|
|
||||||
var orgUserDetailUserAcceptedWithout2Fa = new OrganizationUserUserDetails
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
Status = OrganizationUserStatusType.Accepted,
|
|
||||||
Type = OrganizationUserType.User,
|
|
||||||
Email = "user3@test.com",
|
|
||||||
Name = "TEST",
|
|
||||||
UserId = Guid.NewGuid(),
|
|
||||||
HasMasterPassword = true
|
|
||||||
};
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetManyDetailsByOrganizationAsync(policyUpdate.OrganizationId)
|
|
||||||
.Returns(new List<OrganizationUserUserDetails>
|
|
||||||
{
|
|
||||||
orgUserDetailUserAcceptedWithout2Fa
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
|
||||||
.TwoFactorIsEnabledAsync(Arg.Any<IEnumerable<OrganizationUserUserDetails>>())
|
|
||||||
.Returns(new List<(OrganizationUserUserDetails user, bool hasTwoFactor)>()
|
|
||||||
{
|
|
||||||
(orgUserDetailUserAcceptedWithout2Fa, false),
|
|
||||||
});
|
|
||||||
|
|
||||||
await sutProvider.Sut.OnSaveSideEffectsAsync(policyUpdate, policy);
|
|
||||||
|
|
||||||
await sutProvider.GetDependency<IRevokeNonCompliantOrganizationUserCommand>()
|
|
||||||
.DidNotReceive()
|
|
||||||
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task OnSaveSideEffectsAsync_GivenUpdateTo2faPolicy_WhenAccountProvisioningIsEnabledAndUserDoesNotHaveMasterPassword_ThenNonCompliantMembersErrorMessageWillReturn(
|
|
||||||
Organization organization,
|
|
||||||
[PolicyUpdate(PolicyType.TwoFactorAuthentication)] PolicyUpdate policyUpdate,
|
|
||||||
[Policy(PolicyType.TwoFactorAuthentication, false)] Policy policy,
|
|
||||||
SutProvider<TwoFactorAuthenticationPolicyValidator> sutProvider)
|
|
||||||
{
|
|
||||||
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
var orgUserDetailUserWithout2Fa = new OrganizationUserUserDetails
|
var orgUserDetailUserWithout2Fa = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
@ -304,7 +60,7 @@ public class TwoFactorAuthenticationPolicyValidatorTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task OnSaveSideEffectsAsync_WhenAccountProvisioningIsEnabledAndUserHasMasterPassword_ThenUserWillBeRevoked(
|
public async Task OnSaveSideEffectsAsync_RevokesNonCompliantUsers(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
[PolicyUpdate(PolicyType.TwoFactorAuthentication)] PolicyUpdate policyUpdate,
|
[PolicyUpdate(PolicyType.TwoFactorAuthentication)] PolicyUpdate policyUpdate,
|
||||||
[Policy(PolicyType.TwoFactorAuthentication, false)] Policy policy,
|
[Policy(PolicyType.TwoFactorAuthentication, false)] Policy policy,
|
||||||
@ -313,10 +69,6 @@ public class TwoFactorAuthenticationPolicyValidatorTests
|
|||||||
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
policy.OrganizationId = organization.Id = policyUpdate.OrganizationId;
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
var orgUserDetailUserWithout2Fa = new OrganizationUserUserDetails
|
var orgUserDetailUserWithout2Fa = new OrganizationUserUserDetails
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
|
@ -341,28 +341,12 @@ public class UserServiceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task IsClaimedByAnyOrganizationAsync_WithAccountDeprovisioningDisabled_ReturnsFalse(
|
public async Task IsClaimedByAnyOrganizationAsync_WithManagingEnabledOrganization_ReturnsTrue(
|
||||||
SutProvider<UserService> sutProvider, Guid userId)
|
|
||||||
{
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(false);
|
|
||||||
|
|
||||||
var result = await sutProvider.Sut.IsClaimedByAnyOrganizationAsync(userId);
|
|
||||||
Assert.False(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task IsClaimedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithManagingEnabledOrganization_ReturnsTrue(
|
|
||||||
SutProvider<UserService> sutProvider, Guid userId, Organization organization)
|
SutProvider<UserService> sutProvider, Guid userId, Organization organization)
|
||||||
{
|
{
|
||||||
organization.Enabled = true;
|
organization.Enabled = true;
|
||||||
organization.UseSso = true;
|
organization.UseSso = true;
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
sutProvider.GetDependency<IOrganizationRepository>()
|
||||||
.GetByVerifiedUserEmailDomainAsync(userId)
|
.GetByVerifiedUserEmailDomainAsync(userId)
|
||||||
.Returns(new[] { organization });
|
.Returns(new[] { organization });
|
||||||
@ -372,16 +356,12 @@ public class UserServiceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task IsClaimedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithManagingDisabledOrganization_ReturnsFalse(
|
public async Task IsClaimedByAnyOrganizationAsync_WithManagingDisabledOrganization_ReturnsFalse(
|
||||||
SutProvider<UserService> sutProvider, Guid userId, Organization organization)
|
SutProvider<UserService> sutProvider, Guid userId, Organization organization)
|
||||||
{
|
{
|
||||||
organization.Enabled = false;
|
organization.Enabled = false;
|
||||||
organization.UseSso = true;
|
organization.UseSso = true;
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
sutProvider.GetDependency<IOrganizationRepository>()
|
||||||
.GetByVerifiedUserEmailDomainAsync(userId)
|
.GetByVerifiedUserEmailDomainAsync(userId)
|
||||||
.Returns(new[] { organization });
|
.Returns(new[] { organization });
|
||||||
@ -391,16 +371,12 @@ public class UserServiceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task IsClaimedByAnyOrganizationAsync_WithAccountDeprovisioningEnabled_WithOrganizationUseSsoFalse_ReturnsFalse(
|
public async Task IsClaimedByAnyOrganizationAsync_WithOrganizationUseSsoFalse_ReturnsFalse(
|
||||||
SutProvider<UserService> sutProvider, Guid userId, Organization organization)
|
SutProvider<UserService> sutProvider, Guid userId, Organization organization)
|
||||||
{
|
{
|
||||||
organization.Enabled = true;
|
organization.Enabled = true;
|
||||||
organization.UseSso = false;
|
organization.UseSso = false;
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
sutProvider.GetDependency<IOrganizationRepository>()
|
||||||
.GetByVerifiedUserEmailDomainAsync(userId)
|
.GetByVerifiedUserEmailDomainAsync(userId)
|
||||||
.Returns(new[] { organization });
|
.Returns(new[] { organization });
|
||||||
@ -500,7 +476,7 @@ public class UserServiceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task DisableTwoFactorProviderAsync_WithAccountDeprovisioningEnabled_WhenOrganizationHas2FAPolicyEnabled_DisablingAllProviders_RevokesUserAndSendsEmail(
|
public async Task DisableTwoFactorProviderAsync_WhenOrganizationHas2FAPolicyEnabled_DisablingAllProviders_RevokesUserAndSendsEmail(
|
||||||
SutProvider<UserService> sutProvider, User user,
|
SutProvider<UserService> sutProvider, User user,
|
||||||
Organization organization1, Guid organizationUserId1,
|
Organization organization1, Guid organizationUserId1,
|
||||||
Organization organization2, Guid organizationUserId2)
|
Organization organization2, Guid organizationUserId2)
|
||||||
@ -513,9 +489,6 @@ public class UserServiceTests
|
|||||||
organization1.Enabled = organization2.Enabled = true;
|
organization1.Enabled = organization2.Enabled = true;
|
||||||
organization1.UseSso = organization2.UseSso = true;
|
organization1.UseSso = organization2.UseSso = true;
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
|
||||||
.Returns(true);
|
|
||||||
sutProvider.GetDependency<IPolicyService>()
|
sutProvider.GetDependency<IPolicyService>()
|
||||||
.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.TwoFactorAuthentication)
|
.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.TwoFactorAuthentication)
|
||||||
.Returns(
|
.Returns(
|
||||||
@ -578,7 +551,7 @@ public class UserServiceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task DisableTwoFactorProviderAsync_WithAccountDeprovisioningEnabled_UserHasOneProviderEnabled_DoesNotRemoveUserFromOrganization(
|
public async Task DisableTwoFactorProviderAsync_UserHasOneProviderEnabled_DoesNotRemoveUserFromOrganization(
|
||||||
SutProvider<UserService> sutProvider, User user, Organization organization)
|
SutProvider<UserService> sutProvider, User user, Organization organization)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
Loading…
x
Reference in New Issue
Block a user