test(integration): update auth tests for encrypted login
This commit is contained in:
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Integration tests for authentication flow.
|
||||
/// Integration tests for authentication flow with encrypted login.
|
||||
/// Note: These tests require a running test server with UseFakeAuth=true
|
||||
/// </summary>
|
||||
public class AuthenticationTests : IClassFixture<TestWebApplicationFactory>
|
||||
@@ -26,17 +29,56 @@ public class AuthenticationTests : IClassFixture<TestWebApplicationFactory>
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches the server's public key and encrypts login credentials.
|
||||
/// </summary>
|
||||
private async Task<EncryptedLoginRequest> EncryptLoginAsync(HttpClient client, string username, string password)
|
||||
{
|
||||
// Step 1: Fetch the public key from the server
|
||||
var publicKeyResponse = await client.GetFromJsonAsync<PublicKeyResponse>("/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>();
|
||||
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<UserInfo>();
|
||||
user.ShouldNotBeNull();
|
||||
user.Username.ShouldBe("testuser");
|
||||
var loginResult = await loginResponse.Content.ReadFromJsonAsync<LoginResultModel>();
|
||||
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<TestWebApplicationFactory>
|
||||
[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<LoginResultModel>();
|
||||
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<TestWebApplicationFactory>
|
||||
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<LoginResultModel>();
|
||||
result.ShouldNotBeNull();
|
||||
result.Success.ShouldBeFalse();
|
||||
result.ErrorMessage.ShouldBe("Invalid encrypted payload");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\JdeScoping.Api\JdeScoping.Api.csproj" />
|
||||
<ProjectReference Include="..\..\src\JdeScoping.Core\JdeScoping.Core.csproj" />
|
||||
<ProjectReference Include="..\..\src\JdeScoping.Host\JdeScoping.Host.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user