mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 08:32:50 -05:00
Merge branch 'refs/heads/main' into km/pm-10600
This commit is contained in:
@ -3,6 +3,7 @@ using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.Auth.Models.Request.Accounts;
|
||||
using Bit.Api.Vault.AuthorizationHandlers.Collections;
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
@ -15,6 +16,7 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
@ -185,14 +187,46 @@ public class OrganizationUsersControllerTests
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.Invite(organizationAbility.Id, model));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(true)]
|
||||
[BitAutoData(false)]
|
||||
public async Task Get_ReturnsUser(
|
||||
bool accountDeprovisioningEnabled,
|
||||
OrganizationUserUserDetails organizationUser, ICollection<CollectionAccessSelection> collections,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
organizationUser.Permissions = null;
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
||||
.Returns(accountDeprovisioningEnabled);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ManageUsers(organizationUser.OrganizationId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetDetailsByIdWithCollectionsAsync(organizationUser.Id)
|
||||
.Returns((organizationUser, collections));
|
||||
|
||||
sutProvider.GetDependency<IGetOrganizationUsersManagementStatusQuery>()
|
||||
.GetUsersOrganizationManagementStatusAsync(organizationUser.OrganizationId, Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(organizationUser.Id)))
|
||||
.Returns(new Dictionary<Guid, bool> { { organizationUser.Id, true } });
|
||||
|
||||
var response = await sutProvider.Sut.Get(organizationUser.Id, false);
|
||||
|
||||
Assert.Equal(organizationUser.Id, response.Id);
|
||||
Assert.Equal(accountDeprovisioningEnabled, response.ManagedByOrganization);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Get_ReturnsUsers(
|
||||
public async Task GetMany_ReturnsUsers(
|
||||
ICollection<OrganizationUserUserDetails> organizationUsers, OrganizationAbility organizationAbility,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
Get_Setup(organizationAbility, organizationUsers, sutProvider);
|
||||
var response = await sutProvider.Sut.Get(organizationAbility.Id);
|
||||
GetMany_Setup(organizationAbility, organizationUsers, sutProvider);
|
||||
var response = await sutProvider.Sut.Get(organizationAbility.Id, false, false);
|
||||
|
||||
Assert.True(response.Data.All(r => organizationUsers.Any(ou => ou.Id == r.Id)));
|
||||
}
|
||||
@ -368,7 +402,7 @@ public class OrganizationUsersControllerTests
|
||||
await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.BulkDeleteAccount(orgId, model));
|
||||
}
|
||||
|
||||
private void Get_Setup(OrganizationAbility organizationAbility,
|
||||
private void GetMany_Setup(OrganizationAbility organizationAbility,
|
||||
ICollection<OrganizationUserUserDetails> organizationUsers,
|
||||
SutProvider<OrganizationUsersController> sutProvider)
|
||||
{
|
||||
|
@ -2,7 +2,6 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Authorization;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Test.AdminConsole.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
@ -24,7 +23,6 @@ public class OrganizationUserUserDetailsAuthorizationHandlerTests
|
||||
CurrentContextOrganization organization,
|
||||
SutProvider<OrganizationUserUserDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
EnableFeatureFlag(sutProvider);
|
||||
organization.Type = userType;
|
||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||
|
||||
@ -48,7 +46,6 @@ public class OrganizationUserUserDetailsAuthorizationHandlerTests
|
||||
CurrentContextOrganization organization,
|
||||
SutProvider<OrganizationUserUserDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
EnableFeatureFlag(sutProvider);
|
||||
organization.Type = OrganizationUserType.User;
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ProviderUserForOrgAsync(organization.Id)
|
||||
@ -69,7 +66,6 @@ public class OrganizationUserUserDetailsAuthorizationHandlerTests
|
||||
CurrentContextOrganization organization,
|
||||
SutProvider<OrganizationUserUserDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
EnableFeatureFlag(sutProvider);
|
||||
organization.Type = OrganizationUserType.User;
|
||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(Arg.Any<Guid>()).Returns(organization);
|
||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||
@ -88,78 +84,6 @@ public class OrganizationUserUserDetailsAuthorizationHandlerTests
|
||||
public async Task ReadAll_NotMember_NoSuccess(
|
||||
CurrentContextOrganization organization,
|
||||
SutProvider<OrganizationUserUserDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
EnableFeatureFlag(sutProvider);
|
||||
var context = new AuthorizationHandlerContext(
|
||||
new[] { OrganizationUserUserDetailsOperations.ReadAll },
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(organization.Id)
|
||||
);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(Arg.Any<Guid>()).Returns((CurrentContextOrganization)null);
|
||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
Assert.False(context.HasSucceeded);
|
||||
}
|
||||
|
||||
private void EnableFeatureFlag(SutProvider<OrganizationUserUserDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.Pm3478RefactorOrganizationUserApi)
|
||||
.Returns(true);
|
||||
}
|
||||
|
||||
// TESTS WITH FLAG DISABLED - TO BE DELETED IN FLAG CLEANUP
|
||||
|
||||
[Theory, CurrentContextOrganizationCustomize]
|
||||
[BitAutoData(OrganizationUserType.Admin)]
|
||||
[BitAutoData(OrganizationUserType.Owner)]
|
||||
[BitAutoData(OrganizationUserType.User)]
|
||||
[BitAutoData(OrganizationUserType.Custom)]
|
||||
public async Task FlagDisabled_ReadAll_AnyMemberOfOrg_Success(
|
||||
OrganizationUserType userType,
|
||||
Guid userId, SutProvider<OrganizationUserUserDetailsAuthorizationHandler> sutProvider,
|
||||
CurrentContextOrganization organization)
|
||||
{
|
||||
organization.Type = userType;
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
new[] { OrganizationUserUserDetailsOperations.ReadAll },
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(organization.Id));
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData, CurrentContextOrganizationCustomize]
|
||||
public async Task FlagDisabled_ReadAll_ProviderUser_Success(
|
||||
CurrentContextOrganization organization,
|
||||
SutProvider<OrganizationUserUserDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
organization.Type = OrganizationUserType.User;
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ProviderUserForOrgAsync(organization.Id)
|
||||
.Returns(true);
|
||||
|
||||
var context = new AuthorizationHandlerContext(
|
||||
new[] { OrganizationUserUserDetailsOperations.ReadAll },
|
||||
new ClaimsPrincipal(),
|
||||
new OrganizationScope(organization.Id));
|
||||
|
||||
await sutProvider.Sut.HandleAsync(context);
|
||||
|
||||
Assert.True(context.HasSucceeded);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task FlagDisabled_ReadAll_NotMember_NoSuccess(
|
||||
CurrentContextOrganization organization,
|
||||
SutProvider<OrganizationUserUserDetailsAuthorizationHandler> sutProvider)
|
||||
{
|
||||
var context = new AuthorizationHandlerContext(
|
||||
new[] { OrganizationUserUserDetailsOperations.ReadAll },
|
||||
|
@ -0,0 +1,57 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class OrganizationHasVerifiedDomainsQueryTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task HasVerifiedDomainsAsync_WithVerifiedDomain_ReturnsTrue(
|
||||
OrganizationDomain organizationDomain,
|
||||
SutProvider<OrganizationHasVerifiedDomainsQuery> sutProvider)
|
||||
{
|
||||
organizationDomain.SetVerifiedDate(); // Set the verified date to make it verified
|
||||
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetDomainsByOrganizationIdAsync(organizationDomain.OrganizationId)
|
||||
.Returns(new List<OrganizationDomain> { organizationDomain });
|
||||
|
||||
var result = await sutProvider.Sut.HasVerifiedDomainsAsync(organizationDomain.OrganizationId);
|
||||
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HasVerifiedDomainsAsync_WithoutVerifiedDomain_ReturnsFalse(
|
||||
OrganizationDomain organizationDomain,
|
||||
SutProvider<OrganizationHasVerifiedDomainsQuery> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetDomainsByOrganizationIdAsync(organizationDomain.OrganizationId)
|
||||
.Returns(new List<OrganizationDomain> { organizationDomain });
|
||||
|
||||
var result = await sutProvider.Sut.HasVerifiedDomainsAsync(organizationDomain.OrganizationId);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HasVerifiedDomainsAsync_WithoutOrganizationDomains_ReturnsFalse(
|
||||
Guid organizationId,
|
||||
SutProvider<OrganizationHasVerifiedDomainsQuery> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetDomainsByOrganizationIdAsync(organizationId)
|
||||
.Returns(new List<OrganizationDomain>());
|
||||
|
||||
var result = await sutProvider.Sut.HasVerifiedDomainsAsync(organizationId);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
@ -1,4 +1,7 @@
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
@ -15,7 +18,7 @@ namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.OrganizationDomains;
|
||||
public class VerifyOrganizationDomainCommandTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
public async Task UserVerifyOrganizationDomain_ShouldThrowConflict_WhenDomainHasBeenClaimed(Guid id,
|
||||
public async Task UserVerifyOrganizationDomainAsync_ShouldThrowConflict_WhenDomainHasBeenClaimed(Guid id,
|
||||
SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
{
|
||||
var expected = new OrganizationDomain
|
||||
@ -37,7 +40,7 @@ public class VerifyOrganizationDomainCommandTests
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UserVerifyOrganizationDomain_ShouldThrowConflict_WhenDomainHasBeenClaimedByAnotherOrganization(Guid id,
|
||||
public async Task UserVerifyOrganizationDomainAsync_ShouldThrowConflict_WhenDomainHasBeenClaimedByAnotherOrganization(Guid id,
|
||||
SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
{
|
||||
var expected = new OrganizationDomain
|
||||
@ -61,7 +64,7 @@ public class VerifyOrganizationDomainCommandTests
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UserVerifyOrganizationDomain_ShouldVerifyDomainUpdateAndLogEvent_WhenTxtRecordExists(Guid id,
|
||||
public async Task UserVerifyOrganizationDomainAsync_ShouldVerifyDomainUpdateAndLogEvent_WhenTxtRecordExists(Guid id,
|
||||
SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
{
|
||||
var expected = new OrganizationDomain
|
||||
@ -91,7 +94,7 @@ public class VerifyOrganizationDomainCommandTests
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UserVerifyOrganizationDomain_ShouldNotSetVerifiedDate_WhenTxtRecordDoesNotExist(Guid id,
|
||||
public async Task UserVerifyOrganizationDomainAsync_ShouldNotSetVerifiedDate_WhenTxtRecordDoesNotExist(Guid id,
|
||||
SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
{
|
||||
var expected = new OrganizationDomain
|
||||
@ -120,7 +123,7 @@ public class VerifyOrganizationDomainCommandTests
|
||||
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SystemVerifyOrganizationDomain_CallsEventServiceWithUpdatedJobRunCount(SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
public async Task SystemVerifyOrganizationDomainAsync_CallsEventServiceWithUpdatedJobRunCount(SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
{
|
||||
var domain = new OrganizationDomain()
|
||||
{
|
||||
@ -137,4 +140,97 @@ public class VerifyOrganizationDomainCommandTests
|
||||
.LogOrganizationDomainEventAsync(default, EventType.OrganizationDomain_NotVerified,
|
||||
EventSystemUser.DomainVerification);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UserVerifyOrganizationDomainAsync_GivenOrganizationDomainWithAccountDeprovisioningEnabled_WhenDomainIsVerified_ThenSingleOrgPolicyShouldBeEnabled(
|
||||
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetClaimedDomainsByDomainNameAsync(domain.DomainName)
|
||||
.Returns([]);
|
||||
|
||||
sutProvider.GetDependency<IDnsResolverService>()
|
||||
.ResolveAsync(domain.DomainName, domain.Txt)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
||||
.Returns(true);
|
||||
|
||||
_ = await sutProvider.Sut.UserVerifyOrganizationDomainAsync(domain);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyService>()
|
||||
.Received(1)
|
||||
.SaveAsync(Arg.Is<Policy>(x => x.Type == PolicyType.SingleOrg && x.OrganizationId == domain.OrganizationId && x.Enabled), null);
|
||||
}
|
||||
|
||||
[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<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
||||
.Returns(false);
|
||||
|
||||
_ = await sutProvider.Sut.UserVerifyOrganizationDomainAsync(domain);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyService>()
|
||||
.DidNotReceive()
|
||||
.SaveAsync(Arg.Any<Policy>(), null);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UserVerifyOrganizationDomainAsync_GivenOrganizationDomainWithAccountDeprovisioningEnabled_WhenDomainIsNotVerified_ThenSingleOrgPolicyShouldNotBeEnabled(
|
||||
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetClaimedDomainsByDomainNameAsync(domain.DomainName)
|
||||
.Returns([]);
|
||||
|
||||
sutProvider.GetDependency<IDnsResolverService>()
|
||||
.ResolveAsync(domain.DomainName, domain.Txt)
|
||||
.Returns(false);
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
||||
.Returns(true);
|
||||
|
||||
_ = await sutProvider.Sut.UserVerifyOrganizationDomainAsync(domain);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyService>()
|
||||
.DidNotReceive()
|
||||
.SaveAsync(Arg.Any<Policy>(), null);
|
||||
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task UserVerifyOrganizationDomainAsync_GivenOrganizationDomainWithAccountDeprovisioningDisabled_WhenDomainIsNotVerified_ThenSingleOrgPolicyShouldBeNotBeEnabled(
|
||||
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetClaimedDomainsByDomainNameAsync(domain.DomainName)
|
||||
.Returns([]);
|
||||
|
||||
sutProvider.GetDependency<IDnsResolverService>()
|
||||
.ResolveAsync(domain.DomainName, domain.Txt)
|
||||
.Returns(false);
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
||||
.Returns(true);
|
||||
|
||||
_ = await sutProvider.Sut.UserVerifyOrganizationDomainAsync(domain);
|
||||
|
||||
await sutProvider.GetDependency<IPolicyService>()
|
||||
.DidNotReceive()
|
||||
.SaveAsync(Arg.Any<Policy>(), null);
|
||||
}
|
||||
}
|
||||
|
@ -76,48 +76,4 @@ public class OrganizationDomainServiceTests
|
||||
await sutProvider.GetDependency<IOrganizationDomainRepository>().ReceivedWithAnyArgs(1)
|
||||
.DeleteExpiredAsync(7);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HasVerifiedDomainsAsync_WithVerifiedDomain_ReturnsTrue(
|
||||
OrganizationDomain organizationDomain,
|
||||
SutProvider<OrganizationDomainService> sutProvider)
|
||||
{
|
||||
organizationDomain.SetVerifiedDate(); // Set the verified date to make it verified
|
||||
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetDomainsByOrganizationIdAsync(organizationDomain.OrganizationId)
|
||||
.Returns(new List<OrganizationDomain> { organizationDomain });
|
||||
|
||||
var result = await sutProvider.Sut.HasVerifiedDomainsAsync(organizationDomain.OrganizationId);
|
||||
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HasVerifiedDomainsAsync_WithoutVerifiedDomain_ReturnsFalse(
|
||||
OrganizationDomain organizationDomain,
|
||||
SutProvider<OrganizationDomainService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetDomainsByOrganizationIdAsync(organizationDomain.OrganizationId)
|
||||
.Returns(new List<OrganizationDomain> { organizationDomain });
|
||||
|
||||
var result = await sutProvider.Sut.HasVerifiedDomainsAsync(organizationDomain.OrganizationId);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task HasVerifiedDomainsAsync_WithoutOrganizationDomains_ReturnsFalse(
|
||||
Guid organizationId,
|
||||
SutProvider<OrganizationDomainService> sutProvider)
|
||||
{
|
||||
sutProvider.GetDependency<IOrganizationDomainRepository>()
|
||||
.GetDomainsByOrganizationIdAsync(organizationId)
|
||||
.Returns(new List<OrganizationDomain>());
|
||||
|
||||
var result = await sutProvider.Sut.HasVerifiedDomainsAsync(organizationId);
|
||||
|
||||
Assert.False(result);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.AdminConsole.Services.Implementations;
|
||||
@ -815,4 +816,32 @@ public class PolicyServiceTests
|
||||
new() { OrganizationId = Guid.NewGuid(), PolicyType = PolicyType.DisableSend, PolicyEnabled = true, OrganizationUserType = OrganizationUserType.User, OrganizationUserStatus = OrganizationUserStatusType.Invited, IsProvider = true }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveAsync_GivenOrganizationUsingPoliciesAndHasVerifiedDomains_WhenSingleOrgPolicyIsDisabled_ThenAnErrorShouldBeThrownOrganizationHasVerifiedDomains(
|
||||
[AdminConsoleFixtures.Policy(PolicyType.SingleOrg)] Policy policy, Organization org, SutProvider<PolicyService> sutProvider)
|
||||
{
|
||||
org.Id = policy.OrganizationId;
|
||||
org.UsePolicies = true;
|
||||
|
||||
policy.Enabled = false;
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.AccountDeprovisioning)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(policy.OrganizationId)
|
||||
.Returns(org);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationHasVerifiedDomainsQuery>()
|
||||
.HasVerifiedDomainsAsync(org.Id)
|
||||
.Returns(true);
|
||||
|
||||
var badRequestException = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveAsync(policy, null));
|
||||
|
||||
Assert.Equal("Organization has verified domains.", badRequestException.Message);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Identity.IdentityServer;
|
||||
using Bit.Identity.IdentityServer.RequestValidators;
|
||||
using Bit.Identity.Models.Request.Accounts;
|
||||
using Bit.IntegrationTestCommon.Factories;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
@ -237,6 +237,11 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
|
||||
MasterPasswordHash = DefaultPassword
|
||||
});
|
||||
var userManager = factory.GetService<UserManager<User>>();
|
||||
await factory.RegisterAsync(new RegisterRequestModel
|
||||
{
|
||||
Email = DefaultUsername,
|
||||
MasterPasswordHash = DefaultPassword
|
||||
});
|
||||
var user = await userManager.FindByEmailAsync(DefaultUsername);
|
||||
Assert.NotNull(user);
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
@ -11,8 +10,8 @@ using Bit.Core.Models.Api;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tokens;
|
||||
using Bit.Identity.IdentityServer;
|
||||
using Bit.Identity.IdentityServer.RequestValidators;
|
||||
using Bit.Identity.Test.Wrappers;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Duende.IdentityServer.Validation;
|
||||
@ -32,18 +31,14 @@ public class BaseRequestValidatorTests
|
||||
private readonly IUserService _userService;
|
||||
private readonly IEventService _eventService;
|
||||
private readonly IDeviceValidator _deviceValidator;
|
||||
private readonly IOrganizationDuoWebTokenProvider _organizationDuoWebTokenProvider;
|
||||
private readonly ITemporaryDuoWebV4SDKService _duoWebV4SDKService;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly ITwoFactorAuthenticationValidator _twoFactorAuthenticationValidator;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IApplicationCacheService _applicationCacheService;
|
||||
private readonly IMailService _mailService;
|
||||
private readonly ILogger<BaseRequestValidatorTests> _logger;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IPolicyService _policyService;
|
||||
private readonly IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> _tokenDataFactory;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly ISsoConfigRepository _ssoConfigRepository;
|
||||
private readonly IUserDecryptionOptionsBuilder _userDecryptionOptionsBuilder;
|
||||
@ -52,43 +47,35 @@ public class BaseRequestValidatorTests
|
||||
|
||||
public BaseRequestValidatorTests()
|
||||
{
|
||||
_userManager = SubstituteUserManager();
|
||||
_userService = Substitute.For<IUserService>();
|
||||
_eventService = Substitute.For<IEventService>();
|
||||
_deviceValidator = Substitute.For<IDeviceValidator>();
|
||||
_organizationDuoWebTokenProvider = Substitute.For<IOrganizationDuoWebTokenProvider>();
|
||||
_duoWebV4SDKService = Substitute.For<ITemporaryDuoWebV4SDKService>();
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_twoFactorAuthenticationValidator = Substitute.For<ITwoFactorAuthenticationValidator>();
|
||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
_applicationCacheService = Substitute.For<IApplicationCacheService>();
|
||||
_mailService = Substitute.For<IMailService>();
|
||||
_logger = Substitute.For<ILogger<BaseRequestValidatorTests>>();
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
_globalSettings = Substitute.For<GlobalSettings>();
|
||||
_userRepository = Substitute.For<IUserRepository>();
|
||||
_policyService = Substitute.For<IPolicyService>();
|
||||
_tokenDataFactory = Substitute.For<IDataProtectorTokenFactory<SsoEmail2faSessionTokenable>>();
|
||||
_featureService = Substitute.For<IFeatureService>();
|
||||
_ssoConfigRepository = Substitute.For<ISsoConfigRepository>();
|
||||
_userDecryptionOptionsBuilder = Substitute.For<IUserDecryptionOptionsBuilder>();
|
||||
_userManager = SubstituteUserManager();
|
||||
|
||||
_sut = new BaseRequestValidatorTestWrapper(
|
||||
_userManager,
|
||||
_userService,
|
||||
_eventService,
|
||||
_deviceValidator,
|
||||
_organizationDuoWebTokenProvider,
|
||||
_duoWebV4SDKService,
|
||||
_organizationRepository,
|
||||
_twoFactorAuthenticationValidator,
|
||||
_organizationUserRepository,
|
||||
_applicationCacheService,
|
||||
_mailService,
|
||||
_logger,
|
||||
_currentContext,
|
||||
_globalSettings,
|
||||
_userRepository,
|
||||
_policyService,
|
||||
_tokenDataFactory,
|
||||
_featureService,
|
||||
_ssoConfigRepository,
|
||||
_userDecryptionOptionsBuilder);
|
||||
@ -116,7 +103,7 @@ public class BaseRequestValidatorTests
|
||||
|
||||
var errorResponse = (ErrorResponseModel)context.GrantResult.CustomResponse["ErrorModel"];
|
||||
|
||||
// Assert
|
||||
// Assert
|
||||
await _eventService.Received(1)
|
||||
.LogUserEventAsync(context.CustomValidatorRequestContext.User.Id,
|
||||
Core.Enums.EventType.User_FailedLogIn);
|
||||
@ -127,7 +114,7 @@ public class BaseRequestValidatorTests
|
||||
/* Logic path
|
||||
ValidateAsync -> UpdateFailedAuthDetailsAsync -> _mailService.SendFailedLoginAttemptsEmailAsync
|
||||
|-> BuildErrorResultAsync -> _eventService.LogUserEventAsync
|
||||
(self hosted) |-> _logger.LogWarning()
|
||||
(self hosted) |-> _logger.LogWarning()
|
||||
|-> SetErrorResult
|
||||
*/
|
||||
[Theory, BitAutoData]
|
||||
@ -154,7 +141,7 @@ public class BaseRequestValidatorTests
|
||||
|
||||
/* Logic path
|
||||
ValidateAsync -> UpdateFailedAuthDetailsAsync -> _mailService.SendFailedLoginAttemptsEmailAsync
|
||||
|-> BuildErrorResultAsync -> _eventService.LogUserEventAsync
|
||||
|-> BuildErrorResultAsync -> _eventService.LogUserEventAsync
|
||||
|-> SetErrorResult
|
||||
*/
|
||||
[Theory, BitAutoData]
|
||||
@ -202,6 +189,9 @@ public class BaseRequestValidatorTests
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
_twoFactorAuthenticationValidator
|
||||
.RequiresTwoFactorAsync(Arg.Any<User>(), Arg.Any<ValidatedTokenRequest>())
|
||||
.Returns(Task.FromResult(new Tuple<bool, Organization>(false, default)));
|
||||
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
_sut.isValid = true;
|
||||
@ -230,6 +220,9 @@ public class BaseRequestValidatorTests
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
_twoFactorAuthenticationValidator
|
||||
.RequiresTwoFactorAsync(Arg.Any<User>(), Arg.Any<ValidatedTokenRequest>())
|
||||
.Returns(Task.FromResult(new Tuple<bool, Organization>(false, null)));
|
||||
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
_sut.isValid = true;
|
||||
@ -237,7 +230,7 @@ public class BaseRequestValidatorTests
|
||||
context.CustomValidatorRequestContext.User.CreationDate = DateTime.UtcNow - TimeSpan.FromDays(1);
|
||||
_globalSettings.DisableEmailNewDevice = false;
|
||||
|
||||
context.ValidatedTokenRequest.GrantType = "client_credentials"; // This || AuthCode will allow process to continue to get device
|
||||
context.ValidatedTokenRequest.GrantType = "client_credentials"; // This || AuthCode will allow process to continue to get device
|
||||
|
||||
_deviceValidator.SaveDeviceAsync(Arg.Any<User>(), Arg.Any<ValidatedTokenRequest>())
|
||||
.Returns(device);
|
||||
@ -267,10 +260,13 @@ public class BaseRequestValidatorTests
|
||||
context.CustomValidatorRequestContext.User.CreationDate = DateTime.UtcNow - TimeSpan.FromDays(1);
|
||||
_globalSettings.DisableEmailNewDevice = false;
|
||||
|
||||
context.ValidatedTokenRequest.GrantType = "client_credentials"; // This || AuthCode will allow process to continue to get device
|
||||
context.ValidatedTokenRequest.GrantType = "client_credentials"; // This || AuthCode will allow process to continue to get device
|
||||
|
||||
_deviceValidator.SaveDeviceAsync(Arg.Any<User>(), Arg.Any<ValidatedTokenRequest>())
|
||||
.Returns(device);
|
||||
_twoFactorAuthenticationValidator
|
||||
.RequiresTwoFactorAsync(Arg.Any<User>(), Arg.Any<ValidatedTokenRequest>())
|
||||
.Returns(Task.FromResult(new Tuple<bool, Organization>(false, null)));
|
||||
// Act
|
||||
await _sut.ValidateAsync(context);
|
||||
|
||||
@ -306,10 +302,13 @@ public class BaseRequestValidatorTests
|
||||
_policyService.AnyPoliciesApplicableToUserAsync(
|
||||
Arg.Any<Guid>(), PolicyType.RequireSso, OrganizationUserStatusType.Confirmed)
|
||||
.Returns(Task.FromResult(true));
|
||||
_twoFactorAuthenticationValidator
|
||||
.RequiresTwoFactorAsync(Arg.Any<User>(), Arg.Any<ValidatedTokenRequest>())
|
||||
.Returns(Task.FromResult(new Tuple<bool, Organization>(false, null)));
|
||||
// Act
|
||||
await _sut.ValidateAsync(context);
|
||||
|
||||
// Assert
|
||||
// Assert
|
||||
Assert.True(context.GrantResult.IsError);
|
||||
var errorResponse = (ErrorResponseModel)context.GrantResult.CustomResponse["ErrorModel"];
|
||||
Assert.Equal("SSO authentication is required.", errorResponse.Message);
|
||||
@ -330,6 +329,9 @@ public class BaseRequestValidatorTests
|
||||
context.ValidatedTokenRequest.ClientId = "Not Web";
|
||||
_sut.isValid = true;
|
||||
_featureService.IsEnabled(FeatureFlagKeys.BlockLegacyUsers).Returns(true);
|
||||
_twoFactorAuthenticationValidator
|
||||
.RequiresTwoFactorAsync(Arg.Any<User>(), Arg.Any<ValidatedTokenRequest>())
|
||||
.Returns(Task.FromResult(new Tuple<bool, Organization>(false, null)));
|
||||
|
||||
// Act
|
||||
await _sut.ValidateAsync(context);
|
||||
@ -341,28 +343,6 @@ public class BaseRequestValidatorTests
|
||||
, errorResponse.Message);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task RequiresTwoFactorAsync_ClientCredentialsGrantType_ShouldReturnFalse(
|
||||
[AuthFixtures.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest,
|
||||
CustomValidatorRequestContext requestContext,
|
||||
GrantValidationResult grantResult)
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
context.ValidatedTokenRequest.GrantType = "client_credentials";
|
||||
|
||||
// Act
|
||||
var result = await _sut.TestRequiresTwoFactorAsync(
|
||||
context.CustomValidatorRequestContext.User,
|
||||
context.ValidatedTokenRequest);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Item1);
|
||||
Assert.Null(result.Item2);
|
||||
}
|
||||
|
||||
private BaseRequestValidationContextFake CreateContext(
|
||||
ValidatedTokenRequest tokenRequest,
|
||||
CustomValidatorRequestContext requestContext,
|
||||
|
@ -4,7 +4,7 @@ using Bit.Core.Enums;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Identity.IdentityServer;
|
||||
using Bit.Identity.IdentityServer.RequestValidators;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Duende.IdentityServer.Validation;
|
||||
using NSubstitute;
|
||||
|
@ -0,0 +1,575 @@
|
||||
using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Auth.Models;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Models.Data.Organizations;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tokens;
|
||||
using Bit.Identity.IdentityServer.RequestValidators;
|
||||
using Bit.Identity.Test.Wrappers;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Duende.IdentityServer.Validation;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using AuthFixtures = Bit.Identity.Test.AutoFixture;
|
||||
|
||||
namespace Bit.Identity.Test.IdentityServer;
|
||||
|
||||
public class TwoFactorAuthenticationValidatorTests
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly UserManagerTestWrapper<User> _userManager;
|
||||
private readonly IOrganizationDuoWebTokenProvider _organizationDuoWebTokenProvider;
|
||||
private readonly ITemporaryDuoWebV4SDKService _temporaryDuoWebV4SDKService;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly IApplicationCacheService _applicationCacheService;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> _ssoEmail2faSessionTokenable;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly TwoFactorAuthenticationValidator _sut;
|
||||
|
||||
public TwoFactorAuthenticationValidatorTests()
|
||||
{
|
||||
_userService = Substitute.For<IUserService>();
|
||||
_userManager = SubstituteUserManager();
|
||||
_organizationDuoWebTokenProvider = Substitute.For<IOrganizationDuoWebTokenProvider>();
|
||||
_temporaryDuoWebV4SDKService = Substitute.For<ITemporaryDuoWebV4SDKService>();
|
||||
_featureService = Substitute.For<IFeatureService>();
|
||||
_applicationCacheService = Substitute.For<IApplicationCacheService>();
|
||||
_organizationUserRepository = Substitute.For<IOrganizationUserRepository>();
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_ssoEmail2faSessionTokenable = Substitute.For<IDataProtectorTokenFactory<SsoEmail2faSessionTokenable>>();
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
|
||||
_sut = new TwoFactorAuthenticationValidator(
|
||||
_userService,
|
||||
_userManager,
|
||||
_organizationDuoWebTokenProvider,
|
||||
_temporaryDuoWebV4SDKService,
|
||||
_featureService,
|
||||
_applicationCacheService,
|
||||
_organizationUserRepository,
|
||||
_organizationRepository,
|
||||
_ssoEmail2faSessionTokenable,
|
||||
_currentContext);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData("password")]
|
||||
[BitAutoData("authorization_code")]
|
||||
public async void RequiresTwoFactorAsync_IndividualOnly_Required_ReturnTrue(
|
||||
string grantType,
|
||||
[AuthFixtures.ValidatedTokenRequest] ValidatedTokenRequest request,
|
||||
User user)
|
||||
{
|
||||
// Arrange
|
||||
request.GrantType = grantType;
|
||||
// All three of these must be true for the two factor authentication to be required
|
||||
_userManager.TWO_FACTOR_ENABLED = true;
|
||||
_userManager.SUPPORTS_TWO_FACTOR = true;
|
||||
// In order for the two factor authentication to be required, the user must have at least one two factor provider
|
||||
_userManager.TWO_FACTOR_PROVIDERS = ["email"];
|
||||
|
||||
// Act
|
||||
var result = await _sut.RequiresTwoFactorAsync(user, request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Item1);
|
||||
Assert.Null(result.Item2);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData("client_credentials")]
|
||||
[BitAutoData("webauthn")]
|
||||
public async void RequiresTwoFactorAsync_NotRequired_ReturnFalse(
|
||||
string grantType,
|
||||
[AuthFixtures.ValidatedTokenRequest] ValidatedTokenRequest request,
|
||||
User user)
|
||||
{
|
||||
// Arrange
|
||||
request.GrantType = grantType;
|
||||
|
||||
// Act
|
||||
var result = await _sut.RequiresTwoFactorAsync(user, request);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Item1);
|
||||
Assert.Null(result.Item2);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData("password")]
|
||||
[BitAutoData("authorization_code")]
|
||||
public async void RequiresTwoFactorAsync_IndividualFalse_OrganizationRequired_ReturnTrue(
|
||||
string grantType,
|
||||
[AuthFixtures.ValidatedTokenRequest] ValidatedTokenRequest request,
|
||||
User user,
|
||||
OrganizationUserOrganizationDetails orgUser,
|
||||
Organization organization,
|
||||
ICollection<CurrentContextOrganization> organizationCollection)
|
||||
{
|
||||
// Arrange
|
||||
request.GrantType = grantType;
|
||||
// Link the orgUser to the User making the request
|
||||
orgUser.UserId = user.Id;
|
||||
// Link organization to the organization user
|
||||
organization.Id = orgUser.OrganizationId;
|
||||
|
||||
// Set Organization 2FA to required
|
||||
organization.Use2fa = true;
|
||||
organization.TwoFactorProviders = GetTwoFactorOrganizationDuoProviderJson();
|
||||
organization.Enabled = true;
|
||||
|
||||
// Make sure organization list is not empty
|
||||
organizationCollection.Clear();
|
||||
// Fix OrganizationUser Permissions field
|
||||
orgUser.Permissions = "{}";
|
||||
organizationCollection.Add(new CurrentContextOrganization(orgUser));
|
||||
|
||||
_currentContext.OrganizationMembershipAsync(Arg.Any<IOrganizationUserRepository>(), Arg.Any<Guid>())
|
||||
.Returns(Task.FromResult(organizationCollection));
|
||||
|
||||
_applicationCacheService.GetOrganizationAbilitiesAsync()
|
||||
.Returns(new Dictionary<Guid, OrganizationAbility>()
|
||||
{
|
||||
{ orgUser.OrganizationId, new OrganizationAbility(organization)}
|
||||
});
|
||||
|
||||
_organizationRepository.GetManyByUserIdAsync(Arg.Any<Guid>()).Returns([organization]);
|
||||
|
||||
// Act
|
||||
var result = await _sut.RequiresTwoFactorAsync(user, request);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Item1);
|
||||
Assert.NotNull(result.Item2);
|
||||
Assert.IsType<Organization>(result.Item2);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BuildTwoFactorResultAsync_NoProviders_ReturnsNull(
|
||||
User user,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
organization.Use2fa = true;
|
||||
organization.TwoFactorProviders = "{}";
|
||||
organization.Enabled = true;
|
||||
|
||||
user.TwoFactorProviders = "";
|
||||
|
||||
// Act
|
||||
var result = await _sut.BuildTwoFactorResultAsync(user, organization);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BuildTwoFactorResultAsync_OrganizationProviders_NotEnabled_ReturnsNull(
|
||||
User user,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
organization.Use2fa = true;
|
||||
organization.TwoFactorProviders = GetTwoFactorOrganizationNotEnabledDuoProviderJson();
|
||||
organization.Enabled = true;
|
||||
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
// Act
|
||||
var result = await _sut.BuildTwoFactorResultAsync(user, organization);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BuildTwoFactorResultAsync_OrganizationProviders_ReturnsNotNull(
|
||||
User user,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
organization.Use2fa = true;
|
||||
organization.TwoFactorProviders = GetTwoFactorOrganizationDuoProviderJson();
|
||||
organization.Enabled = true;
|
||||
|
||||
user.TwoFactorProviders = null;
|
||||
|
||||
// Act
|
||||
var result = await _sut.BuildTwoFactorResultAsync(user, organization);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<Dictionary<string, object>>(result);
|
||||
Assert.NotEmpty(result);
|
||||
Assert.True(result.ContainsKey("TwoFactorProviders2"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BuildTwoFactorResultAsync_IndividualProviders_NotEnabled_ReturnsNull(
|
||||
User user)
|
||||
{
|
||||
// Arrange
|
||||
user.TwoFactorProviders = GetTwoFactorIndividualNotEnabledProviderJson(TwoFactorProviderType.Email);
|
||||
|
||||
// Act
|
||||
var result = await _sut.BuildTwoFactorResultAsync(user, null);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void BuildTwoFactorResultAsync_IndividualProviders_ReturnsNotNull(
|
||||
User user)
|
||||
{
|
||||
// Arrange
|
||||
_userService.CanAccessPremium(user).Returns(true);
|
||||
|
||||
user.TwoFactorProviders = GetTwoFactorIndividualProviderJson(TwoFactorProviderType.Duo);
|
||||
|
||||
// Act
|
||||
var result = await _sut.BuildTwoFactorResultAsync(user, null);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<Dictionary<string, object>>(result);
|
||||
Assert.NotEmpty(result);
|
||||
Assert.True(result.ContainsKey("TwoFactorProviders2"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(TwoFactorProviderType.Email)]
|
||||
public async void BuildTwoFactorResultAsync_IndividualEmailProvider_SendsEmail_SetsSsoToken_ReturnsNotNull(
|
||||
TwoFactorProviderType providerType,
|
||||
User user)
|
||||
{
|
||||
// Arrange
|
||||
var providerTypeInt = (int)providerType;
|
||||
user.TwoFactorProviders = GetTwoFactorIndividualProviderJson(providerType);
|
||||
|
||||
_userManager.TWO_FACTOR_ENABLED = true;
|
||||
_userManager.SUPPORTS_TWO_FACTOR = true;
|
||||
_userManager.TWO_FACTOR_PROVIDERS = [providerType.ToString()];
|
||||
|
||||
_userService.TwoFactorProviderIsEnabledAsync(Arg.Any<TwoFactorProviderType>(), user)
|
||||
.Returns(true);
|
||||
|
||||
// Act
|
||||
var result = await _sut.BuildTwoFactorResultAsync(user, null);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<Dictionary<string, object>>(result);
|
||||
Assert.NotEmpty(result);
|
||||
Assert.True(result.ContainsKey("TwoFactorProviders2"));
|
||||
var providers = (Dictionary<string, Dictionary<string, object>>)result["TwoFactorProviders2"];
|
||||
Assert.True(providers.ContainsKey(providerTypeInt.ToString()));
|
||||
Assert.True(result.ContainsKey("SsoEmail2faSessionToken"));
|
||||
Assert.True(result.ContainsKey("Email"));
|
||||
|
||||
await _userService.Received(1).SendTwoFactorEmailAsync(Arg.Any<User>());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(TwoFactorProviderType.Duo)]
|
||||
[BitAutoData(TwoFactorProviderType.WebAuthn)]
|
||||
[BitAutoData(TwoFactorProviderType.Email)]
|
||||
[BitAutoData(TwoFactorProviderType.YubiKey)]
|
||||
[BitAutoData(TwoFactorProviderType.OrganizationDuo)]
|
||||
public async void BuildTwoFactorResultAsync_IndividualProvider_ReturnMatchesType(
|
||||
TwoFactorProviderType providerType,
|
||||
User user)
|
||||
{
|
||||
// Arrange
|
||||
var providerTypeInt = (int)providerType;
|
||||
user.TwoFactorProviders = GetTwoFactorIndividualProviderJson(providerType);
|
||||
|
||||
_userManager.TWO_FACTOR_ENABLED = true;
|
||||
_userManager.SUPPORTS_TWO_FACTOR = true;
|
||||
_userManager.TWO_FACTOR_PROVIDERS = [providerType.ToString()];
|
||||
_userManager.TWO_FACTOR_TOKEN = "{\"Key1\":\"WebauthnToken\"}";
|
||||
|
||||
_userService.CanAccessPremium(user).Returns(true);
|
||||
|
||||
// Act
|
||||
var result = await _sut.BuildTwoFactorResultAsync(user, null);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.IsType<Dictionary<string, object>>(result);
|
||||
Assert.NotEmpty(result);
|
||||
Assert.True(result.ContainsKey("TwoFactorProviders2"));
|
||||
var providers = (Dictionary<string, Dictionary<string, object>>)result["TwoFactorProviders2"];
|
||||
Assert.True(providers.ContainsKey(providerTypeInt.ToString()));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void VerifyTwoFactorAsync_Individual_TypeNull_ReturnsFalse(
|
||||
User user,
|
||||
string token)
|
||||
{
|
||||
// Arrange
|
||||
_userService.TwoFactorProviderIsEnabledAsync(
|
||||
TwoFactorProviderType.Email, user).Returns(true);
|
||||
|
||||
_userManager.TWO_FACTOR_PROVIDERS = ["email"];
|
||||
|
||||
// Act
|
||||
var result = await _sut.VerifyTwoFactor(
|
||||
user, null, TwoFactorProviderType.U2f, token);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void VerifyTwoFactorAsync_Individual_NotEnabled_ReturnsFalse(
|
||||
User user,
|
||||
string token)
|
||||
{
|
||||
// Arrange
|
||||
_userService.TwoFactorProviderIsEnabledAsync(
|
||||
TwoFactorProviderType.Email, user).Returns(false);
|
||||
|
||||
_userManager.TWO_FACTOR_PROVIDERS = ["email"];
|
||||
|
||||
// Act
|
||||
var result = await _sut.VerifyTwoFactor(
|
||||
user, null, TwoFactorProviderType.Email, token);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void VerifyTwoFactorAsync_Organization_NotEnabled_ReturnsFalse(
|
||||
User user,
|
||||
string token)
|
||||
{
|
||||
// Arrange
|
||||
_userService.TwoFactorProviderIsEnabledAsync(
|
||||
TwoFactorProviderType.OrganizationDuo, user).Returns(false);
|
||||
|
||||
_userManager.TWO_FACTOR_PROVIDERS = ["OrganizationDuo"];
|
||||
|
||||
// Act
|
||||
var result = await _sut.VerifyTwoFactor(
|
||||
user, null, TwoFactorProviderType.OrganizationDuo, token);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(TwoFactorProviderType.Duo)]
|
||||
[BitAutoData(TwoFactorProviderType.WebAuthn)]
|
||||
[BitAutoData(TwoFactorProviderType.Email)]
|
||||
[BitAutoData(TwoFactorProviderType.YubiKey)]
|
||||
[BitAutoData(TwoFactorProviderType.Remember)]
|
||||
public async void VerifyTwoFactorAsync_Individual_ValidToken_ReturnsTrue(
|
||||
TwoFactorProviderType providerType,
|
||||
User user,
|
||||
string token)
|
||||
{
|
||||
// Arrange
|
||||
_userService.TwoFactorProviderIsEnabledAsync(
|
||||
providerType, user).Returns(true);
|
||||
|
||||
_userManager.TWO_FACTOR_ENABLED = true;
|
||||
_userManager.TWO_FACTOR_TOKEN_VERIFIED = true;
|
||||
|
||||
// Act
|
||||
var result = await _sut.VerifyTwoFactor(user, null, providerType, token);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(TwoFactorProviderType.Duo)]
|
||||
[BitAutoData(TwoFactorProviderType.WebAuthn)]
|
||||
[BitAutoData(TwoFactorProviderType.Email)]
|
||||
[BitAutoData(TwoFactorProviderType.YubiKey)]
|
||||
[BitAutoData(TwoFactorProviderType.Remember)]
|
||||
public async void VerifyTwoFactorAsync_Individual_InvalidToken_ReturnsFalse(
|
||||
TwoFactorProviderType providerType,
|
||||
User user,
|
||||
string token)
|
||||
{
|
||||
// Arrange
|
||||
_userService.TwoFactorProviderIsEnabledAsync(
|
||||
providerType, user).Returns(true);
|
||||
|
||||
_userManager.TWO_FACTOR_ENABLED = true;
|
||||
_userManager.TWO_FACTOR_TOKEN_VERIFIED = false;
|
||||
|
||||
// Act
|
||||
var result = await _sut.VerifyTwoFactor(user, null, providerType, token);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(TwoFactorProviderType.OrganizationDuo)]
|
||||
public async void VerifyTwoFactorAsync_Organization_ValidToken_ReturnsTrue(
|
||||
TwoFactorProviderType providerType,
|
||||
User user,
|
||||
Organization organization,
|
||||
string token)
|
||||
{
|
||||
// Arrange
|
||||
_organizationDuoWebTokenProvider.ValidateAsync(
|
||||
token, organization, user).Returns(true);
|
||||
|
||||
_userManager.TWO_FACTOR_ENABLED = true;
|
||||
_userManager.TWO_FACTOR_TOKEN_VERIFIED = true;
|
||||
|
||||
organization.Use2fa = true;
|
||||
organization.TwoFactorProviders = GetTwoFactorOrganizationDuoProviderJson();
|
||||
organization.Enabled = true;
|
||||
|
||||
// Act
|
||||
var result = await _sut.VerifyTwoFactor(
|
||||
user, organization, providerType, token);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(TwoFactorProviderType.Duo)]
|
||||
[BitAutoData(TwoFactorProviderType.OrganizationDuo)]
|
||||
public async void VerifyTwoFactorAsync_TemporaryDuoService_ValidToken_ReturnsTrue(
|
||||
TwoFactorProviderType providerType,
|
||||
User user,
|
||||
Organization organization,
|
||||
string token)
|
||||
{
|
||||
// Arrange
|
||||
_featureService.IsEnabled(FeatureFlagKeys.DuoRedirect).Returns(true);
|
||||
_userService.TwoFactorProviderIsEnabledAsync(providerType, user).Returns(true);
|
||||
_temporaryDuoWebV4SDKService.ValidateAsync(
|
||||
token, Arg.Any<TwoFactorProvider>(), user).Returns(true);
|
||||
|
||||
user.TwoFactorProviders = GetTwoFactorIndividualProviderJson(providerType);
|
||||
organization.Use2fa = true;
|
||||
organization.TwoFactorProviders = GetTwoFactorOrganizationDuoProviderJson();
|
||||
organization.Enabled = true;
|
||||
|
||||
_userManager.TWO_FACTOR_ENABLED = true;
|
||||
_userManager.TWO_FACTOR_TOKEN = token;
|
||||
_userManager.TWO_FACTOR_TOKEN_VERIFIED = true;
|
||||
|
||||
// Act
|
||||
var result = await _sut.VerifyTwoFactor(
|
||||
user, organization, providerType, token);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(TwoFactorProviderType.Duo)]
|
||||
[BitAutoData(TwoFactorProviderType.OrganizationDuo)]
|
||||
public async void VerifyTwoFactorAsync_TemporaryDuoService_InvalidToken_ReturnsFalse(
|
||||
TwoFactorProviderType providerType,
|
||||
User user,
|
||||
Organization organization,
|
||||
string token)
|
||||
{
|
||||
// Arrange
|
||||
_featureService.IsEnabled(FeatureFlagKeys.DuoRedirect).Returns(true);
|
||||
_userService.TwoFactorProviderIsEnabledAsync(providerType, user).Returns(true);
|
||||
_temporaryDuoWebV4SDKService.ValidateAsync(
|
||||
token, Arg.Any<TwoFactorProvider>(), user).Returns(true);
|
||||
|
||||
user.TwoFactorProviders = GetTwoFactorIndividualProviderJson(providerType);
|
||||
organization.Use2fa = true;
|
||||
organization.TwoFactorProviders = GetTwoFactorOrganizationDuoProviderJson();
|
||||
organization.Enabled = true;
|
||||
|
||||
_userManager.TWO_FACTOR_ENABLED = true;
|
||||
_userManager.TWO_FACTOR_TOKEN = token;
|
||||
_userManager.TWO_FACTOR_TOKEN_VERIFIED = false;
|
||||
|
||||
// Act
|
||||
var result = await _sut.VerifyTwoFactor(
|
||||
user, organization, providerType, token);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
private static UserManagerTestWrapper<User> SubstituteUserManager()
|
||||
{
|
||||
return new UserManagerTestWrapper<User>(
|
||||
Substitute.For<IUserTwoFactorStore<User>>(),
|
||||
Substitute.For<IOptions<IdentityOptions>>(),
|
||||
Substitute.For<IPasswordHasher<User>>(),
|
||||
Enumerable.Empty<IUserValidator<User>>(),
|
||||
Enumerable.Empty<IPasswordValidator<User>>(),
|
||||
Substitute.For<ILookupNormalizer>(),
|
||||
Substitute.For<IdentityErrorDescriber>(),
|
||||
Substitute.For<IServiceProvider>(),
|
||||
Substitute.For<ILogger<UserManager<User>>>());
|
||||
}
|
||||
|
||||
private static string GetTwoFactorOrganizationDuoProviderJson(bool enabled = true)
|
||||
{
|
||||
return
|
||||
"{\"6\":{\"Enabled\":true,\"MetaData\":{\"ClientSecret\":\"secretClientSecret\",\"ClientId\":\"clientId\",\"Host\":\"example.com\"}}}";
|
||||
}
|
||||
|
||||
private static string GetTwoFactorOrganizationNotEnabledDuoProviderJson(bool enabled = true)
|
||||
{
|
||||
return
|
||||
"{\"6\":{\"Enabled\":false,\"MetaData\":{\"ClientSecret\":\"secretClientSecret\",\"ClientId\":\"clientId\",\"Host\":\"example.com\"}}}";
|
||||
}
|
||||
|
||||
private static string GetTwoFactorIndividualProviderJson(TwoFactorProviderType providerType)
|
||||
{
|
||||
return providerType switch
|
||||
{
|
||||
TwoFactorProviderType.Duo => "{\"2\":{\"Enabled\":true,\"MetaData\":{\"ClientSecret\":\"secretClientSecret\",\"ClientId\":\"clientId\",\"Host\":\"example.com\"}}}",
|
||||
TwoFactorProviderType.Email => "{\"1\":{\"Enabled\":true,\"MetaData\":{\"Email\":\"user@test.dev\"}}}",
|
||||
TwoFactorProviderType.WebAuthn => "{\"7\":{\"Enabled\":true,\"MetaData\":{\"Key1\":{\"Name\":\"key1\",\"Descriptor\":{\"Type\":0,\"Id\":\"keyId\",\"Transports\":null},\"PublicKey\":\"key\",\"UserHandle\":\"handle\",\"SignatureCounter\":0,\"CredType\":\"none\",\"RegDate\":\"2022-01-01T00:00:00Z\",\"AaGuid\":\"00000000-0000-0000-0000-000000000000\",\"Migrated\":false}}}}",
|
||||
TwoFactorProviderType.YubiKey => "{\"3\":{\"Enabled\":true,\"MetaData\":{\"Id\":\"yubikeyId\",\"Nfc\":true}}}",
|
||||
TwoFactorProviderType.OrganizationDuo => "{\"6\":{\"Enabled\":true,\"MetaData\":{\"ClientSecret\":\"secretClientSecret\",\"ClientId\":\"clientId\",\"Host\":\"example.com\"}}}",
|
||||
_ => "{}",
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetTwoFactorIndividualNotEnabledProviderJson(TwoFactorProviderType providerType)
|
||||
{
|
||||
return providerType switch
|
||||
{
|
||||
TwoFactorProviderType.Duo => "{\"2\":{\"Enabled\":false,\"MetaData\":{\"ClientSecret\":\"secretClientSecret\",\"ClientId\":\"clientId\",\"Host\":\"example.com\"}}}",
|
||||
TwoFactorProviderType.Email => "{\"1\":{\"Enabled\":false,\"MetaData\":{\"Email\":\"user@test.dev\"}}}",
|
||||
TwoFactorProviderType.WebAuthn => "{\"7\":{\"Enabled\":false,\"MetaData\":{\"Key1\":{\"Name\":\"key1\",\"Descriptor\":{\"Type\":0,\"Id\":\"keyId\",\"Transports\":null},\"PublicKey\":\"key\",\"UserHandle\":\"handle\",\"SignatureCounter\":0,\"CredType\":\"none\",\"RegDate\":\"2022-01-01T00:00:00Z\",\"AaGuid\":\"00000000-0000-0000-0000-000000000000\",\"Migrated\":false}}}}",
|
||||
TwoFactorProviderType.YubiKey => "{\"3\":{\"Enabled\":false,\"MetaData\":{\"Id\":\"yubikeyId\",\"Nfc\":true}}}",
|
||||
TwoFactorProviderType.OrganizationDuo => "{\"6\":{\"Enabled\":false,\"MetaData\":{\"ClientSecret\":\"secretClientSecret\",\"ClientId\":\"clientId\",\"Host\":\"example.com\"}}}",
|
||||
_ => "{}",
|
||||
};
|
||||
}
|
||||
}
|
@ -1,16 +1,13 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Services;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Tokens;
|
||||
using Bit.Identity.IdentityServer;
|
||||
using Bit.Identity.IdentityServer.RequestValidators;
|
||||
using Duende.IdentityServer.Models;
|
||||
using Duende.IdentityServer.Validation;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
@ -54,38 +51,30 @@ IBaseRequestValidatorTestWrapper
|
||||
IUserService userService,
|
||||
IEventService eventService,
|
||||
IDeviceValidator deviceValidator,
|
||||
IOrganizationDuoWebTokenProvider organizationDuoWebTokenProvider,
|
||||
ITemporaryDuoWebV4SDKService duoWebV4SDKService,
|
||||
IOrganizationRepository organizationRepository,
|
||||
ITwoFactorAuthenticationValidator twoFactorAuthenticationValidator,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IApplicationCacheService applicationCacheService,
|
||||
IMailService mailService,
|
||||
ILogger logger,
|
||||
ICurrentContext currentContext,
|
||||
GlobalSettings globalSettings,
|
||||
IUserRepository userRepository,
|
||||
IPolicyService policyService,
|
||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
||||
IFeatureService featureService,
|
||||
ISsoConfigRepository ssoConfigRepository,
|
||||
IUserDecryptionOptionsBuilder userDecryptionOptionsBuilder) :
|
||||
base(
|
||||
base(
|
||||
userManager,
|
||||
userService,
|
||||
eventService,
|
||||
deviceValidator,
|
||||
organizationDuoWebTokenProvider,
|
||||
duoWebV4SDKService,
|
||||
organizationRepository,
|
||||
twoFactorAuthenticationValidator,
|
||||
organizationUserRepository,
|
||||
applicationCacheService,
|
||||
mailService,
|
||||
logger,
|
||||
currentContext,
|
||||
globalSettings,
|
||||
userRepository,
|
||||
policyService,
|
||||
tokenDataFactory,
|
||||
featureService,
|
||||
ssoConfigRepository,
|
||||
userDecryptionOptionsBuilder)
|
||||
@ -98,13 +87,6 @@ IBaseRequestValidatorTestWrapper
|
||||
await ValidateAsync(context, context.ValidatedTokenRequest, context.CustomValidatorRequestContext);
|
||||
}
|
||||
|
||||
public async Task<Tuple<bool, Organization>> TestRequiresTwoFactorAsync(
|
||||
User user,
|
||||
ValidatedTokenRequest context)
|
||||
{
|
||||
return await RequiresTwoFactorAsync(user, context);
|
||||
}
|
||||
|
||||
protected override ClaimsPrincipal GetSubject(
|
||||
BaseRequestValidationContextFake context)
|
||||
{
|
||||
|
96
test/Identity.Test/Wrappers/UserManagerTestWrapper.cs
Normal file
96
test/Identity.Test/Wrappers/UserManagerTestWrapper.cs
Normal file
@ -0,0 +1,96 @@
|
||||
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Bit.Identity.Test.Wrappers;
|
||||
|
||||
public class UserManagerTestWrapper<TUser> : UserManager<TUser> where TUser : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Modify this value to mock the responses from UserManager.GetTwoFactorEnabledAsync()
|
||||
/// </summary>
|
||||
public bool TWO_FACTOR_ENABLED { get; set; } = false;
|
||||
/// <summary>
|
||||
/// Modify this value to mock the responses from UserManager.GetValidTwoFactorProvidersAsync()
|
||||
/// </summary>
|
||||
public IList<string> TWO_FACTOR_PROVIDERS { get; set; } = [];
|
||||
/// <summary>
|
||||
/// Modify this value to mock the responses from UserManager.GenerateTwoFactorTokenAsync()
|
||||
/// </summary>
|
||||
public string TWO_FACTOR_TOKEN { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// Modify this value to mock the responses from UserManager.VerifyTwoFactorTokenAsync()
|
||||
/// </summary>
|
||||
public bool TWO_FACTOR_TOKEN_VERIFIED { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Modify this value to mock the responses from UserManager.SupportsUserTwoFactor
|
||||
/// </summary>
|
||||
public bool SUPPORTS_TWO_FACTOR { get; set; } = false;
|
||||
|
||||
public override bool SupportsUserTwoFactor
|
||||
{
|
||||
get
|
||||
{
|
||||
return SUPPORTS_TWO_FACTOR;
|
||||
}
|
||||
}
|
||||
|
||||
public UserManagerTestWrapper(
|
||||
IUserStore<TUser> store,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
IPasswordHasher<TUser> passwordHasher,
|
||||
IEnumerable<IUserValidator<TUser>> userValidators,
|
||||
IEnumerable<IPasswordValidator<TUser>> passwordValidators,
|
||||
ILookupNormalizer keyNormalizer,
|
||||
IdentityErrorDescriber errors,
|
||||
IServiceProvider services,
|
||||
ILogger<UserManager<TUser>> logger)
|
||||
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators,
|
||||
keyNormalizer, errors, services, logger)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// return class variable TWO_FACTOR_ENABLED
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<bool> GetTwoFactorEnabledAsync(TUser user)
|
||||
{
|
||||
return TWO_FACTOR_ENABLED;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return class variable TWO_FACTOR_PROVIDERS
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<IList<string>> GetValidTwoFactorProvidersAsync(TUser user)
|
||||
{
|
||||
return TWO_FACTOR_PROVIDERS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return class variable TWO_FACTOR_TOKEN
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="tokenProvider"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<string> GenerateTwoFactorTokenAsync(TUser user, string tokenProvider)
|
||||
{
|
||||
return TWO_FACTOR_TOKEN;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return class variable TWO_FACTOR_TOKEN_VERIFIED
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="tokenProvider"></param>
|
||||
/// <param name="token"></param>
|
||||
/// <returns></returns>
|
||||
public override async Task<bool> VerifyTwoFactorTokenAsync(TUser user, string tokenProvider, string token)
|
||||
{
|
||||
return TWO_FACTOR_TOKEN_VERIFIED;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user