using System.Security.Cryptography; using System.Text; using System.Text.Json; using JdeScoping.Client.Services; using JdeScoping.Core.Models.Auth; using Microsoft.AspNetCore.Mvc.Testing; using Shouldly; namespace JdeScoping.Api.IntegrationTests.ClientIntegration; public class AuthApiClientIntegrationTests : ClientIntegrationTestBase { public AuthApiClientIntegrationTests(TestWebApplicationFactory factory) : base(factory) { } [Fact] public async Task GetPublicKeyAsync_ReturnsValidPublicKey() { // Act var result = await AuthClient.GetPublicKeyAsync(); // Assert result.IsSuccess.ShouldBeTrue(); result.Value.PublicKeyPem.ShouldStartWith("-----BEGIN PUBLIC KEY-----"); } [Fact] public async Task LoginAsync_WithValidCredentials_ReturnsSuccess() { // Arrange - get public key and encrypt credentials var publicKeyResult = await AuthClient.GetPublicKeyAsync(); publicKeyResult.IsSuccess.ShouldBeTrue(); var loginModel = new LoginModel { Username = "testuser", Password = "testpass" }; var json = JsonSerializer.Serialize(loginModel); var plaintext = Encoding.UTF8.GetBytes(json); using var rsa = RSA.Create(); rsa.ImportFromPem(publicKeyResult.Value.PublicKeyPem); var ciphertext = rsa.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256); var encryptedRequest = new EncryptedLoginRequest(Convert.ToBase64String(ciphertext)); // Act var result = await AuthClient.LoginAsync(encryptedRequest); // Assert result.IsSuccess.ShouldBeTrue(); result.Value.Success.ShouldBeTrue(); result.Value.User.ShouldNotBeNull(); result.Value.User.Username.ShouldBe("testuser"); } [Fact] public async Task GetCurrentUserAsync_AfterLogin_ReturnsUserInfo() { // Arrange await LoginAsync(); // Act var result = await AuthClient.GetCurrentUserAsync(); // Assert result.IsSuccess.ShouldBeTrue(); result.Value.Username.ShouldBe("testuser"); } [Fact] public async Task GetCurrentUserAsync_WithoutAuth_ReturnsUnauthorized() { // Arrange - use fresh client without cookies var freshClient = new AuthApiClient(CreateFreshClient()); // Act var result = await freshClient.GetCurrentUserAsync(); // Assert result.IsUnauthorized.ShouldBeTrue(); } [Fact] public async Task LogoutAsync_AfterLogin_InvalidatesSession() { // Arrange - create fresh client for this test to avoid affecting other tests var client = Factory.CreateClient(new WebApplicationFactoryClientOptions { HandleCookies = true, AllowAutoRedirect = false }); var authClient = new AuthApiClient(client); // Login first var publicKeyResult = await authClient.GetPublicKeyAsync(); var loginModel = new LoginModel { Username = "testuser", Password = "testpass" }; var json = JsonSerializer.Serialize(loginModel); using var rsa = RSA.Create(); rsa.ImportFromPem(publicKeyResult.Value.PublicKeyPem); var ciphertext = rsa.Encrypt(Encoding.UTF8.GetBytes(json), RSAEncryptionPadding.OaepSHA256); await authClient.LoginAsync(new EncryptedLoginRequest(Convert.ToBase64String(ciphertext))); // Verify login worked var beforeLogout = await authClient.GetCurrentUserAsync(); beforeLogout.IsSuccess.ShouldBeTrue(); // Act - call logout (server returns 200 OK with empty body) await authClient.LogoutAsync(); // Assert - verify session is invalidated (me endpoint should return unauthorized) var meResult = await authClient.GetCurrentUserAsync(); meResult.IsUnauthorized.ShouldBeTrue(); } }