feat(secrets): mount /admin/secrets UI + secrets authorization (Task 5, G-6)
Mount the shared ZB.MOM.WW.Secrets.Ui RCL page at /admin/secrets on admin nodes: - Register secrets:manage/secrets:reveal policies additively via Configure<AuthorizationOptions>(o => o.AddSecretsAuthorization()) in AddAdminUI (the admin-only composition layer that already references the RCL — avoids forcing an RCL dependency into the core Security lib; mirrors HistorianGateway) - Register the RCL routable assembly in BOTH the SSR endpoint (AddAdditionalAssemblies) and the interactive Router (App.razor AdditionalAssemblies) or the route 404s - Add a Secrets nav item; the page's own [Authorize(Policy=...)] gates access Claim-type MATCH: AdminRole=Administrator reads the same ClaimTypes.Role as FleetAdmin, so existing Administrators are authorized with no new role mapping. Full clean boot verified; interactive reveal deferred to the live gate (shared UI already proven).
This commit is contained in:
@@ -19,7 +19,7 @@
|
|||||||
<HeadOutlet/>
|
<HeadOutlet/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<Routes/>
|
<Routes AdditionalAssemblies="@(new[] { typeof(ZB.MOM.WW.Secrets.Ui.SecretsPage).Assembly })" />
|
||||||
<script src="_content/ZB.MOM.WW.OtOpcUa.AdminUI/lib/bootstrap/js/bootstrap.bundle.min.js"></script>
|
<script src="_content/ZB.MOM.WW.OtOpcUa.AdminUI/lib/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||||
<ThemeScripts />
|
<ThemeScripts />
|
||||||
<script src="_content/ZB.MOM.WW.OtOpcUa.AdminUI/js/monaco-init.js"></script>
|
<script src="_content/ZB.MOM.WW.OtOpcUa.AdminUI/js/monaco-init.js"></script>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<NavRailItem Href="/reservations" Text="Reservations" />
|
<NavRailItem Href="/reservations" Text="Reservations" />
|
||||||
<NavRailItem Href="/certificates" Text="Certificates" />
|
<NavRailItem Href="/certificates" Text="Certificates" />
|
||||||
<NavRailItem Href="/role-grants" Text="Role grants" />
|
<NavRailItem Href="/role-grants" Text="Role grants" />
|
||||||
|
<NavRailItem Href="/admin/secrets" Text="Secrets" />
|
||||||
</NavRailSection>
|
</NavRailSection>
|
||||||
<NavRailSection Title="Scripting" Key="scripting">
|
<NavRailSection Title="Scripting" Key="scripting">
|
||||||
<NavRailItem Href="/scripts" Text="Scripts" />
|
<NavRailItem Href="/scripts" Text="Scripts" />
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Web;
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
@@ -10,6 +11,7 @@ using ZB.MOM.WW.OtOpcUa.Commons.Browsing;
|
|||||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||||
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Browser;
|
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Browser;
|
||||||
using ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser;
|
using ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser;
|
||||||
|
using ZB.MOM.WW.Secrets.Ui;
|
||||||
|
|
||||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI;
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI;
|
||||||
|
|
||||||
@@ -28,8 +30,13 @@ public static class EndpointRouteBuilderExtensions
|
|||||||
// Razor class library static assets (_content/ZB.MOM.WW.OtOpcUa.AdminUI/**) are
|
// Razor class library static assets (_content/ZB.MOM.WW.OtOpcUa.AdminUI/**) are
|
||||||
// served via the Host's app.UseStaticFiles() middleware which must run BEFORE
|
// served via the Host's app.UseStaticFiles() middleware which must run BEFORE
|
||||||
// UseAuthentication() — see Program.cs.
|
// UseAuthentication() — see Program.cs.
|
||||||
|
// The /admin/secrets management page lives in the external ZB.MOM.WW.Secrets.Ui RCL, so its
|
||||||
|
// routable component must be discovered at the endpoint layer (AddAdditionalAssemblies) —
|
||||||
|
// the interactive Router's AdditionalAssemblies (App.razor) alone is not enough for SSR
|
||||||
|
// endpoint discovery. Both registrations are required or /admin/secrets 404s.
|
||||||
app.MapRazorComponents<TApp>()
|
app.MapRazorComponents<TApp>()
|
||||||
.AddInteractiveServerRenderMode();
|
.AddInteractiveServerRenderMode()
|
||||||
|
.AddAdditionalAssemblies(typeof(ZB.MOM.WW.Secrets.Ui.SecretsPage).Assembly);
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,6 +50,15 @@ public static class EndpointRouteBuilderExtensions
|
|||||||
services.AddRazorComponents().AddInteractiveServerComponents();
|
services.AddRazorComponents().AddInteractiveServerComponents();
|
||||||
services.AddOtOpcUaDriverStatusServices();
|
services.AddOtOpcUaDriverStatusServices();
|
||||||
|
|
||||||
|
// Secrets-management UI (ZB.MOM.WW.Secrets.Ui RCL, mounted at /admin/secrets). Register its
|
||||||
|
// "secrets:manage"/"secrets:reveal" authorization policies additively onto the AuthorizationOptions
|
||||||
|
// that AddOtOpcUaAuth (called just before AddAdminUI on admin nodes) sets up — Configure<T> stacks,
|
||||||
|
// so this ADDS the two policies without disturbing FleetAdmin/DriverOperator/ConfigEditor. The
|
||||||
|
// policies' AdminRole = "Administrator" reads the same ClaimTypes.Role claim as FleetAdmin, so an
|
||||||
|
// existing Administrator satisfies them with no new group→role mapping. Registered here (the AdminUI
|
||||||
|
// composition layer that already references the RCL) rather than in the core Security lib.
|
||||||
|
services.Configure<AuthorizationOptions>(o => o.AddSecretsAuthorization());
|
||||||
|
|
||||||
// Browse pipeline — see docs/plans/2026-05-28-driver-browsers-design.md
|
// Browse pipeline — see docs/plans/2026-05-28-driver-browsers-design.md
|
||||||
services.AddSingleton<Browsing.BrowseSessionRegistry>();
|
services.AddSingleton<Browsing.BrowseSessionRegistry>();
|
||||||
services.AddHostedService<Browsing.BrowseSessionReaper>();
|
services.AddHostedService<Browsing.BrowseSessionReaper>();
|
||||||
|
|||||||
Reference in New Issue
Block a user