Files
lmxopcua/src/Server/ZB.MOM.WW.OtOpcUa.Admin/Components/Routes.razor
T
Joseph Doherty 973730d0eb fix(admin): enforce authentication on all Admin UI routes (Admin-001/002)
Admin-001: Routes.razor used a plain RouteView, so the page-level
[Authorize] attributes on 11 pages were inert — every page, including
mutating ones, was reachable fully unauthenticated.
Admin-002: several pages (e.g. NewCluster, which writes config rows)
carried no auth attribute at all.

- Routes.razor: RouteView → AuthorizeRouteView with NotAuthorized /
  Authorizing slots; add RedirectToLogin component.
- Program.cs: SetFallbackPolicy(RequireAuthenticatedUser) — secure by
  default for new pages/endpoints.
- Login.razor: [AllowAnonymous] so login stays reachable; login page,
  /auth/* endpoints and static assets remain anonymous.
- Add [Authorize] to the previously un-gated pages; NewCluster gated to
  the CanPublish (FleetAdmin) policy.

Regression tests in PageAuthorizationTests pin that anonymous requests
to protected/mutating routes are rejected and that login + static
assets stay anonymously reachable. Admin test suite: 210/210 pass.

Resolves code-review findings Admin-001 and Admin-002 (Critical).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 05:53:58 -04:00

33 lines
1.4 KiB
Plaintext

@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Routing
@using ZB.MOM.WW.OtOpcUa.Admin.Components.Layout
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
@* AuthorizeRouteView (not a plain RouteView) is what makes a page-level
[Authorize] attribute actually enforced — with RouteView the attribute
is inert (Admin-001). Unauthenticated users hit the NotAuthorized slot
and are bounced to /login; the route is preserved as returnUrl. *@
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<NotAuthorized>
@if (context.User.Identity?.IsAuthenticated != true)
{
<RedirectToLogin/>
}
else
{
<LayoutView Layout="@typeof(MainLayout)">
<p class="text-danger">You do not have permission to view this page.</p>
</LayoutView>
}
</NotAuthorized>
<Authorizing>
<LayoutView Layout="@typeof(MainLayout)"><p>Authorizing…</p></LayoutView>
</Authorizing>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)"><p>Not found.</p></LayoutView>
</NotFound>
</Router>