diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/App.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/App.razor index 7255b31d..4697fe81 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/App.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/App.razor @@ -19,7 +19,7 @@ - + diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Layout/MainLayout.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Layout/MainLayout.razor index 50b5ecdf..29be26aa 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Layout/MainLayout.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Layout/MainLayout.razor @@ -20,6 +20,7 @@ + diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/EndpointRouteBuilderExtensions.cs b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/EndpointRouteBuilderExtensions.cs index 72a33228..8bff8987 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/EndpointRouteBuilderExtensions.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/EndpointRouteBuilderExtensions.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Components; 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.Driver.Galaxy.Browser; using ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Browser; +using ZB.MOM.WW.Secrets.Ui; 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 // served via the Host's app.UseStaticFiles() middleware which must run BEFORE // 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() - .AddInteractiveServerRenderMode(); + .AddInteractiveServerRenderMode() + .AddAdditionalAssemblies(typeof(ZB.MOM.WW.Secrets.Ui.SecretsPage).Assembly); return app; } @@ -43,6 +50,15 @@ public static class EndpointRouteBuilderExtensions services.AddRazorComponents().AddInteractiveServerComponents(); 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 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(o => o.AddSecretsAuthorization()); + // Browse pipeline — see docs/plans/2026-05-28-driver-browsers-design.md services.AddSingleton(); services.AddHostedService();