From 3cb73eb09fab32767b19580bf040308461300539 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Sat, 3 Jan 2026 08:51:39 -0500 Subject: [PATCH] test(integration): update auth tests for encrypted login --- .../AuthenticationTests.cs | 85 ++++++++++++++++--- .../JdeScoping.Api.IntegrationTests.csproj | 1 + 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/NEW/tests/JdeScoping.Api.IntegrationTests/AuthenticationTests.cs b/NEW/tests/JdeScoping.Api.IntegrationTests/AuthenticationTests.cs index 3f4bd23..ed85cd1 100644 --- a/NEW/tests/JdeScoping.Api.IntegrationTests/AuthenticationTests.cs +++ b/NEW/tests/JdeScoping.Api.IntegrationTests/AuthenticationTests.cs @@ -1,14 +1,17 @@ using System.Net; using System.Net.Http.Json; -using JdeScoping.Api.Models; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; using JdeScoping.Core.Models; +using JdeScoping.Core.Models.Auth; using Microsoft.AspNetCore.Mvc.Testing; using Shouldly; namespace JdeScoping.Api.IntegrationTests; /// -/// Integration tests for authentication flow. +/// Integration tests for authentication flow with encrypted login. /// Note: These tests require a running test server with UseFakeAuth=true /// public class AuthenticationTests : IClassFixture @@ -26,17 +29,56 @@ public class AuthenticationTests : IClassFixture }); } + /// + /// Fetches the server's public key and encrypts login credentials. + /// + private async Task EncryptLoginAsync(HttpClient client, string username, string password) + { + // Step 1: Fetch the public key from the server + var publicKeyResponse = await client.GetFromJsonAsync("/api/auth/public-key"); + publicKeyResponse.ShouldNotBeNull(); + publicKeyResponse.PublicKeyPem.ShouldStartWith("-----BEGIN PUBLIC KEY-----"); + + // Step 2: Create login model and serialize to JSON + var loginModel = new LoginModel { Username = username, Password = password }; + var json = JsonSerializer.Serialize(loginModel); + var plaintext = Encoding.UTF8.GetBytes(json); + + // Step 3: Import the public key and encrypt + using var rsa = RSA.Create(); + rsa.ImportFromPem(publicKeyResponse.PublicKeyPem); + var ciphertext = rsa.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256); + + return new EncryptedLoginRequest(Convert.ToBase64String(ciphertext)); + } + + [Fact] + public async Task GetPublicKey_ReturnsValidPemKey() + { + // Act + var response = await _client.GetAsync("/api/auth/public-key"); + + // Assert + response.StatusCode.ShouldBe(HttpStatusCode.OK); + var publicKeyResponse = await response.Content.ReadFromJsonAsync(); + publicKeyResponse.ShouldNotBeNull(); + publicKeyResponse.PublicKeyPem.ShouldStartWith("-----BEGIN PUBLIC KEY-----"); + publicKeyResponse.PublicKeyPem.ShouldContain("-----END PUBLIC KEY-----"); + } + [Fact] public async Task FullLoginLogoutFlow_WithCookies() { - // Step 1: Login - var loginRequest = new LoginRequest { Username = "testuser", Password = "testpass" }; - var loginResponse = await _client.PostAsJsonAsync("/api/auth/login", loginRequest); + // Step 1: Login with encrypted credentials + var encryptedRequest = await EncryptLoginAsync(_client, "testuser", "testpass"); + var loginResponse = await _client.PostAsJsonAsync("/api/auth/login", encryptedRequest); loginResponse.StatusCode.ShouldBe(HttpStatusCode.OK); - var user = await loginResponse.Content.ReadFromJsonAsync(); - user.ShouldNotBeNull(); - user.Username.ShouldBe("testuser"); + var loginResult = await loginResponse.Content.ReadFromJsonAsync(); + loginResult.ShouldNotBeNull(); + loginResult.Success.ShouldBeTrue(); + loginResult.User.ShouldNotBeNull(); + loginResult.User.Username.ShouldBe("testuser"); // Step 2: Verify we can access protected endpoint var meResponse = await _client.GetAsync("/api/auth/me"); @@ -76,11 +118,15 @@ public class AuthenticationTests : IClassFixture [Fact] public async Task ProtectedEndpoints_Work_WithAuthCookie() { - // Login first - var loginRequest = new LoginRequest { Username = "testuser", Password = "testpass" }; - var loginResponse = await _client.PostAsJsonAsync("/api/auth/login", loginRequest); + // Login first with encrypted credentials + var encryptedRequest = await EncryptLoginAsync(_client, "testuser", "testpass"); + var loginResponse = await _client.PostAsJsonAsync("/api/auth/login", encryptedRequest); loginResponse.StatusCode.ShouldBe(HttpStatusCode.OK); + var loginResult = await loginResponse.Content.ReadFromJsonAsync(); + loginResult.ShouldNotBeNull(); + loginResult.Success.ShouldBeTrue(); + // Now search endpoint should work var searchResponse = await _client.GetAsync("/api/search"); searchResponse.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -109,4 +155,21 @@ public class AuthenticationTests : IClassFixture var operatorsResponse = await freshClient.GetAsync("/api/lookup/operators?q=test"); operatorsResponse.StatusCode.ShouldBe(HttpStatusCode.OK); } + + [Fact] + public async Task Login_WithInvalidEncryptedData_ReturnsBadRequest() + { + // Arrange - send invalid encrypted data + var invalidRequest = new EncryptedLoginRequest("not-valid-base64!!!"); + + // Act + var response = await _client.PostAsJsonAsync("/api/auth/login", invalidRequest); + + // Assert + response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); + var result = await response.Content.ReadFromJsonAsync(); + result.ShouldNotBeNull(); + result.Success.ShouldBeFalse(); + result.ErrorMessage.ShouldBe("Invalid encrypted payload"); + } } diff --git a/NEW/tests/JdeScoping.Api.IntegrationTests/JdeScoping.Api.IntegrationTests.csproj b/NEW/tests/JdeScoping.Api.IntegrationTests/JdeScoping.Api.IntegrationTests.csproj index b8f3722..549a2a3 100644 --- a/NEW/tests/JdeScoping.Api.IntegrationTests/JdeScoping.Api.IntegrationTests.csproj +++ b/NEW/tests/JdeScoping.Api.IntegrationTests/JdeScoping.Api.IntegrationTests.csproj @@ -10,6 +10,7 @@ +