1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-16 07:50:49 -05:00
bitwarden/test/Core.Test/Auth/Services/TwoFactorEmailServiceTests.cs
2025-06-13 19:21:33 -04:00

326 lines
13 KiB
C#

using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models;
using Bit.Core.Auth.Services;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Core.Auth.Enums;
using Microsoft.AspNetCore.Identity;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.Auth.Services;
[SutProviderCustomize]
public class TwoFactorEmailServiceTests
{
[Theory, BitAutoData]
public async Task SendTwoFactorEmailAsync_Success(SutProvider<TwoFactorEmailService> sutProvider, User user)
{
var email = user.Email.ToLowerInvariant();
var token = "thisisatokentocompare";
var IpAddress = "1.1.1.1";
var deviceType = DeviceType.Android;
var context = sutProvider.GetDependency<ICurrentContext>();
context.DeviceType = deviceType;
context.IpAddress = IpAddress;
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
userTwoFactorTokenProvider
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(true));
userTwoFactorTokenProvider
.GenerateAsync("TwoFactor", Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(token));
var userManager = sutProvider.GetDependency<UserManager<User>>();
userManager.RegisterTokenProvider(CoreHelpers.CustomProviderName(TwoFactorProviderType.Email), userTwoFactorTokenProvider);
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Email"] = email },
Enabled = true
}
});
await sutProvider.Sut.SendTwoFactorEmailAsync(user);
await sutProvider.GetDependency<IMailService>()
.Received(1)
.SendTwoFactorEmailAsync(email, user.Email, token, IpAddress, deviceType.ToString(),
TwoFactorEmailPurpose.Login);
}
[Theory, BitAutoData]
public async Task SendTwoFactorSetupEmailAsync_Success(SutProvider<TwoFactorEmailService> sutProvider, User user)
{
var email = user.Email.ToLowerInvariant();
var token = "thisisatokentocompare";
var IpAddress = "1.1.1.1";
var deviceType = DeviceType.Android;
var context = sutProvider.GetDependency<ICurrentContext>();
context.DeviceType = deviceType;
context.IpAddress = IpAddress;
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
userTwoFactorTokenProvider
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(true));
userTwoFactorTokenProvider
.GenerateAsync("TwoFactor", Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(token));
var userManager = sutProvider.GetDependency<UserManager<User>>();
userManager.RegisterTokenProvider(CoreHelpers.CustomProviderName(TwoFactorProviderType.Email), userTwoFactorTokenProvider);
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Email"] = email },
Enabled = true
}
});
await sutProvider.Sut.SendTwoFactorEmailAsync(user);
await sutProvider.GetDependency<IMailService>()
.Received(1)
.SendTwoFactorEmailAsync(email, user.Email, token, IpAddress, deviceType.ToString(),
TwoFactorEmailPurpose.Login);
}
[Theory, BitAutoData]
public async Task SendNewDeviceVerificationEmailAsync_Success(SutProvider<TwoFactorEmailService> sutProvider, User user)
{
var email = user.Email.ToLowerInvariant();
var token = "thisisatokentocompare";
var IpAddress = "1.1.1.1";
var deviceType = DeviceType.Android;
var context = sutProvider.GetDependency<ICurrentContext>();
context.DeviceType = deviceType;
context.IpAddress = IpAddress;
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
userTwoFactorTokenProvider
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(true));
userTwoFactorTokenProvider
.GenerateAsync("otp:" + user.Email, Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(token));
var userManager = sutProvider.GetDependency<UserManager<User>>();
userManager.RegisterTokenProvider(TokenOptions.DefaultEmailProvider, userTwoFactorTokenProvider);
await sutProvider.Sut.SendNewDeviceVerificationEmailAsync(user);
await sutProvider.GetDependency<IMailService>()
.Received(1)
.SendTwoFactorEmailAsync(email, user.Email, token, IpAddress, deviceType.ToString(),
TwoFactorEmailPurpose.NewDeviceVerification);
}
[Theory, BitAutoData]
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderOnUser(SutProvider<TwoFactorEmailService> sutProvider, User user)
{
user.TwoFactorProviders = null;
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
}
[Theory, BitAutoData]
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderMetadataOnUser(SutProvider<TwoFactorEmailService> sutProvider, User user)
{
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
MetaData = null,
Enabled = true
}
});
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
}
[Theory, BitAutoData]
public async Task SendTwoFactorEmailAsync_ExceptionBecauseNoProviderEmailMetadataOnUser(SutProvider<TwoFactorEmailService> sutProvider, User user)
{
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["qweqwe"] = user.Email.ToLowerInvariant() },
Enabled = true
}
});
await Assert.ThrowsAsync<ArgumentNullException>("No email.", () => sutProvider.Sut.SendTwoFactorEmailAsync(user));
}
[Theory, BitAutoData]
public async Task SendNewDeviceVerificationEmailAsync_ExceptionBecauseUserNull(SutProvider<TwoFactorEmailService> sutProvider)
{
await Assert.ThrowsAsync<ArgumentNullException>(() => sutProvider.Sut.SendNewDeviceVerificationEmailAsync(null));
}
[Theory]
[BitAutoData(DeviceType.UnknownBrowser, "Unknown Browser")]
[BitAutoData(DeviceType.Android, "Android")]
public async Task SendTwoFactorEmailAsync_DeviceMatches(DeviceType deviceType, string deviceTypeName,
SutProvider<TwoFactorEmailService> sutProvider,
User user)
{
var email = user.Email.ToLowerInvariant();
var token = "thisisatokentocompare";
var IpAddress = "1.1.1.1";
var context = sutProvider.GetDependency<ICurrentContext>();
context.DeviceType = deviceType;
context.IpAddress = IpAddress;
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
userTwoFactorTokenProvider
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(true));
userTwoFactorTokenProvider
.GenerateAsync("TwoFactor", Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(token));
var userManager = sutProvider.GetDependency<UserManager<User>>();
userManager.RegisterTokenProvider(CoreHelpers.CustomProviderName(TwoFactorProviderType.Email), userTwoFactorTokenProvider);
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Email"] = email },
Enabled = true
}
});
await sutProvider.Sut.SendTwoFactorEmailAsync(user);
await sutProvider.GetDependency<IMailService>()
.Received(1)
.SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), deviceTypeName, TwoFactorEmailPurpose.Login);
}
[Theory, BitAutoData]
public async Task SendTwoFactorEmailAsync_NullDeviceTypeShouldSendUnkownBrowserType(SutProvider<TwoFactorEmailService> sutProvider, User user)
{
var email = user.Email.ToLowerInvariant();
var token = "thisisatokentocompare";
var IpAddress = "1.1.1.1";
var userTwoFactorTokenProvider = Substitute.For<IUserTwoFactorTokenProvider<User>>();
userTwoFactorTokenProvider
.CanGenerateTwoFactorTokenAsync(Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(true));
userTwoFactorTokenProvider
.GenerateAsync("TwoFactor", Arg.Any<UserManager<User>>(), user)
.Returns(Task.FromResult(token));
var context = Substitute.For<ICurrentContext>();
context.DeviceType = null;
context.IpAddress = IpAddress;
var userManager = sutProvider.GetDependency<UserManager<User>>();
userManager.RegisterTokenProvider(CoreHelpers.CustomProviderName(TwoFactorProviderType.Email), userTwoFactorTokenProvider);
user.SetTwoFactorProviders(new Dictionary<TwoFactorProviderType, TwoFactorProvider>
{
[TwoFactorProviderType.Email] = new TwoFactorProvider
{
MetaData = new Dictionary<string, object> { ["Email"] = email },
Enabled = true
}
});
await sutProvider.Sut.SendTwoFactorEmailAsync(user);
await sutProvider.GetDependency<IMailService>()
.Received(1)
.SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), "Unknown Browser", Arg.Any<TwoFactorEmailPurpose>());
}
// [Theory, BitAutoData]
// public async Task ResendNewDeviceVerificationEmail_UserNull_SendTwoFactorEmailAsyncNotCalled(
// SutProvider<UserService> sutProvider, string email, string secret)
// {
// sutProvider.GetDependency<IUserRepository>()
// .GetByEmailAsync(email)
// .Returns(null as User);
// await sutProvider.Sut.ResendNewDeviceVerificationEmail(email, secret);
// await sutProvider.GetDependency<IMailService>()
// .DidNotReceive()
// .SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<bool>());
// }
// [Theory, BitAutoData]
// public async Task ResendNewDeviceVerificationEmail_SecretNotValid_SendTwoFactorEmailAsyncNotCalled(
// SutProvider<UserService> sutProvider, string email, string secret)
// {
// sutProvider.GetDependency<IUserRepository>()
// .GetByEmailAsync(email)
// .Returns(null as User);
// await sutProvider.Sut.ResendNewDeviceVerificationEmail(email, secret);
// await sutProvider.GetDependency<IMailService>()
// .DidNotReceive()
// .SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<bool>());
// }
// [Theory, BitAutoData]
// public async Task ResendNewDeviceVerificationEmail_SendsToken_Success(User user)
// {
// // Arrange
// var testPassword = "test_password";
// SetupUserAndDevice(user, true);
// var sutProvider = new SutProvider<TwoFactorEmailService>();
// // Setup the fake password verification
// sutProvider
// .GetDependency<IUserPasswordStore<User>>()
// .GetPasswordHashAsync(user, Arg.Any<CancellationToken>())
// .Returns((ci) =>
// {
// return Task.FromResult("hashed_test_password");
// });
// sutProvider.GetDependency<IPasswordHasher<User>>()
// .VerifyHashedPassword(user, "hashed_test_password", testPassword)
// .Returns((ci) =>
// {
// return PasswordVerificationResult.Success;
// });
// sutProvider.GetDependency<IUserRepository>()
// .GetByEmailAsync(user.Email)
// .Returns(user);
// var context = sutProvider.GetDependency<ICurrentContext>();
// context.DeviceType = DeviceType.Android;
// context.IpAddress = "1.1.1.1";
// await sutProvider.Sut.ResendNewDeviceVerificationEmail(user.Email, testPassword);
// await sutProvider.GetDependency<IMailService>()
// .Received(1)
// .SendTwoFactorEmailAsync(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<bool>());
// }
}