dashboard: role-based LDAP auth + hub bearer scheme, drop PathBase
Restructure dashboard auth around LDAP-driven Admin/Viewer roles, add a
bearer scheme so SignalR hubs (next commit) can authenticate without
forwarding the HttpOnly browser cookie, and mount the dashboard at the
host root instead of a configurable `/dashboard` prefix.
Configuration changes (breaking):
- `MxGateway:Dashboard:PathBase` removed — the dashboard now serves at `/`.
- `MxGateway:Dashboard:RequireAdminScope` removed — role checks replace
the single admin-scope claim.
- `MxGateway:Ldap:RequiredGroup` removed — replaced by `MxGateway:Dashboard:GroupToRole`,
a map from LDAP group name to dashboard role. Legal role values:
`Admin` and `Viewer`. Users whose LDAP groups don't intersect this
map are rejected at login (the existing fail-closed contract).
- appsettings.json ships a default mapping `{ GwAdmin: Admin, GwReader: Viewer }`.
Auth model:
- DashboardRoles: new static class with `Admin` and `Viewer` constants.
- DashboardAuthenticator.AuthenticateAsync: after LDAP bind, maps the
user's groups through `DashboardOptions.GroupToRole` and emits one
`ClaimTypes.Role` claim per resolved role. Empty result → login fails.
- DashboardAuthorizationRequirement now carries `RequiredRoles`; static
presets `AnyDashboardRole` (Viewer ∨ Admin) and `AdminOnly`.
- DashboardAuthorizationHandler checks `IsInRole` against the
requirement's role list instead of the old scope claim. The
`AuthenticationMode.Disabled` and `AllowAnonymousLocalhost` bypasses
are preserved.
- DashboardApiKeyAuthorization.CanManage now requires the `Admin` role
(was: required LDAP group membership). The constructor's IOptions
parameter is gone.
Policies / schemes:
- DashboardAuthenticationDefaults gains `ViewerPolicy`, `AdminPolicy`,
`HubClientsPolicy`, and `HubAuthenticationScheme`. The legacy
`AuthorizationPolicy` and `ScopeClaimType` constants are removed.
- DashboardServiceCollectionExtensions registers all three policies,
adds the cookie scheme and the HubToken bearer scheme side by side,
calls `AddSignalR()`, and hard-codes the cookie's login/logout/denied
paths to root-relative `/login` etc.
Hub bearer infrastructure (no hubs wired yet — next commit):
- HubTokenService: mints time-limited data-protected JSON tokens
carrying the user's name, NameIdentifier, and roles. 30-minute
lifetime, purpose `ZB.MOM.WW.MxGateway.Dashboard.HubToken.v1`.
- HubTokenAuthenticationHandler: validates the token from
`Authorization: Bearer …` or `?access_token=…` (WebSocket upgrade
query string) and rebuilds the principal.
Endpoint mapping:
- DashboardEndpointRouteBuilderExtensions drops the `MapGroup(pathBase)`
wrapper. Login/logout/denied and Razor component routes are now
mounted at `/`. The login form posts to `/login`. Razor components
require the new `ViewerPolicy`.
- All page `@page "/dashboard/X"` dual-route directives are removed —
pages live at their canonical roots (`@page "/"`, `@page "/sessions"`, …).
- App.razor and DashboardLayout.razor drop their PathBase computations.
EffectiveLdapConfiguration drops `RequiredGroup`; EffectiveDashboardConfiguration
drops `PathBase`/`RequireAdminScope` and gains `GroupToRole`. SettingsPage
renders the role mapping in place of the retired fields.
Tests updated:
- DashboardAuthenticatorTests: covers the new GroupToRole mapping
(short name + DN + multi-role).
- DashboardAuthorizationHandlerTests: split into Viewer-policy and
Admin-policy cases.
- DashboardApiKeyAuthorizationTests, DashboardApiKeyManagementServiceTests:
authorized principal now carries the `Admin` role claim.
- DashboardCookieOptionsTests: expects root-relative login/logout paths.
- GatewayApplicationTests: dashboard component routes registered at `/`,
`/sessions`, … and gated by `ViewerPolicy`. Filter on
`ComponentTypeMetadata` to ignore minimal-API endpoints sharing `/`.
- GatewayOptionsTests + Validator: drop PathBase / RequireAdminScope /
RequiredGroup assertions; add a `GroupToRole` value-validation case.
- DashboardLdapLiveTests: provides the default `GwAdmin` → `Admin`
mapping so the live LDAP bind resolves to a role.
Verification: 473 server tests, 275 worker tests (+9 dev-rig skips), 18
integration tests (live MxAccess + LDAP + Galaxy) all pass.
This commit is intentionally UI-neutral. The sidebar layout and the
SignalR hubs that consume the new HubToken scheme land in a follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,8 +24,7 @@
|
||||
"ServiceAccountPassword": "serviceaccount123",
|
||||
"UserNameAttribute": "cn",
|
||||
"DisplayNameAttribute": "cn",
|
||||
"GroupAttribute": "memberOf",
|
||||
"RequiredGroup": "GwAdmin"
|
||||
"GroupAttribute": "memberOf"
|
||||
},
|
||||
"Worker": {
|
||||
"ExecutablePath": "src\\ZB.MOM.WW.MxGateway.Worker\\bin\\x86\\Release\\ZB.MOM.WW.MxGateway.Worker.exe",
|
||||
@@ -50,13 +49,15 @@
|
||||
},
|
||||
"Dashboard": {
|
||||
"Enabled": true,
|
||||
"PathBase": "/dashboard",
|
||||
"RequireAdminScope": true,
|
||||
"AllowAnonymousLocalhost": true,
|
||||
"SnapshotIntervalMilliseconds": 1000,
|
||||
"RecentFaultLimit": 100,
|
||||
"RecentSessionLimit": 200,
|
||||
"ShowTagValues": false
|
||||
"ShowTagValues": false,
|
||||
"GroupToRole": {
|
||||
"GwAdmin": "Admin",
|
||||
"GwReader": "Viewer"
|
||||
}
|
||||
},
|
||||
"Protocol": {
|
||||
"WorkerProtocolVersion": 1,
|
||||
|
||||
Reference in New Issue
Block a user