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 @@
+