diff --git a/docs/plans/2026-06-02-auth-audit-normalization-phase1.md b/docs/plans/2026-06-02-auth-audit-normalization-phase1.md index 755a2b7..2882c55 100644 --- a/docs/plans/2026-06-02-auth-audit-normalization-phase1.md +++ b/docs/plans/2026-06-02-auth-audit-normalization-phase1.md @@ -84,16 +84,23 @@ Cookie `ZB.MOM.WW.ScadaBridge.Auth`; JWT-in-cookie via `JwtTokenService`. 5. **MxGateway ApiKeys cutover is the donor path — lowest risk** (delete locals, re-point to library; keep `ConstraintEnforcer`/gRPC/scopes on top). Confirms the GAPS sequencing (gateway first). -## Open decisions (check back with user) +## Resolved decisions (2026-06-02) -- **Decision A — ScadaBridge inbound API keys depth:** - (a) Full adopt `Auth.ApiKeys` (re-architect inbound auth: Bearer token format, keyId/scope model, move keys to the - library SQLite store or implement `IApiKeyStore` over its SQL Server tables) — faithful but large. - (b) Keep ScadaBridge's inbound-API auth as-is, adopt only the shared **token format + pepper/hashing convention** - (smallest behaviour-visible change; the GAPS D2 "reconcile token format" reading). - (c) Implement the library's `IApiKeyStore`/`IApiKeyVerifier` over ScadaBridge's existing SQL Server tables + - per-method-approval policy (middle path: shared verifier seam, keep storage + approval model). -- **Decision B — canonical role mappings:** confirm the per-app tables above (esp. OtOpcUa `ConfigEditor→Designer`, - `FleetAdmin→Administrator+Deployer`; ScadaBridge `Audit`/`AuditReadOnly` collapse). -- **Decision C — `DevStubMode`** (OtOpcUa) and MxGateway loopback/`AllowAnonymousLocalhost` bypass: keep app-side - (library has no equivalent) — confirm we preserve these dev escape hatches unchanged. +- **Decision A — ScadaBridge inbound API keys depth → (a) FULL ADOPT.** Re-architect inbound-API auth to the + library's model: `__` Bearer token format, keyId lookup + constant-time compare, + scopes/constraints, and **move inbound API keys into the library's SQLite store** (separate from the SQL Server + config DB). This is the largest, highest-risk item in Phase 1. Implications to handle in Task 1.3: + - New SQLite auth DB for ScadaBridge inbound keys (path via `ApiKeyOptions.SqlitePath`); migrate/retire the + SQL Server `ApiKey{Name,KeyHash}` table + `ApiMethod.ApprovedApiKeyIds` linkage. + - Re-model **per-method approval** as the library's scopes/constraints (or the opaque constraint blob) — the + `ApiMethod.ApprovedApiKeyIds` set becomes per-key scope grants. + - Switch the inbound transport from `X-API-Key` header to `Authorization: Bearer ` (a client-visible + contract change — extends the already-accepted token-format change; needs the interop check + a doc/CHANGELOG note). + - Existing raw keys cannot be migrated (deterministic-by-value hash, no keyId/secret split) → **re-issue** all + inbound API keys; call this out in the cutover runbook. +- **Decision B — canonical role mappings → confirmed as tabled above** (OtOpcUa `ConfigViewer→Viewer`, + `ConfigEditor→Designer`, `FleetAdmin→Administrator+Deployer`; MxGateway `Viewer/Admin`; ScadaBridge + `Admin→Administrator`, `Design→Designer`, `Deployment→Deployer`, `Audit→Administrator`, `AuditReadOnly→Viewer`). +- **Decision C — dev escape hatches → keep app-side, unchanged.** OtOpcUa `DevStubMode` and MxGateway + `AllowAnonymousLocalhost`/loopback bypass have no library equivalent; preserve them in each app outside the + shared `Auth.Ldap` path.