diff --git a/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs b/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs index ccaa758b..86b26ccd 100644 --- a/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs +++ b/ProjectLighthouse.Tests.GameApiTests/DatabaseTests.cs @@ -23,8 +23,6 @@ namespace ProjectLighthouse.Tests.GameApiTests Assert.NotNull(userB); await database.RemoveUser(userA); // Only remove userA since userA and userB are the same user - - await database.SaveChangesAsync(); } } } \ No newline at end of file diff --git a/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs new file mode 100644 index 00000000..ce7f7f74 --- /dev/null +++ b/ProjectLighthouse.Tests.WebsiteTests/AuthenticationTests.cs @@ -0,0 +1,133 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Tests; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.EntityFrameworkCore; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; +using Xunit; + +namespace ProjectLighthouse.Tests.WebsiteTests +{ + public class AuthenticationTests : IDisposable + { + public readonly IWebHost WebHost = new WebHostBuilder().UseKestrel().UseStartup().UseWebRoot("StaticFiles").Build(); + public readonly string BaseAddress; + + public readonly IWebDriver Driver = new ChromeDriver(); + + public AuthenticationTests() + { + this.WebHost.Start(); + + IServerAddressesFeature? serverAddressesFeature = WebHost.ServerFeatures.Get(); + if (serverAddressesFeature == null) throw new ArgumentNullException(); + + this.BaseAddress = serverAddressesFeature.Addresses.First(); + } + + [DatabaseFact] + public async Task ShouldLoginWithPassword() + { + await using Database database = new(); + Random random = new(); + + string password = HashHelper.Sha256Hash(HashHelper.GenerateRandomBytes(64).ToArray()); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash(HashHelper.Sha256Hash(password))); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login"); + + this.Driver.FindElement(By.Id("text")).SendKeys(user.Username); + this.Driver.FindElement(By.Id("password")).SendKeys(password); + + this.Driver.FindElement(By.Id("submit")).Click(); + + WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId); + Assert.NotNull(webToken); + + await database.RemoveUser(user); + } + + [DatabaseFact] + public async Task ShouldNotLoginWithNoPassword() + { + await using Database database = new(); + Random random = new(); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("just like the hindenberg,")); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login"); + + this.Driver.FindElement(By.Id("text")).SendKeys(user.Username); + + this.Driver.FindElement(By.Id("submit")).Click(); + + WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId); + Assert.Null(webToken); + + await database.RemoveUser(user); + } + + [DatabaseFact] + public async Task ShouldNotLoginWithWrongPassword() + { + await using Database database = new(); + Random random = new(); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure")); + + this.Driver.Navigate().GoToUrl(this.BaseAddress + "/login"); + + this.Driver.FindElement(By.Id("text")).SendKeys(user.Username); + this.Driver.FindElement(By.Id("password")).SendKeys("nah man"); + + this.Driver.FindElement(By.Id("submit")).Click(); + + WebToken? webToken = await database.WebTokens.FirstOrDefaultAsync(t => t.UserId == user.UserId); + Assert.Null(webToken); + + await database.RemoveUser(user); + } + + [DatabaseFact] + public async Task ShouldLoginWithInjectedCookie() + { + const string loggedInAsUsernameTextXPath = "/html/body/div/div/div/p[1]/b"; + + await using Database database = new(); + Random random = new(); + User user = await database.CreateUser($"unitTestUser{random.Next()}", HashHelper.BCryptHash("i'm an engineering failure")); + + WebToken webToken = new() + { + UserId = user.UserId, + UserToken = HashHelper.GenerateAuthToken(), + }; + + database.WebTokens.Add(webToken); + await database.SaveChangesAsync(); + + INavigation navigation = this.Driver.Navigate(); + + navigation.GoToUrl(this.BaseAddress + "/"); + this.Driver.Manage().Cookies.AddCookie(new Cookie("LighthouseToken", webToken.UserToken)); + Assert.Throws(() => this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath))); + navigation.Refresh(); + Assert.True(this.Driver.FindElement(By.XPath(loggedInAsUsernameTextXPath)).Text == user.Username); + + await database.RemoveUser(user); + } + + public void Dispose() + { + this.Driver.Close(); + this.Driver.Dispose(); + this.WebHost.Dispose(); + + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj new file mode 100644 index 00000000..93e88c08 --- /dev/null +++ b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj @@ -0,0 +1,36 @@ + + + + net6.0 + enable + + false + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/ProjectLighthouse.Tests/LighthouseServerTest.cs b/ProjectLighthouse.Tests/LighthouseServerTest.cs index 0a02da01..4e79d578 100644 --- a/ProjectLighthouse.Tests/LighthouseServerTest.cs +++ b/ProjectLighthouse.Tests/LighthouseServerTest.cs @@ -22,7 +22,6 @@ namespace LBPUnion.ProjectLighthouse.Tests public LighthouseServerTest() { this.Server = new TestServer(new WebHostBuilder().UseStartup()); - this.Client = this.Server.CreateClient(); } public async Task AuthenticateResponse(int number = -1, bool createUser = true) diff --git a/ProjectLighthouse.sln b/ProjectLighthouse.sln index 745241a4..c1ae0363 100644 --- a/ProjectLighthouse.sln +++ b/ProjectLighthouse.sln @@ -8,6 +8,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D360C08E EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests.GameApiTests", "ProjectLighthouse.Tests.GameApiTests\ProjectLighthouse.Tests.GameApiTests.csproj", "{200EED99-FE3E-45C6-A51E-76ED9819CA2B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectLighthouse.Tests.WebsiteTests", "ProjectLighthouse.Tests.WebsiteTests\ProjectLighthouse.Tests.WebsiteTests.csproj", "{CF65EB5B-5364-4D2A-8639-F147A67F08E7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,9 +28,14 @@ Global {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {200EED99-FE3E-45C6-A51E-76ED9819CA2B}.Release|Any CPU.Build.0 = Release|Any CPU + {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF65EB5B-5364-4D2A-8639-F147A67F08E7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {AFC74569-B289-4ACC-B21C-313A3A62C017} = {D360C08E-EA47-43AC-A566-FDF413442980} {200EED99-FE3E-45C6-A51E-76ED9819CA2B} = {D360C08E-EA47-43AC-A566-FDF413442980} + {CF65EB5B-5364-4D2A-8639-F147A67F08E7} = {D360C08E-EA47-43AC-A566-FDF413442980} EndGlobalSection EndGlobal diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings index 385c8365..7bbd6e1f 100644 --- a/ProjectLighthouse.sln.DotSettings +++ b/ProjectLighthouse.sln.DotSettings @@ -89,6 +89,7 @@ True True True + True True True True