Consolidate LDAP roles into OPC UA session roles with granular write permissions

Map LDAP groups to custom OPC UA role NodeIds on RoleBasedIdentity.GrantedRoleIds
during authentication, replacing the username-to-role side cache. Split ReadWrite
into WriteOperate/WriteTune/WriteConfigure so write access is gated per Galaxy
security classification. AnonymousCanWrite now behaves consistently regardless
of LDAP state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-03-29 01:50:16 -04:00
parent 50b9603465
commit 50b85d41bd
21 changed files with 549 additions and 94 deletions

View File

@@ -63,15 +63,17 @@ The `ServiceLevel` is updated whenever MXAccess connection state changes or Gala
`UserTokenPolicies` are dynamically configured based on the `Authentication` settings in `appsettings.json`:
- An `Anonymous` user token policy is added when `AllowAnonymous` is `true` (the default).
- A `UserName` user token policy is added when `Ldap.Enabled` is `true`.
- A `UserName` user token policy is added when an authentication provider is configured (LDAP or injected).
Both policies can be active simultaneously, allowing clients to connect with or without credentials.
### Session impersonation
When a client presents `UserName` credentials, the server validates them through `IUserAuthenticationProvider`. If LDAP authentication is enabled, credentials are validated via LDAP bind and group membership determines the user's application-level roles (`ReadOnly`, `ReadWrite`, `AlarmAck`). If validation fails, the session is rejected.
When a client presents `UserName` credentials, the server validates them through `IUserAuthenticationProvider`. If the provider also implements `IRoleProvider` (as `LdapAuthenticationProvider` does), LDAP group membership is resolved once during authentication and mapped to custom OPC UA role `NodeId`s in a dedicated `urn:zbmom:lmxopcua:roles` namespace. These role NodeIds are added to the session's `RoleBasedIdentity.GrantedRoleIds`.
On successful validation, the session identity is set to a `RoleBasedIdentity` that carries the user's granted role IDs. Authenticated users receive the `WellKnownRole_AuthenticatedUser` role. Anonymous connections receive the `WellKnownRole_Anonymous` role. When LDAP is enabled, application-level roles from group membership control write and alarm-ack permissions. Without LDAP, `AnonymousCanWrite` controls whether anonymous users can write.
Anonymous sessions receive `WellKnownRole_Anonymous`. Authenticated sessions receive `WellKnownRole_AuthenticatedUser` plus any LDAP-derived role NodeIds. Permission checks in `LmxNodeManager` inspect `GrantedRoleIds` directly — no username extraction or side-channel cache is needed.
`AnonymousCanWrite` controls whether anonymous sessions can write, regardless of whether LDAP is enabled.
## Certificate handling