feat(security): DisableLoginGuard refuses DisableLogin outside Development without explicit ack

This commit is contained in:
Joseph Doherty
2026-07-08 14:52:00 -04:00
parent c3a9e708a2
commit 74c295e37a
3 changed files with 58 additions and 0 deletions
@@ -24,4 +24,7 @@ public sealed class AuthDisableLoginOptions
/// <summary>The username the auto-login principal is minted with. Default "multi-role".</summary>
public string User { get; set; } = "multi-role";
/// <summary>Explicit second acknowledgement key: permits DisableLogin outside Development. Default false.</summary>
public bool AllowOutsideDevelopment { get; set; }
}
@@ -0,0 +1,25 @@
namespace ZB.MOM.WW.ScadaBridge.Security.Auth;
/// <summary>
/// Startup guard for the dev/test <see cref="AuthDisableLoginOptions.DisableLogin"/> flag.
/// DisableLogin authenticates EVERY request with ALL roles (including Operator+Verifier,
/// nullifying the two-person secured-write control) on a SCADA control surface, so it is
/// refused outside the Development environment unless the operator sets the explicit
/// second acknowledgement key <see cref="AuthDisableLoginOptions.AllowOutsideDevelopment"/>.
/// Called by the Host composition root before AddSecurity(); fail-fast at boot.
/// </summary>
public static class DisableLoginGuard
{
public static void Validate(bool disableLogin, string environmentName, bool allowOutsideDevelopment)
{
if (!disableLogin) return;
if (string.Equals(environmentName, "Development", StringComparison.OrdinalIgnoreCase)) return;
if (allowOutsideDevelopment) return;
throw new InvalidOperationException(
"ScadaBridge:Security:Auth:DisableLogin=true disables ALL authentication on a SCADA control " +
$"surface and is refused outside the Development environment (current: '{environmentName}'). " +
"Remove the flag, run with ASPNETCORE_ENVIRONMENT=Development, or — only if you fully accept an " +
"unauthenticated deployment — additionally set " +
"ScadaBridge:Security:Auth:AllowOutsideDevelopment=true.");
}
}