using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.Auth.Abstractions.Roles;
using ZB.MOM.WW.Auth.AspNetCore;
using ZB.MOM.WW.MxGateway.Server.Configuration;
using ZB.MOM.WW.MxGateway.Server.Security.Audit;
namespace ZB.MOM.WW.MxGateway.Server.Dashboard;
///
/// Extension methods for configuring the gateway dashboard services.
///
public static class DashboardServiceCollectionExtensions
{
///
/// Registers all dashboard services, authentication, and Razor components.
///
/// Service collection to register services.
///
/// Application configuration, used to bind the shared LDAP provider's options
/// from the MxGateway:Ldap section.
///
public static IServiceCollection AddGatewayDashboard(
this IServiceCollection services,
IConfiguration configuration)
{
// Dashboard logins delegate bind/search to the shared ZB.MOM.WW.Auth.Ldap
// provider. Its LdapOptions bind straight from MxGateway:Ldap (the gateway's
// LdapOptions field names match the shared options: Transport / AllowInsecure /
// SearchBase / ServiceAccount* / *Attribute). AddZbLdapAuth also adds a
// ValidateOnStart() so an insecure-transport misconfiguration fails fast at boot.
services.AddZbLdapAuth(configuration, "MxGateway:Ldap");
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton, DashboardGroupRoleMapper>();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddScoped();
services.AddScoped();
services.AddSingleton();
services.AddHostedService();
services.AddHostedService();
services.AddHttpContextAccessor();
services.AddSingleton();
services.AddAntiforgery();
services.AddCascadingAuthenticationState();
services.AddRazorComponents()
.AddInteractiveServerComponents();
services.AddSignalR();
services
.AddAuthentication(DashboardAuthenticationDefaults.AuthenticationScheme)
.AddCookie(DashboardAuthenticationDefaults.AuthenticationScheme, cookieOptions =>
{
// Hardened defaults (HttpOnly, SameSite=Strict, SecurePolicy, SlidingExpiration,
// ExpireTimeSpan) via the shared ZbCookieDefaults.Apply. requireHttps is set to
// its default (true / Always) here and overridden per-environment by the
// PostConfigure below; the 8-hour idle timeout is preserved (not the 30-min default).
ZbCookieDefaults.Apply(cookieOptions, requireHttps: true, idleTimeout: TimeSpan.FromHours(8));
// Cookie name, path, and redirect paths are MxGateway-specific — set after Apply
// so they are never overwritten by the shared helper (Apply intentionally skips name).
// This is the canonical default; it is overridden per-environment from
// DashboardOptions.CookieName by the PostConfigure below.
cookieOptions.Cookie.Name = DashboardAuthenticationDefaults.CookieName;
cookieOptions.Cookie.Path = "/";
cookieOptions.LoginPath = "/login";
cookieOptions.LogoutPath = "/logout";
cookieOptions.AccessDeniedPath = "/denied";
})
.AddScheme(
DashboardAuthenticationDefaults.HubAuthenticationScheme,
_ => { });
// Honour DashboardOptions.RequireHttpsCookie (default true / Always; set false for dev
// HTTP deployments → SameAsRequest) and the optional per-environment cookie-name
// override. Both run after the inline AddCookie config above, so they win.
services.AddOptions(DashboardAuthenticationDefaults.AuthenticationScheme)
.Configure>((cookieOptions, gatewayOptions) =>
{
cookieOptions.Cookie.SecurePolicy = gatewayOptions.Value.Dashboard.RequireHttpsCookie
? CookieSecurePolicy.Always
: CookieSecurePolicy.SameAsRequest;
// Config-driven cookie name (MxGateway:Dashboard:CookieName). Null/blank keeps
// the canonical default set above, so a misconfiguration cannot unname the cookie.
var cookieName = gatewayOptions.Value.Dashboard.CookieName;
if (!string.IsNullOrWhiteSpace(cookieName))
{
cookieOptions.Cookie.Name = cookieName;
}
});
services.AddAuthorization(authorization =>
{
authorization.AddPolicy(
DashboardAuthenticationDefaults.ViewerPolicy,
policy => policy.AddRequirements(DashboardAuthorizationRequirement.AnyDashboardRole));
authorization.AddPolicy(
DashboardAuthenticationDefaults.AdminPolicy,
policy => policy.AddRequirements(DashboardAuthorizationRequirement.AdminOnly));
authorization.AddPolicy(
DashboardAuthenticationDefaults.HubClientsPolicy,
policy => policy
.AddAuthenticationSchemes(
DashboardAuthenticationDefaults.AuthenticationScheme,
DashboardAuthenticationDefaults.HubAuthenticationScheme)
.AddRequirements(DashboardAuthorizationRequirement.AnyDashboardRole));
});
services.AddSingleton();
return services;
}
}