feat(auth)!: ScadaBridge canonical roles + SoD collapse (Audit→Administrator, AuditReadOnly→Viewer) + config-DB migration (Task 1.7)
Standardize role string VALUES on the canonical vocabulary
(Administrator/Designer/Deployer/Viewer; Operator/Engineer unused here):
Admin -> Administrator
Design -> Designer
Deployment -> Deployer
Audit -> Administrator (COLLAPSE; accepted privilege escalation)
AuditReadOnly-> Viewer (COLLAPSE; keeps audit-read, no export)
SoD: OperationalAuditRoles = { Administrator, Viewer },
AuditExportRoles = { Administrator }
so Viewer reads the audit log + nav but cannot bulk-export, while
Administrator does both + holds the full admin surface (the documented,
accepted auditor/admin SoD collapse).
Atomic move across every enforcement site:
- Roles constants; AuthorizationPolicies (RequireClaim values + SoD arrays +
honest XML-doc); RoleMapper Deployer check.
- ManagementActor.GetRequiredRole switch + the hard-coded site-scope
admin-bypass (now Roles.Administrator at all 6 sites). Site-scoping logic
is otherwise unchanged.
- DebugStreamHub Administrator/Deployer gates (Deployer kept case-sensitive).
- CentralUI BrowseService/BindingTester Designer guards; LdapMappingForm
dropdown now offers canonical values (incl. Viewer).
- Config-DB seed (LdapGroupMappings Id 1-4) + EF migration CanonicalizeRoles:
Id-keyed UpdateData for seed rows + idempotent raw catch-all UPDATEs for
operator-added rows. Down is lossy on the collapse (documented in-file).
No pending model changes.
Tests reworked to the collapsed model across Security/CentralUI/
ManagementService/ConfigurationDatabase/Integration suites, incl. explicit
Viewer-reads-not-exports and former-Audit-now-Administrator-escalation cases.
CHANGELOG: BREAKING security note documenting the canonicalization + SoD
collapse.
This commit is contained in:
@@ -6,6 +6,53 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed — BREAKING: canonical role names + audit separation-of-duties collapse (Task 1.7)
|
||||
|
||||
Role string VALUES are standardized onto the canonical vocabulary
|
||||
(`Administrator`/`Designer`/`Deployer`/`Viewer`; `Operator`/`Engineer` are unused
|
||||
by ScadaBridge). The legacy ScadaBridge role names were renamed and two were
|
||||
**collapsed**:
|
||||
|
||||
| Legacy role | Canonical role | Notes |
|
||||
|-----------------|-----------------|-------|
|
||||
| `Admin` | `Administrator` | rename |
|
||||
| `Design` | `Designer` | rename |
|
||||
| `Deployment` | `Deployer` | rename |
|
||||
| `Audit` | `Administrator` | **COLLAPSE** |
|
||||
| `AuditReadOnly` | `Viewer` | **COLLAPSE** |
|
||||
|
||||
- **SECURITY — privilege escalation (accepted).** The former `Audit` role
|
||||
collapses into `Administrator`. This is a real escalation: a former audit-only
|
||||
user now holds the **entire admin surface** (create/update/delete sites, manage
|
||||
LDAP group→role mappings and API keys, preview/import transport bundles), not
|
||||
just audit read+export. This loss of auditor/admin separation-of-duties is a
|
||||
deliberate, accepted trade-off of the canonicalization.
|
||||
- **SECURITY — half-SoD preserved.** The former `AuditReadOnly` role collapses
|
||||
into `Viewer`, which **keeps audit READ** (Audit Log page, Configuration Audit
|
||||
Log page, audit nav group) but **cannot bulk-export**. The audit policy sets are
|
||||
now `OperationalAuditRoles = { Administrator, Viewer }` and
|
||||
`AuditExportRoles = { Administrator }`, so a `Viewer` reads the audit log but the
|
||||
Export-CSV button / `/api/audit/export` endpoint correctly refuses it.
|
||||
- **Enforcement.** Every enforcement site moved together: the role-claim values,
|
||||
the authorization policies (`RequireAdmin`/`RequireDesign`/`RequireDeployment`
|
||||
policy *names* are unchanged; only the role *values* inside them changed), the
|
||||
`ManagementActor.GetRequiredRole` switch, the hard-coded site-scope admin-bypass
|
||||
(`Roles.Administrator` everywhere), the `DebugStreamHub` Administrator/Deployer
|
||||
gates, and the CentralUI `BrowseService`/`BindingTester` Designer guards.
|
||||
**Site-scoping logic is otherwise unchanged** — only the admin-bypass *value*
|
||||
moved from `"Admin"` to `Roles.Administrator`.
|
||||
- **Config-DB migration `CanonicalizeRoles`.** Updates the four seeded
|
||||
`LdapGroupMappings` rows (Id 1-4) to the canonical role values and adds raw
|
||||
idempotent catch-all `UPDATE`s for operator-added rows
|
||||
(`Admin`/`Audit`→`Administrator`, `Design`→`Designer`, `Deployment`→`Deployer`,
|
||||
`AuditReadOnly`→`Viewer`). The Down migration is **lossy** for the collapse: it
|
||||
best-effort maps `Administrator`→`Admin` and `Viewer`→`AuditReadOnly` but cannot
|
||||
recover the original `Audit`/`Admin` or `Viewer`/`AuditReadOnly` distinction.
|
||||
- **Operator action.** Any LDAP group→role mappings created with the legacy role
|
||||
strings are migrated automatically by `CanonicalizeRoles`. New mappings created
|
||||
via the CentralUI LDAP-mappings form now offer the canonical role values
|
||||
(including a `Viewer` option for audit-read-only delegation).
|
||||
|
||||
### Changed — BREAKING: inbound API authentication
|
||||
|
||||
Inbound API authentication has migrated off the SQL Server `X-API-Key` scheme and
|
||||
|
||||
Reference in New Issue
Block a user