using Microsoft.Extensions.Logging;
using ZB.MOM.WW.OtOpcUa.OpcUaServer.Security;
using ZB.MOM.WW.OtOpcUa.Security.Ldap;
namespace ZB.MOM.WW.OtOpcUa.Host.OpcUa;
///
/// Production adapter that bridges OPC UA UserName
/// tokens to the same the Admin UI cookie/JWT flows use, so a
/// single LDAP source-of-truth governs both control-plane (Admin) and data-plane (OPC UA)
/// session identities. Roles flow through unchanged — the data-plane ACL evaluator reads
/// them off OperationContext.UserIdentity downstream.
///
public sealed class LdapOpcUaUserAuthenticator(
ILdapAuthService ldap,
ILogger logger)
: IOpcUaUserAuthenticator
{
public async Task AuthenticateUserNameAsync(string username, string password, CancellationToken ct)
{
try
{
var result = await ldap.AuthenticateAsync(username, password, ct).ConfigureAwait(false);
if (!result.Success)
{
return OpcUaUserAuthResult.Deny(result.Error ?? "Invalid credentials");
}
return OpcUaUserAuthResult.Allow(result.DisplayName ?? username, result.Roles);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
logger.LogWarning(ex, "LDAP authentication threw for OPC UA user {User}", username);
return OpcUaUserAuthResult.Deny("Authentication backend error");
}
}
}