Files
ScadaBridge/src/ScadaLink.CentralUI/Auth/CookieAuthenticationStateProvider.cs
T
Joseph Doherty d38356efdb Phase 1 WP-11–22: Host infrastructure, Blazor Server UI, and integration tests
Host infrastructure (WP-11–17):
- StartupValidator with 19 validation rules
- /health/ready endpoint with DB + Akka health checks
- Akka.NET bootstrap via AkkaHostedService (HOCON config, cluster, remoting, SBR)
- Serilog with SiteId/NodeHostname/NodeRole enrichment
- DeadLetterMonitorActor with count tracking
- CoordinatedShutdown wiring (no Environment.Exit)
- Windows Service support (UseWindowsService)

Central UI (WP-18–21):
- Blazor Server shell with Bootstrap 5, role-aware NavMenu
- Login/logout flow (LDAP auth → JWT → HTTP-only cookie)
- CookieAuthenticationStateProvider with idle timeout
- LDAP group mapping CRUD page (Admin role)
- Route guards with Authorize attributes per role
- SignalR reconnection overlay for failover

Integration tests (WP-22):
- Startup validation, auth flow, audit transactions, readiness gating
186 tests pass (1 skipped: LDAP integration), zero warnings.
2026-03-16 19:50:59 -04:00

57 lines
1.9 KiB
C#

using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Http;
using ScadaLink.Security;
namespace ScadaLink.CentralUI.Auth;
/// <summary>
/// Reads the JWT from an HTTP-only cookie and creates a ClaimsPrincipal for Blazor Server.
/// This bridges cookie-based auth (set by the login endpoint) with Blazor's auth state.
/// </summary>
public class CookieAuthenticationStateProvider : ServerAuthenticationStateProvider
{
public const string AuthCookieName = "ScadaLink.Auth";
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly JwtTokenService _jwtTokenService;
public CookieAuthenticationStateProvider(
IHttpContextAccessor httpContextAccessor,
JwtTokenService jwtTokenService)
{
_httpContextAccessor = httpContextAccessor;
_jwtTokenService = jwtTokenService;
}
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null)
{
return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
}
var token = httpContext.Request.Cookies[AuthCookieName];
if (string.IsNullOrEmpty(token))
{
return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
}
var principal = _jwtTokenService.ValidateToken(token);
if (principal == null)
{
return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
}
// Check idle timeout
if (_jwtTokenService.IsIdleTimedOut(principal))
{
return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
}
return Task.FromResult(new AuthenticationState(principal));
}
}