544a6ddb77
Resolves the 35 findings from the 2026-06-01 baseline (commit 26ba1c7),
test-first for every behavioral change. +51 tests (331 -> 382 passing, 0 failed).
- Telemetry-001 (HIGH): RedactionEnricher now honours property removal, so a
redactor that drops a key actually scrubs the secret from the event.
- Auth: LDAP validator ValidateOnStart; API-key verify no longer fails on a
best-effort MarkUsed write or a corrupt scopes column (fail-closed); LDAP cert
validation hook; KeyPrefix persistence aligned; README algorithm corrected.
- Health: Akka checks return Degraded (not throw) when the cluster isn't up yet;
GrpcDependencyHealthCheck catch-all; null 'description' rendered; composite
endpoint builder; XML docs shipped.
- Audit: CompositeAuditWriter no longer re-throws OperationCanceledException;
TruncatingAuditRedactor over-redact scrubs Target + safe negative max; options
record; XML docs shipped.
- Configuration: TryAddEnumerable idempotent registration; consistent port
quoting; strict invariant port parsing; XML docs + README packaged.
- Theme: mobile toggle is now CSS-only (no Bootstrap JS); token/CSS hygiene;
XML docs on the public parameter surface.
Shared-contract/spec docs updated where the code was the source of truth
(observability service.instance.id, MapZbMetrics, redactor reach). All changes
additive/back-compatible at v0.1.0. code-reviews bookkeeping follows separately.
83 lines
3.9 KiB
Markdown
83 lines
3.9 KiB
Markdown
# ZB.MOM.WW.Auth
|
|
|
|
Authentication and authorisation libraries for the **ZB.MOM.WW SCADA family** (OtOpcUa, MxAccessGateway, ScadaBridge). These are **libraries, not a service** — each package is linked directly into the consuming application at build time. There is no central authentication process or network hop; auth logic runs in-process alongside the application.
|
|
|
|
---
|
|
|
|
## Packages
|
|
|
|
| Package | Description | Key Dependencies |
|
|
|---|---|---|
|
|
| `ZB.MOM.WW.Auth.Abstractions` | Auth contracts, canonical role constants, and shared types (`LdapOptions`, `LdapAuthResult`, `ILdapAuthService`, `IApiKeyStore`). No runtime dependencies beyond the BCL. | — |
|
|
| `ZB.MOM.WW.Auth.Ldap` | LDAP authentication service: bind-then-search-then-bind against GLAuth or Active Directory; RFC 4514-aware group extraction; fail-closed. | `Abstractions`, `Novell.Directory.Ldap.NETStandard` |
|
|
| `ZB.MOM.WW.Auth.ApiKeys` | SQLite-backed API-key store with **pepper-keyed HMAC-SHA256** secret hashing, rotation, and audit log. DI wiring is `AddZbApiKeyAuth`; an opt-in `MigrationHostedService` runs schema migrations on startup. | `Abstractions`, `Microsoft.Data.Sqlite` |
|
|
| `ZB.MOM.WW.Auth.AspNetCore` | ASP.NET Core wiring for the **LDAP** provider only: `AddZbLdapAuth` (binds + start-time-validates `LdapOptions`, registers `ILdapAuthService`), plus `ZbCookieDefaults.Apply` (hardened cookie helper the consumer calls itself) and `ZbClaimTypes` constants. It does **not** wire API keys or cookie middleware — API-key DI is `AddZbApiKeyAuth` in the `ApiKeys` package. | `Abstractions`, `Ldap`, `Microsoft.AspNetCore.App` |
|
|
|
|
---
|
|
|
|
## Consumer Matrix
|
|
|
|
| Consumer | Abstractions | Ldap | ApiKeys | AspNetCore |
|
|
|---|:---:|:---:|:---:|:---:|
|
|
| **OtOpcUa** | yes | yes | — | yes |
|
|
| **MxAccessGateway** | yes | yes | yes | yes |
|
|
| **ScadaBridge** | yes | yes | yes | yes |
|
|
|
|
`ApiKeys` is NOT used by OtOpcUa (that app authenticates human operators via LDAP + cookies only; machine-to-machine access is out of scope).
|
|
|
|
---
|
|
|
|
## Versioning
|
|
|
|
All four packages are versioned **lockstep** from `Directory.Build.props`. The current release is **0.1.0**. A single version bump in `Directory.Build.props` bumps all four packages simultaneously — consumers should reference the same version for all ZB.MOM.WW.Auth packages.
|
|
|
|
---
|
|
|
|
## Running the opt-in LDAP integration test
|
|
|
|
The GLAuth integration test (`GLAuthIntegrationTests`) is **skipped by default** and does not affect the normal test run. To exercise it against a live GLAuth instance:
|
|
|
|
1. Start the GLAuth Docker stack from the sibling repo:
|
|
```
|
|
cd ~/Desktop/ScadaBridge/infra/glauth
|
|
docker compose up -d
|
|
```
|
|
|
|
2. Set the required environment variables and run the test:
|
|
```bash
|
|
export ZB_LDAP_IT=1
|
|
export ZB_LDAP_SVC_DN="cn=svc,dc=lmxopcua,dc=local"
|
|
export ZB_LDAP_SVC_PW="svcpass"
|
|
export ZB_LDAP_USER="alice"
|
|
export ZB_LDAP_PW="alicepass"
|
|
|
|
dotnet test tests/ZB.MOM.WW.Auth.Ldap.Tests \
|
|
--filter "FullyQualifiedName~GLAuthIntegrationTests"
|
|
```
|
|
|
|
All other variables (`ZB_LDAP_SERVER`, `ZB_LDAP_PORT`, `ZB_LDAP_BASE`, `ZB_LDAP_USERATTR`) default to sensible GLAuth values and are optional. The test also probes TCP reachability before attempting auth and skips if the server is not contactable.
|
|
|
|
---
|
|
|
|
## Publishing packages
|
|
|
|
Use `build/push.sh` to pack and push to the Gitea NuGet feed:
|
|
|
|
```bash
|
|
export GITEA_NUGET_SOURCE="https://gitea.dohertylan.com/api/packages/dohertj2/nuget/index.json"
|
|
export GITEA_NUGET_KEY="your-gitea-token"
|
|
./build/push.sh
|
|
```
|
|
|
|
The script runs `dotnet pack -c Release` then `dotnet nuget push --skip-duplicate`.
|
|
|
|
---
|
|
|
|
## Design documentation
|
|
|
|
Full design docs live in the `components/auth` folder of the SCADA project notes:
|
|
|
|
- `~/Desktop/scadaproj/components/auth/spec/SPEC.md` — overall auth specification
|
|
- `~/Desktop/scadaproj/components/auth/spec/CANONICAL-ROLES.md` — role taxonomy
|
|
- `~/Desktop/scadaproj/components/auth/shared-contract/` — shared contract types
|