Phase 3 PR 28 — Admin UI cert-trust management page #27
Reference in New Issue
Block a user
Delete Branch "phase-3-pr28-cert-trust"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds
/certificatesAdmin UI route (FleetAdmin-only) that surfaces the OPC UA server's PKI storerejected+trustedcert folders and gives operators Trust / Delete / Revoke actions so rejected client certs can be promoted without touching disk.Service
CertTrustServicereads$PkiStoreRoot/{rejected,trusted}/certs/*.derdirectly viaX509CertificateLoader— noOpc.Uadependency in the Admin project. The Opc.Ua stack uses a Directory-typed store on disk so the file layout is stable, and the Admin process can manage it without needing the Server's assemblies loaded. Typical deployment has Admin + Server side-by-side on the same machine;CertTrustOptions.PkiStoreRootdefaults to%ProgramData%\OtOpcUa\pkito matchOpcUaServerOptions.PkiStoreRoot's default, so a vanilla install needs no override.Operator actions
File.Move(rejected/certs/x.der → trusted/certs/x.der, overwrite: true). Idempotent, tolerates a concurrent operator doing the same move.trusted/certs/. The Opc.Ua stack re-reads the Directory store on each new client handshake, so no explicit reload signal is needed; operators retry the rejected client's connection after trusting.UX details
X509Certificate2.Thumbprintis upper-case hex but operators often copy-paste from logs that lowercase it..derfiles in the store are logged + skipped — a single bad file can't take the whole management page offline.user + thumbprint + actionso the filesystem-op log inCertTrustServicecorrelates back to the authenticated admin. DB-levelConfigAuditLogpersistence is deferred because that schema is cluster-scoped and cert actions are cluster-agnostic.Tests
CertTrustServiceTests— 9 new unit cases:ListRejectedparses subject / thumbprint / store kind from a self-signed test cert.TrustRejectedmoves the file;ListRejectedempty afterwards.TrustRejectedwith a missing thumbprint returns false without touching trusted.DeleteRejectedremoves the file.UntrustCertremoves from trusted only..derin the store is logged + skipped; valid certs still surface.Full Admin.Tests Unit suite: 23 pass / 0 fail (14 prior + 9 new). Full Admin build clean — 0 errors, 0 warnings.
Docs
lmx-followups.mditem #3 marked DONE. Deferred: flippingAutoAcceptUntrustedClientCertificatestofalseas the production default — that's a deployment-config follow-up, not a code gap. The Admin UI is now ready to be the trust gate.Closes
LMX follow-up #3.
Razor page layout: two tables (Rejected / Trusted) with Subject / Issuer / Thumbprint / Valid-window / Actions columns, status banner after each action with success or warning kind ('file missing' = another admin handled it), FleetAdmin-only via [Authorize(Roles=AdminRoles.FleetAdmin)]. Each action invokes LogActionAsync which Serilog-logs the authenticated admin user + thumbprint + action for an audit trail — DB-level ConfigAuditLog persistence is deferred because its schema is cluster-scoped and cert actions are cluster-agnostic; Serilog + CertTrustService's filesystem-op info logs give the forensic trail in the meantime. Sidebar link added to MainLayout between Reservations and the future Account page. Tests — CertTrustServiceTests (9 new unit cases): ListRejected parses Subject + Thumbprint + store kind from a self-signed test cert written into rejected/certs/; rejected and trusted stores are kept separate; TrustRejected moves the file and the Rejected list is empty afterwards; TrustRejected with a thumbprint not in rejected returns false without touching trusted; DeleteRejected removes the file; UntrustCert removes from trusted only; thumbprint match is case-insensitive (operator UX); missing store directories produce empty lists instead of throwing DirectoryNotFoundException (pristine-install tolerance); a junk .der in the store is logged + skipped and the valid certs still surface (one bad file doesn't break the page). Full Admin.Tests Unit suite: 23 pass / 0 fail (14 prior + 9 new). Full Admin build clean — 0 errors, 0 warnings. lmx-followups.md #3 marked DONE with a cross-reference to this PR and a note that flipping AutoAcceptUntrustedClientCertificates to false as the production default is a deployment-config follow-up, not a code gap — the Admin UI is now ready to be the trust gate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>