using System.Security.Claims; using System.Text.Encodings.Web; using System.Text.Json; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace WorkClub.Tests.Integration.Infrastructure; public class TestAuthHandler : AuthenticationHandler { public TestAuthHandler( IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder) { } protected override Task HandleAuthenticateAsync() { // Support explicit unauthenticated test scenarios var unauthenticatedHeader = Context.Request.Headers["X-Test-Unauthenticated"].ToString(); if (!string.IsNullOrEmpty(unauthenticatedHeader) && unauthenticatedHeader.Equals("true", StringComparison.OrdinalIgnoreCase)) { return Task.FromResult(AuthenticateResult.NoResult()); } var clubsClaim = Context.Request.Headers["X-Test-Clubs"].ToString(); var emailClaim = Context.Request.Headers["X-Test-Email"].ToString(); var userIdClaim = Context.Request.Headers["X-Test-UserId"].ToString(); var clubRolesJson = Context.Request.Headers["X-Test-ClubRoles"].ToString(); // If no test auth headers are present, return NoResult (unauthenticated) if (string.IsNullOrEmpty(emailClaim) && string.IsNullOrEmpty(userIdClaim) && string.IsNullOrEmpty(clubsClaim)) { return Task.FromResult(AuthenticateResult.NoResult()); } var resolvedEmail = string.IsNullOrEmpty(emailClaim) ? "test@test.com" : emailClaim; var claims = new List { new Claim(ClaimTypes.NameIdentifier, "test-user"), new Claim("sub", string.IsNullOrEmpty(userIdClaim) ? Guid.NewGuid().ToString() : userIdClaim), new Claim(ClaimTypes.Email, resolvedEmail), new Claim("preferred_username", resolvedEmail), }; if (!string.IsNullOrEmpty(clubsClaim)) { claims.Add(new Claim("clubs", clubsClaim)); } // Parse tenant-specific role from X-Test-ClubRoles if provided if (!string.IsNullOrEmpty(clubRolesJson)) { var tenantId = Context.Request.Headers["X-Tenant-Id"].ToString(); if (!string.IsNullOrEmpty(tenantId)) { try { var clubRoles = JsonSerializer.Deserialize>(clubRolesJson); if (clubRoles != null) { var tenantRole = clubRoles.FirstOrDefault(kvp => kvp.Key.Equals(tenantId, StringComparison.OrdinalIgnoreCase)).Value; if (!string.IsNullOrEmpty(tenantRole)) { claims.Add(new Claim(ClaimTypes.Role, tenantRole)); } } } catch (JsonException) { // Invalid JSON in X-Test-ClubRoles header, proceed without role claim } } } var identity = new ClaimsIdentity(claims, "Test"); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, "Test"); return Task.FromResult(AuthenticateResult.Success(ticket)); } }