345 lines
12 KiB
C#
345 lines
12 KiB
C#
using e_suite.API.Common.models;
|
|
using e_suite.Database.Core.Models;
|
|
using e_suite.Database.Core.Tables.UserManager;
|
|
using e_suite.Nuget.PasswordHasher;
|
|
using eSuite.Core.MailService;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Moq;
|
|
using NUnit.Framework;
|
|
using UserManager.UnitTests.Helpers;
|
|
|
|
namespace UserManager.UnitTests.UserManager;
|
|
|
|
[TestFixture]
|
|
public class LoginUnitTests : UserManagerTestBase<object>
|
|
{
|
|
[SetUp]
|
|
public override async Task Setup()
|
|
{
|
|
await base.Setup();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_UserNotFound_ReturnsFailed()
|
|
{
|
|
//Arrange
|
|
var login = new Login
|
|
{
|
|
Email = "fred@bloggs.com" //User does not exist in fake database.
|
|
};
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.Failed));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_VerifyHashedPasswordFails_ReturnsNull()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 15,
|
|
Email = "testuser@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = true
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = existingUser.Email,
|
|
Password = "testing"
|
|
};
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.Failed);
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
CustomPasswordHasherMock.Verify(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password), Times.Once);
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.Failed));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_VerifyHashedPasswordMatches_ReturnsSuccess()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 15,
|
|
Email = "testuser@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = true
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = existingUser.Email,
|
|
Password = "testing"
|
|
};
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.Success);
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
CustomPasswordHasherMock.Verify(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password), Times.Once);
|
|
CustomPasswordHasherMock.Verify(x => x.HashPassword(It.IsAny<IPassword>(), login.Password), Times.Never);
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.Success));
|
|
Assert.That(result.Token, Is.Not.Empty);
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_VerifyHashedPasswordRequestsRehash_ReturnsSuccessAndRehashesPassword()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 14,
|
|
Email = "testuser@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = true
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = existingUser.Email,
|
|
Password = "testing"
|
|
};
|
|
|
|
var newHashedPassword = "123456";
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.SuccessRehashNeeded);
|
|
CustomPasswordHasherMock.Setup(x => x.HashPassword(It.IsAny<IPassword>(), login.Password)).Returns(newHashedPassword);
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
CustomPasswordHasherMock.Verify(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password), Times.Once);
|
|
CustomPasswordHasherMock.Verify(x => x.HashPassword(It.IsAny<IPassword>(), login.Password), Times.Once);
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.Success));
|
|
Assert.That(result.Token, Is.Not.Empty);
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_EmailNotConfirmed_ReturnsError()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 16,
|
|
Email = "testuser2@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = false
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = existingUser.Email,
|
|
Password = "testing"
|
|
};
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.Success);
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.EmailNotConfirmed));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_RequestTfaDisable_ReturnsTwoFactorAuthenticationRemovalRequested()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 16,
|
|
Email = "testuser3@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = true,
|
|
UsingTwoFactorAuthentication = true,
|
|
FirstName = "Test3",
|
|
LastName = "User"
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = existingUser.Email,
|
|
Password = "testing",
|
|
RequestTfaRemoval = true
|
|
};
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.Success);
|
|
|
|
MailRequest actualMailRequest = null!;
|
|
|
|
MailServiceMock.Setup(x => x.RequestEMailAsync(It.IsAny<MailRequest>(), It.IsAny<CancellationToken>()))
|
|
.Callback<MailRequest, CancellationToken>((mailRequest, cancellationToken) => { actualMailRequest = mailRequest; });
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert that the new row was added to the database correctly.
|
|
var emailUserAction = UserManagerRepository.EmailUserActions.SingleOrDefault(x => x.User.Email == login.Email);
|
|
|
|
Assert.That(emailUserAction, Is.Not.Null);
|
|
Assert.That(emailUserAction?.EmailActionType, Is.EqualTo(EmailUserActionType.DisableAuthenticator));
|
|
Assert.That(emailUserAction?.User.Email, Is.EqualTo(login.Email));
|
|
Assert.That(emailUserAction?.Token, Is.Not.Empty);
|
|
|
|
//Assert that the e-mail request was sent.
|
|
MailServiceMock.Verify(x => x.RequestEMailAsync(It.IsAny<MailRequest>(), It.IsAny<CancellationToken>()), Times.Once);
|
|
Assert.That(actualMailRequest, Is.Not.Null);
|
|
Assert.That(actualMailRequest.EmailType, Is.EqualTo(MailType.DisableAuthenticator));
|
|
Assert.That(actualMailRequest.To.Count, Is.EqualTo(1));
|
|
Assert.That(actualMailRequest.To[0].DisplayName, Is.EqualTo(existingUser.DisplayName));
|
|
Assert.That(actualMailRequest.To[0].Email, Is.EqualTo(login.Email));
|
|
Assert.That(actualMailRequest.Parameters.Count, Is.EqualTo(1));
|
|
Assert.That(actualMailRequest.Parameters["url"], Is.Not.Empty);
|
|
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.TwoFactorAuthenticationRemovalRequested));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_TfaEnabledButCodeNotProvided_ReturnsTwoFactorAuthenticationCodeRequired()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 16,
|
|
Email = "testuser3@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = true,
|
|
UsingTwoFactorAuthentication = true,
|
|
FirstName = "Test3",
|
|
LastName = "User"
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = existingUser.Email,
|
|
Password = "testing",
|
|
RequestTfaRemoval = false
|
|
};
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.Success);
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.TwoFactorAuthenticationCodeRequired));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_TfaEnabledButCodeIncorrect_ReturnsTwoFactorAuthenticationCodeIncorrect()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 16,
|
|
Email = "testuser3@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = true,
|
|
UsingTwoFactorAuthentication = true,
|
|
FirstName = "Test3",
|
|
LastName = "User"
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = existingUser.Email,
|
|
Password = "testing",
|
|
RequestTfaRemoval = false,
|
|
SecurityCode = "123456"
|
|
};
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.Success);
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
TwoFactorAuthenticatorMock.Verify(x => x.ValidateTwoFactorPIN(It.IsAny<string>(), login.SecurityCode, false), Times.Once);
|
|
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.TwoFactorAuthenticationCodeIncorrect));
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_TfaEnabledAndCodeCorrect_ReturnsSuccess()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 16,
|
|
Email = "testuser3@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = true,
|
|
UsingTwoFactorAuthentication = true,
|
|
FirstName = "Test3",
|
|
LastName = "User"
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = "testuser3@sun-strategy.com", //User exists in fake database. But email is not confirmed.
|
|
Password = "testing",
|
|
RequestTfaRemoval = false,
|
|
SecurityCode = "123456"
|
|
};
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.Success);
|
|
TwoFactorAuthenticatorMock.Setup(x => x.ValidateTwoFactorPIN(It.IsAny<string>(), login.SecurityCode, It.IsAny<bool>())).Returns(true);
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.Success));
|
|
Assert.That(result.Token, Is.Not.Empty);
|
|
}
|
|
|
|
[Test]
|
|
public async Task Login_AccountIsNotActive_ReturnsFailed()
|
|
{
|
|
//Arrange
|
|
var existingUser = new User
|
|
{
|
|
Id = 15,
|
|
Email = "testuser@sun-strategy.com",
|
|
Password = "testing",
|
|
EmailConfirmed = true,
|
|
Active = false
|
|
};
|
|
await UserManagerRepository.AddUser(AuditUserDetails, existingUser, default);
|
|
|
|
var login = new Login
|
|
{
|
|
Email = existingUser.Email,
|
|
Password = "testing"
|
|
};
|
|
|
|
CustomPasswordHasherMock.Setup(x => x.VerifyHashedPassword(It.IsAny<IPassword>(), It.IsAny<string>(), login.Password)).Returns(PasswordVerificationResult.Success);
|
|
|
|
//Act
|
|
var result = await UserManager.Login(login);
|
|
|
|
//Assert
|
|
Assert.That(result.Result, Is.EqualTo(LoginResult.Failed));
|
|
Assert.That(result.Token, Is.Empty);
|
|
}
|
|
} |