From 2e231911fd6cbdaec415ea89198780682a2122e7 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 18 Jun 2026 05:17:02 -0400 Subject: [PATCH] =?UTF-8?q?fix(adminui):=20cert=20page=20review=20?= =?UTF-8?q?=E2=80=94=20server-side=20FleetAdmin=20re-check,=20explicit=20d?= =?UTF-8?q?elete=20switch,=20alert=20CSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Pages/Certificates.razor | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Certificates.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Certificates.razor index 601aaaa9..b0be8210 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Certificates.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Certificates.razor @@ -7,6 +7,8 @@ @using ZB.MOM.WW.OtOpcUa.AdminUI.Certificates @inject IConfiguration Config @inject CertificateStoreManager CertManager +@inject Microsoft.AspNetCore.Authorization.IAuthorizationService AuthorizationService +@inject AuthenticationStateProvider AuthState @implements IDisposable
@@ -28,7 +30,7 @@ else { @if (_statusMsg is not null) { -
@_statusMsg
+
@_statusMsg
} @if (_pending is { } p) { @@ -174,15 +176,32 @@ else private void CancelAction() => _pending = null; - private void ConfirmAction() + private async Task ConfirmAction() { if (_pending is not { } p) return; + + // Defense-in-depth: the action buttons are FleetAdmin-gated in markup, but this handler + // runs on the server circuit — re-check the policy before mutating the trust store. + var authState = await AuthState.GetAuthenticationStateAsync(); + if (!(await AuthorizationService.AuthorizeAsync(authState.User, null, "FleetAdmin")).Succeeded) + { + _statusError = true; + _statusMsg = "Unauthorized — FleetAdmin required."; + _pending = null; + return; + } + var result = p.Verb switch { "trust" => CertManager.Trust(p.Thumbprint), "untrust" => CertManager.Untrust(p.Thumbprint), - "delete" => CertManager.Delete(p.Kind == StoreKind.Trusted ? "trusted" : "rejected", p.Thumbprint), - _ => CertActionResult.Fail("unknown action"), + "delete" => p.Kind switch + { + StoreKind.Trusted => CertManager.Delete("trusted", p.Thumbprint), + StoreKind.Rejected => CertManager.Delete("rejected", p.Thumbprint), + _ => CertActionResult.Fail($"cannot delete from {p.Kind}"), + }, + _ => CertActionResult.Fail("unknown action"), }; _statusError = !result.Success; _statusMsg = result.Success