using System.Security.Claims; using Microsoft.AspNetCore.Http; using ZB.MOM.WW.Auth.AspNetCore; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services; namespace ZB.MOM.WW.ScadaBridge.Security; /// /// HTTP-backed (Phase 3): resolves the audit /// Actor from the authenticated principal on the ambient /// . Used by the user-facing /// inbound API audit path so a cookie/LDAP-authenticated request records the /// real user as AuditEvent.Actor. /// /// /// The username is sourced from the canonical /// claim (= , /// minted by and by the cookie login path), falling /// back to (which /// pins to via its /// token-validation NameClaimType). /// When there is no ambient request, the principal is unauthenticated, or no /// usable name claim is present, returns null so /// the caller keeps its existing actor/fallback — an unauthenticated principal is /// never echoed back as an actor. /// public sealed class HttpAuditActorAccessor : IAuditActorAccessor { private readonly IHttpContextAccessor _httpContextAccessor; /// Initializes a new instance of . /// Accessor for the ambient HTTP context. public HttpAuditActorAccessor(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); } /// public string? CurrentActor { get { var user = _httpContextAccessor.HttpContext?.User; if (user?.Identity is not { IsAuthenticated: true }) { // No ambient request, or the principal is unauthenticated — never // echo an unauthenticated identity back as an actor. return null; } // Prefer the canonical username claim (the value JwtTokenService and // the cookie login path mint); fall back to Identity.Name (pinned to // ZbClaimTypes.Name by JwtTokenService.NameClaimType). var username = user.FindFirst(JwtTokenService.UsernameClaimType)?.Value; if (!string.IsNullOrWhiteSpace(username)) { return username; } var name = user.Identity?.Name; return string.IsNullOrWhiteSpace(name) ? null : name; } } }