Files
mxaccessgw/src/ZB.MOM.WW.MxGateway.Tests/Gateway/Dashboard/DashboardCookieOptionsTests.cs
T
Joseph Doherty e57d864ab2 fix(dashboard): make dashboard auth cookie name configurable
The dashboard auth cookie name was hardcoded to the constant
DashboardAuthenticationDefaults.CookieName (MxGatewayDashboard). Browser
cookies are scoped by host+path but NOT by port, so two gateway instances
sharing a hostname would clobber each other's dashboard session under the
shared name.

Add DashboardOptions.CookieName (MxGateway:Dashboard:CookieName); null/blank
keeps the canonical default. Applied in the existing dashboard cookie
PostConfigure (runs after the inline AddCookie default, so it wins). Behaviour
is unchanged when unset. Adds a Tests case for the override.
2026-06-03 13:11:29 -04:00

72 lines
3.1 KiB
C#

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.MxGateway.Server;
using ZB.MOM.WW.MxGateway.Server.Dashboard;
namespace ZB.MOM.WW.MxGateway.Tests.Gateway.Dashboard;
public sealed class DashboardCookieOptionsTests
{
/// <summary>Verifies that the application configures secure dashboard authentication cookies.</summary>
[Fact]
public async Task Build_ConfiguresSecureDashboardCookie()
{
await using WebApplication app = GatewayApplication.Build([]);
IOptionsMonitor<CookieAuthenticationOptions> optionsMonitor = app.Services
.GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>();
CookieAuthenticationOptions options = optionsMonitor.Get(
DashboardAuthenticationDefaults.AuthenticationScheme);
Assert.Equal(DashboardAuthenticationDefaults.CookieName, options.Cookie.Name);
Assert.True(options.Cookie.HttpOnly);
Assert.Equal(CookieSecurePolicy.Always, options.Cookie.SecurePolicy);
Assert.Equal(SameSiteMode.Strict, options.Cookie.SameSite);
Assert.Equal("/", options.Cookie.Path);
Assert.Equal("/login", options.LoginPath);
Assert.Equal("/logout", options.LogoutPath);
Assert.Equal("/denied", options.AccessDeniedPath);
}
/// <summary>
/// Verifies that setting <c>MxGateway:Dashboard:RequireHttpsCookie=false</c>
/// relaxes the cookie to <see cref="CookieSecurePolicy.SameAsRequest"/> so
/// the dashboard can be reached over plain HTTP in dev.
/// </summary>
[Fact]
public async Task Build_WithRequireHttpsCookieFalse_UsesSameAsRequest()
{
await using WebApplication app = GatewayApplication.Build(
["--MxGateway:Dashboard:RequireHttpsCookie=false"]);
IOptionsMonitor<CookieAuthenticationOptions> optionsMonitor = app.Services
.GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>();
CookieAuthenticationOptions options = optionsMonitor.Get(
DashboardAuthenticationDefaults.AuthenticationScheme);
Assert.Equal(CookieSecurePolicy.SameAsRequest, options.Cookie.SecurePolicy);
}
/// <summary>
/// Verifies that <c>MxGateway:Dashboard:CookieName</c> overrides the dashboard auth
/// cookie name, so a gateway instance sharing a hostname with another can be given a
/// distinct name (browser cookies are scoped by host+path, not port).
/// </summary>
[Fact]
public async Task Build_WithCookieNameOverride_UsesConfiguredName()
{
await using WebApplication app = GatewayApplication.Build(
["--MxGateway:Dashboard:CookieName=MxGatewayDashboard.env2"]);
IOptionsMonitor<CookieAuthenticationOptions> optionsMonitor = app.Services
.GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>();
CookieAuthenticationOptions options = optionsMonitor.Get(
DashboardAuthenticationDefaults.AuthenticationScheme);
Assert.Equal("MxGatewayDashboard.env2", options.Cookie.Name);
}
}