refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)
Solution + 23 src projects + 26 test projects renamed; folders, csproj, namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated. ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated. SQL roles/logins, LDAP domains, CLI command name, and CLI config dir (~/.scadalink → ~/.scadabridge) also renamed. Build green; 5 Host.Tests fail awaiting SQL login rename in next commit. Pre-existing StaleTagMonitor timing flakes unchanged. Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Module | `src/ScadaLink.Security` |
|
||||
| Module | `src/ZB.MOM.WW.ScadaBridge.Security` |
|
||||
| Design doc | `docs/requirements/Component-Security.md` |
|
||||
| Status | Reviewed |
|
||||
| Last reviewed | 2026-05-28 |
|
||||
@@ -117,7 +117,7 @@ _Re-review (2026-05-28, `1eb6e97`):_
|
||||
| Severity | High |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:37-47` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/LdapAuthService.cs:37-47` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -153,7 +153,7 @@ and `AuthenticateAsync_NoTlsTransport_RejectedWithoutAllowInsecure`.
|
||||
| Severity | High |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/ServiceCollectionExtensions.cs:16-23` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/ServiceCollectionExtensions.cs:16-23` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -186,7 +186,7 @@ tuning left as a separate, lower-priority improvement.)
|
||||
| Severity | High |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/JwtTokenService.cs:33`, `src/ScadaLink.Security/SecurityOptions.cs:42` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/JwtTokenService.cs:33`, `src/ZB.MOM.WW.ScadaBridge.Security/SecurityOptions.cs:42` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -222,7 +222,7 @@ corrected to state the requirement. Regression tests
|
||||
| Severity | Medium |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:66`, `:138`, `:157-159` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/LdapAuthService.cs:66`, `:138`, `:157-159` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -258,7 +258,7 @@ Regression tests `BuildFallbackUserDn_UsesConfiguredUserIdAttribute`,
|
||||
| Severity | Medium |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:157-159` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/LdapAuthService.cs:157-159` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -297,7 +297,7 @@ Regression tests `BuildFallbackUserDn_EscapesDnMetacharacters`,
|
||||
| Severity | Medium |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/JwtTokenService.cs:67-75`, `:56-59` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/JwtTokenService.cs:67-75`, `:56-59` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -311,7 +311,7 @@ silently exploitable.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
Set a fixed `Issuer` and `Audience` (e.g. `"scadalink-central"`) when generating tokens
|
||||
Set a fixed `Issuer` and `Audience` (e.g. `"scadabridge-central"`) when generating tokens
|
||||
and enable `ValidateIssuer`/`ValidateAudience` with the matching expected values during
|
||||
validation.
|
||||
|
||||
@@ -320,7 +320,7 @@ validation.
|
||||
Resolved 2026-05-16 (commit `pending`). Confirmed: `GenerateToken` set neither `iss`
|
||||
nor `aud` and `ValidateToken` had `ValidateIssuer = false`/`ValidateAudience = false`.
|
||||
`GenerateToken` now binds `JwtTokenService.TokenIssuer`/`TokenAudience`
|
||||
(both `"scadalink-central"`) into every token, and `ValidateToken` enables
|
||||
(both `"scadabridge-central"`) into every token, and `ValidateToken` enables
|
||||
`ValidateIssuer`/`ValidateAudience` against those fixed values — a token signed with
|
||||
the shared key but a foreign issuer is now rejected. Regression tests
|
||||
`GenerateToken_SetsIssuerAndAudience`, `ValidateToken_RejectsTokenWithWrongIssuer`,
|
||||
@@ -333,7 +333,7 @@ the shared key but a foreign issuer is now rejected. Regression tests
|
||||
| Severity | Medium |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/JwtTokenService.cs:40`, `:111-123` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/JwtTokenService.cs:40`, `:111-123` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -381,7 +381,7 @@ Security-side defect — the reset-on-refresh bug — is fully fixed here. Regre
|
||||
| Severity | Low |
|
||||
| Category | Performance & resource management |
|
||||
| Status | Deferred |
|
||||
| Location | `src/ScadaLink.Security/RoleMapper.cs:25-48` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/RoleMapper.cs:25-48` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -403,7 +403,7 @@ issues one `GetScopeRulesForMappingAsync` round-trip per matched Deployment mapp
|
||||
genuine N+1 on the login / 15-minute-refresh path. However, the only correct fix
|
||||
(a batch `GetScopeRulesForMappingsAsync(IEnumerable<int>)` repository method, or an
|
||||
eager-load navigation property) requires changes to `ISecurityRepository`
|
||||
(`src/ScadaLink.Commons`) and `SecurityRepository` (`src/ScadaLink.ConfigurationDatabase`).
|
||||
(`src/ZB.MOM.WW.ScadaBridge.Commons`) and `SecurityRepository` (`src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase`).
|
||||
Both are outside the Security module's permitted edit scope for this review pass, and the
|
||||
existing `ISecurityRepository` surface offers no per-set scope-rule query, so the N+1
|
||||
cannot be removed from within `RoleMapper.cs` alone. Severity is Low (bounded by the
|
||||
@@ -418,7 +418,7 @@ rules in a single call.
|
||||
| Severity | Low |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:42`, `:46`, `:51`, `:56-57`, `:67-73`, `:135`, `:139-145` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/LdapAuthService.cs:42`, `:46`, `:51`, `:56-57`, `:67-73`, `:135`, `:139-145` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -490,7 +490,7 @@ of the document and the code.
|
||||
| Severity | Low |
|
||||
| Category | Testing coverage |
|
||||
| Status | Resolved |
|
||||
| Location | `tests/ScadaLink.Security.Tests/UnitTest1.cs` |
|
||||
| Location | `tests/ZB.MOM.WW.ScadaBridge.Security.Tests/UnitTest1.cs` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -529,7 +529,7 @@ LDAP-timeout coverage (Security-009) plus extra no-service-account / DN-path edg
|
||||
| Severity | Medium |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:78-118` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/LdapAuthService.cs:78-118` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -581,7 +581,7 @@ treating a genuine empty-groups result as a successful login. Regression tests
|
||||
| Severity | Low |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:258-269` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/LdapAuthService.cs:258-269` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -621,7 +621,7 @@ testing. Regression tests `ExtractFirstRdnValue_EscapedComma_KeepsWholeGroupName
|
||||
| Severity | Medium |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/JwtTokenService.cs:156-169` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/JwtTokenService.cs:156-169` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -665,7 +665,7 @@ invariant. Regression tests `RefreshToken_IdleExpiredPrincipal_ReturnsNull`,
|
||||
| Severity | Low |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:20-21`, `:80`, `:122`, `:169`, `:193` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/LdapAuthService.cs:20-21`, `:80`, `:122`, `:169`, `:193` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -707,7 +707,7 @@ use the single canonical identity. Regression tests
|
||||
| Severity | Medium |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/RoleMapper.cs:30-31`, `:41-55`, `:59` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/RoleMapper.cs:30-31`, `:41-55`, `:59` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -765,17 +765,17 @@ after.
|
||||
| Severity | Medium |
|
||||
| Category | Design-document adherence |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/SiteScopeAuthorizationHandler.cs:8-58`; `src/ScadaLink.Security/AuthorizationPolicies.cs:113-143` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/SiteScopeAuthorizationHandler.cs:8-58`; `src/ZB.MOM.WW.ScadaBridge.Security/AuthorizationPolicies.cs:113-143` |
|
||||
|
||||
**Description**
|
||||
|
||||
The module declares `SiteScopeRequirement` (an `IAuthorizationRequirement` carrying a
|
||||
`TargetSiteId`) and the matching `SiteScopeAuthorizationHandler` that combines the
|
||||
Deployment role claim with the `SiteId` claims to enforce the design's site-scoping
|
||||
rule. The handler is registered in `AddScadaLinkAuthorization`
|
||||
rule. The handler is registered in `AddScadaBridgeAuthorization`
|
||||
(`services.AddSingleton<IAuthorizationHandler, SiteScopeAuthorizationHandler>()`). But
|
||||
no `AddPolicy` call ever wires the requirement to a named policy, and a grep across
|
||||
`src/ScadaLink.CentralUI` and `src/ScadaLink.ManagementService` confirms that **no
|
||||
`src/ZB.MOM.WW.ScadaBridge.CentralUI` and `src/ZB.MOM.WW.ScadaBridge.ManagementService` confirms that **no
|
||||
production code ever instantiates `new SiteScopeRequirement(...)` or calls
|
||||
`AuthorizeAsync(...)` with one** — the only callers are the unit tests in
|
||||
`SecurityTests.cs:1146,1166,1185,1203`. The design + CLAUDE.md state that "Deployment
|
||||
@@ -808,7 +808,7 @@ piecemeal.
|
||||
Resolved 2026-05-28 (commit pending) per recommendation option (a): deleted
|
||||
`SiteScopeRequirement` and `SiteScopeAuthorizationHandler` outright, along with the
|
||||
unwired `services.AddSingleton<IAuthorizationHandler, SiteScopeAuthorizationHandler>()`
|
||||
registration in `AuthorizationPolicies.AddScadaLinkAuthorization` and the four
|
||||
registration in `AuthorizationPolicies.AddScadaBridgeAuthorization` and the four
|
||||
isolation tests in `SecurityTests.cs`. `SiteScopeService` (CentralUI-002) is now
|
||||
documented as the sole site-scoping mechanism — the stale "mirrors
|
||||
SiteScopeAuthorizationHandler" comment in `SiteScopeService.ResolveAsync` was rewritten
|
||||
@@ -822,7 +822,7 @@ new report pages now consume `SiteScopeService`).
|
||||
| Severity | Low |
|
||||
| Category | Code organization & conventions |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/RoleMapper.cs:41`; `src/ScadaLink.Security/SiteScopeAuthorizationHandler.cs:36`; `src/ScadaLink.Security/AuthorizationPolicies.cs:118,121,124,95,107` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/RoleMapper.cs:41`; `src/ZB.MOM.WW.ScadaBridge.Security/SiteScopeAuthorizationHandler.cs:36`; `src/ZB.MOM.WW.ScadaBridge.Security/AuthorizationPolicies.cs:118,121,124,95,107` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -852,11 +852,11 @@ will then either succeed everywhere or fail to compile.
|
||||
|
||||
**Resolution**
|
||||
|
||||
Resolved 2026-05-28 (commit pending). Added `src/ScadaLink.Security/Roles.cs` holding
|
||||
Resolved 2026-05-28 (commit pending). Added `src/ZB.MOM.WW.ScadaBridge.Security/Roles.cs` holding
|
||||
`Admin`/`Design`/`Deployment`/`Audit`/`AuditReadOnly` as `public const string`
|
||||
fields. Replaced every magic-string occurrence in this module:
|
||||
`RoleMapper.MapGroupsToRolesAsync` now compares against `Roles.Deployment`;
|
||||
`AuthorizationPolicies.AddScadaLinkAuthorization` binds `RequireClaim(...)` to
|
||||
`AuthorizationPolicies.AddScadaBridgeAuthorization` binds `RequireClaim(...)` to
|
||||
`Roles.{Admin,Design,Deployment}`; `OperationalAuditRoles` /
|
||||
`AuditExportRoles` are now built from `Roles.Admin`, `Roles.Audit`, `Roles.AuditReadOnly`.
|
||||
`SiteScopeAuthorizationHandler.cs` was deleted under Security-017, so its
|
||||
@@ -870,7 +870,7 @@ single edit or fails to compile.
|
||||
| Severity | Low |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/LdapAuthService.cs:85-89`, `:147-151` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/LdapAuthService.cs:85-89`, `:147-151` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -903,7 +903,7 @@ distinct error message.
|
||||
**Resolution**
|
||||
|
||||
Resolved 2026-05-28 (commit pending). Added a new `ServiceAccountBindException`
|
||||
(`src/ScadaLink.Security/ServiceAccountBindException.cs`) — deliberately NOT an
|
||||
(`src/ZB.MOM.WW.ScadaBridge.Security/ServiceAccountBindException.cs`) — deliberately NOT an
|
||||
`LdapException` subtype so it short-circuits the generic LDAP catch — and a private
|
||||
`BindServiceAccountAsync` helper on `LdapAuthService` that wraps both service-account
|
||||
rebind sites (the post-user-bind group-lookup rebind AND the `ResolveUserDnAsync`
|
||||
@@ -926,7 +926,7 @@ is the closest meaningful unit-level coverage.
|
||||
| Severity | Low |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/SecurityOptions.cs:6-7`, `:36-37`; `src/ScadaLink.Security/ServiceCollectionExtensions.cs:13-30` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/SecurityOptions.cs:6-7`, `:36-37`; `src/ZB.MOM.WW.ScadaBridge.Security/ServiceCollectionExtensions.cs:13-30` |
|
||||
|
||||
**Resolution (2026-05-28):** added `SecurityOptionsValidator`
|
||||
(`IValidateOptions<SecurityOptions>`) that rejects empty/whitespace
|
||||
@@ -972,7 +972,7 @@ every required `SecurityOptions` field is enforced at startup, not at first use.
|
||||
| Severity | Low |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.Security/SecurityOptions.cs:100-108`; `src/ScadaLink.Security/ServiceCollectionExtensions.cs:54-59` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Security/SecurityOptions.cs:100-108`; `src/ZB.MOM.WW.ScadaBridge.Security/ServiceCollectionExtensions.cs:54-59` |
|
||||
|
||||
**Resolution (2026-05-28):** Added `ILoggerFactory` to the cookie-options
|
||||
`Configure` callback in `AddSecurity` so an explicit `RequireHttpsCookie=false`
|
||||
|
||||
Reference in New Issue
Block a user