From 57302500acf9c52a794aa1bc724de90e3c3efc00 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 16 Jun 2026 08:54:11 -0400 Subject: [PATCH] docs(security): document dev disable-login flag + ship default-false config key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a "Dev Disable-Login Flag" subsection to Component-Security.md covering ScadaBridge:Security:Auth:DisableLogin / User, the AutoLoginAuthenticationHandler mechanism, and the no-environment-guard / startup-warning production risk. Ships DisableLogin: false under ScadaBridge → Security → Auth in: - src/.../Host/appsettings.json (canonical default) - docker/central-node-a/appsettings.Central.json - docker/central-node-b/appsettings.Central.json Also records DL-3 commit SHAs in the plan tasks file. --- docker/central-node-a/appsettings.Central.json | 4 ++++ docker/central-node-b/appsettings.Central.json | 4 ++++ docs/plans/2026-06-16-disable-login.md.tasks.json | 2 +- docs/requirements/Component-Security.md | 10 ++++++++++ src/ZB.MOM.WW.ScadaBridge.Host/appsettings.json | 9 +++++++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/docker/central-node-a/appsettings.Central.json b/docker/central-node-a/appsettings.Central.json index 8908a4d2..0ec94080 100644 --- a/docker/central-node-a/appsettings.Central.json +++ b/docker/central-node-a/appsettings.Central.json @@ -31,6 +31,10 @@ "ServiceAccountDn": "cn=serviceaccount,dc=zb,dc=local", "ServiceAccountPassword": "serviceaccount123" }, + "Auth": { + "DisableLogin": false, + "User": "multi-role" + }, "JwtSigningKey": "scadabridge-dev-jwt-signing-key-must-be-at-least-32-characters-long", "JwtExpiryMinutes": 15, "IdleTimeoutMinutes": 30, diff --git a/docker/central-node-b/appsettings.Central.json b/docker/central-node-b/appsettings.Central.json index 20884f6d..a83e26f2 100644 --- a/docker/central-node-b/appsettings.Central.json +++ b/docker/central-node-b/appsettings.Central.json @@ -31,6 +31,10 @@ "ServiceAccountDn": "cn=serviceaccount,dc=zb,dc=local", "ServiceAccountPassword": "serviceaccount123" }, + "Auth": { + "DisableLogin": false, + "User": "multi-role" + }, "JwtSigningKey": "scadabridge-dev-jwt-signing-key-must-be-at-least-32-characters-long", "JwtExpiryMinutes": 15, "IdleTimeoutMinutes": 30, diff --git a/docs/plans/2026-06-16-disable-login.md.tasks.json b/docs/plans/2026-06-16-disable-login.md.tasks.json index 03f87887..353f607a 100644 --- a/docs/plans/2026-06-16-disable-login.md.tasks.json +++ b/docs/plans/2026-06-16-disable-login.md.tasks.json @@ -5,7 +5,7 @@ "tasks": [ {"id": 62, "ref": "DL-1", "subject": "AuthDisableLoginOptions + Roles.All", "class": "small", "status": "completed", "commits": ["72691e5"]}, {"id": 63, "ref": "DL-2", "subject": "AutoLoginAuthenticationHandler + tests", "class": "high-risk", "status": "completed", "blockedBy": [62], "commits": ["dcd445a", "0926ce4"]}, - {"id": 64, "ref": "DL-3", "subject": "Wire flag into AddSecurity + Host + startup warning", "class": "standard", "status": "completed", "blockedBy": [62, 63]}, + {"id": 64, "ref": "DL-3", "subject": "Wire flag into AddSecurity + Host + startup warning", "class": "standard", "status": "completed", "blockedBy": [62, 63], "commits": ["e896042", "75919ce"]}, {"id": 65, "ref": "DL-4", "subject": "Docs + dev config note", "class": "trivial", "status": "pending", "blockedBy": [64]} ], "lastUpdated": "2026-06-16" diff --git a/docs/requirements/Component-Security.md b/docs/requirements/Component-Security.md index c4e844e4..d97ebdbc 100644 --- a/docs/requirements/Component-Security.md +++ b/docs/requirements/Component-Security.md @@ -22,6 +22,16 @@ Central cluster. Sites do not have user-facing interfaces and do not perform ind - **No local user store**: All identity and group information comes from AD. No credentials are cached locally. - **No Windows Integrated Authentication**: The app authenticates directly against LDAP/AD, not via Kerberos/NTLM. +## Dev Disable-Login Flag + +**`ScadaBridge:Security:Auth:DisableLogin`** (bool, default `false`) — when `true`, the Central UI bypasses the login form entirely and auto-authenticates every request as the user named by `ScadaBridge:Security:Auth:User` (default `multi-role`) with all four roles (Administrator, Designer, Deployer, Viewer) granted system-wide. The mechanism is `AutoLoginAuthenticationHandler`, registered under the cookie scheme via `AddSecurity(disableLogin: true)`; because it sits in the cookie scheme, every existing authorization policy authenticates through it with zero policy changes required. + +There is **no environment guard** — a loud startup warning in the application log is the only protection. This disables authentication on a SCADA control surface. + +> **Dev/test ONLY. Never enable in production.** + +Set in a local or docker-dev environment via the environment variable `ScadaBridge__Security__Auth__DisableLogin=true`. Note that `ScadaBridge:Security:Auth` is a child sub-section nested inside `ScadaBridge:Security`. + ## Session Management ### Cookie + JWT Hybrid diff --git a/src/ZB.MOM.WW.ScadaBridge.Host/appsettings.json b/src/ZB.MOM.WW.ScadaBridge.Host/appsettings.json index a0879e67..39500a48 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Host/appsettings.json +++ b/src/ZB.MOM.WW.ScadaBridge.Host/appsettings.json @@ -1,5 +1,14 @@ { "_logging": "Host-021: Serilog is the sole logger provider (Program.cs calls builder.Host.UseSerilog()), so the standard Microsoft 'Logging:LogLevel' block has no effect and was removed. The minimum level is set via 'ScadaBridge:Logging:MinimumLevel' (bound to LoggingOptions per Host-011); sinks are defined under the 'Serilog' section below and applied via ReadFrom.Configuration (Host-014). See LoggerConfigurationFactory + Component-Host.md REQ-HOST-8.", + "ScadaBridge": { + "Security": { + "Auth": { + "_comment": "DisableLogin bypasses the login form and auto-authenticates every request as User with all roles. DEV/TEST ONLY — no environment guard; a startup warning is the only protection. Never enable in production.", + "DisableLogin": false, + "User": "multi-role" + } + } + }, "Serilog": { "Using": [ "Serilog.Sinks.Console",