feat(opcua,host): F13c LDAP-bound UserName validator
Adds IOpcUaUserAuthenticator seam in OpcUaServer.Security with a deny-all NullOpcUaUserAuthenticator default. OpcUaApplicationHost subscribes to SessionManager.ImpersonateUser after _application.Start so UserName tokens flow through the authenticator and either attach a UserIdentity to the session (Allow) or set IdentityValidationError = BadIdentityTokenRejected (Deny / authenticator exception). Anonymous + X509 tokens fall through to SDK defaults. LdapOpcUaUserAuthenticator (Host project) bridges to the same ILdapAuthService that AddOtOpcUaAuth uses for Admin cookies / JWT, so a single LDAP source-of-truth governs both Admin control plane and OPC UA data plane. Program.cs registers LdapOptions + LdapAuthService + IOpcUaUserAuthenticator on driver-role hosts; admin-only nodes are unchanged. OtOpcUaServerHostedService threads the resolved authenticator into OpcUaApplicationHost so the seam respects Host DI. 10 new tests: 6 in OpcUaServer.Tests cover the pure HandleImpersonation static method (success / denial / anonymous fallthrough / authenticator- throw / null-username / Null authenticator); 4 in Host.IntegrationTests cover the LdapOpcUaUserAuthenticator adapter (LDAP allow → Allow with roles, LDAP deny → Deny, exception → backend-error denial, display-name fallback). OpcUaServer suite is 40 / 40 green. Closes #104. Unblocks Task 60 (dual-endpoint + ServiceLevel tests) once #81 residual lands.
This commit is contained in:
@@ -12,9 +12,11 @@ using ZB.MOM.WW.OtOpcUa.Host;
|
||||
using ZB.MOM.WW.OtOpcUa.Host.Drivers;
|
||||
using ZB.MOM.WW.OtOpcUa.Host.Health;
|
||||
using ZB.MOM.WW.OtOpcUa.Host.OpcUa;
|
||||
using ZB.MOM.WW.OtOpcUa.OpcUaServer.Security;
|
||||
using ZB.MOM.WW.OtOpcUa.Runtime;
|
||||
using ZB.MOM.WW.OtOpcUa.Security;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Endpoints;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Ldap;
|
||||
|
||||
// Roles drive the entire conditional wiring below — see ZB.MOM.WW.OtOpcUa.Cluster.RoleParser.
|
||||
var roles = RoleParser.Parse(Environment.GetEnvironmentVariable("OTOPCUA_ROLES"));
|
||||
@@ -56,6 +58,15 @@ if (hasDriver)
|
||||
builder.Services.AddSingleton<DeferredAddressSpaceSink>();
|
||||
builder.Services.AddSingleton<IOpcUaAddressSpaceSink>(sp =>
|
||||
sp.GetRequiredService<DeferredAddressSpaceSink>());
|
||||
|
||||
// F13c — bind UserName tokens to the same LDAP backend the Admin cookie/JWT flows use.
|
||||
// ILdapAuthService is registered by AddOtOpcUaAuth on admin nodes; on driver-only nodes
|
||||
// it isn't, so we register the LDAP options + service unconditionally for driver hosts
|
||||
// to keep parity. The LdapAdapter falls back to Deny on any backend error.
|
||||
builder.Services.AddOptions<LdapOptions>().Bind(builder.Configuration.GetSection("Ldap"));
|
||||
builder.Services.AddSingleton<ILdapAuthService, LdapAuthService>();
|
||||
builder.Services.AddSingleton<IOpcUaUserAuthenticator, LdapOpcUaUserAuthenticator>();
|
||||
|
||||
builder.Services.AddHostedService<OtOpcUaServerHostedService>();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user