using System.Security.Claims; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using ZB.MOM.WW.Auth.AspNetCore; using ZB.MOM.WW.MxGateway.Server.Configuration; namespace ZB.MOM.WW.MxGateway.Server.Dashboard; /// /// Authentication handler used ONLY when MxGateway:Dashboard:DisableLogin is true. /// Registered under the dashboard cookie scheme name /// (), it authenticates /// EVERY request as the configured dev user with both dashboard roles — no credential check, /// no cookie, no LDAP bind. The minted principal mirrors the shape the real login /// () produces, so policies and the UI cannot tell it /// apart. DEV/TEST ONLY; never enable in production. /// public sealed class DashboardAutoLoginAuthenticationHandler : AuthenticationHandler, IAuthenticationSignInHandler { /// Username used when AutoLoginUser is null or blank. public const string DefaultUser = "multi-role"; private readonly string _user; /// Initializes the handler with scheme plumbing and the dashboard options. /// The per-scheme authentication options monitor. /// The logger factory the base handler uses. /// The URL encoder the base handler uses. /// Gateway options carrying the dashboard auto-login user. public DashboardAutoLoginAuthenticationHandler( IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, IOptions gatewayOptions) : base(options, logger, encoder) { string? configured = gatewayOptions.Value.Dashboard.AutoLoginUser; _user = string.IsNullOrWhiteSpace(configured) ? DefaultUser : configured.Trim(); } /// No-op: auto-login writes no cookie, so a sign-in has nothing to persist. /// Ignored. /// Ignored. /// A completed task. public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties) => Task.CompletedTask; /// No-op: there is no auth cookie to clear; the next request re-authenticates. /// Ignored. /// A completed task. public Task SignOutAsync(AuthenticationProperties? properties) => Task.CompletedTask; /// protected override Task HandleAuthenticateAsync() { ClaimsPrincipal principal = CreatePrincipal(_user); AuthenticationTicket ticket = new(principal, Scheme.Name); return Task.FromResult(AuthenticateResult.Success(ticket)); } /// /// Builds the multi-role dev principal. Null/blank falls back to /// . The authorization-relevant claim shape mirrors /// ; LDAP group claims (LdapGroupClaimType) are /// intentionally omitted because auto-login has no real LDAP context. /// /// The configured auto-login username (may be null/blank). /// An authenticated principal holding both dashboard roles. internal static ClaimsPrincipal CreatePrincipal(string? user) { string name = string.IsNullOrWhiteSpace(user) ? DefaultUser : user.Trim(); // LdapGroupClaimType claims are omitted — no LDAP groups exist in the auto-login context. Claim[] claims = [ new Claim(ClaimTypes.NameIdentifier, name), new Claim(ZbClaimTypes.Username, name), new Claim(ZbClaimTypes.Name, name), new Claim(ZbClaimTypes.DisplayName, name), new Claim(ZbClaimTypes.Role, DashboardRoles.Admin), new Claim(ZbClaimTypes.Role, DashboardRoles.Viewer), ]; ClaimsIdentity identity = new( claims, DashboardAuthenticationDefaults.AuthenticationScheme, ZbClaimTypes.Name, ZbClaimTypes.Role); return new ClaimsPrincipal(identity); } }