e57d864ab2
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.
72 lines
3.1 KiB
C#
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);
|
|
}
|
|
}
|