feat(auth): cut ScadaBridge over to ZB.MOM.WW.Auth.Ldap; nest+rename Ldap config; roles+sitescope via IGroupRoleMapper (Task 1.2/1.4)

This commit is contained in:
Joseph Doherty
2026-06-02 01:04:34 -04:00
parent 9230afa25f
commit ac34dac479
31 changed files with 647 additions and 1132 deletions
@@ -1,82 +1,20 @@
namespace ZB.MOM.WW.ScadaBridge.Security;
/// <summary>
/// Non-LDAP security configuration: the cookie-embedded JWT signing/lifetime
/// settings and the session idle-timeout / cookie-security policy.
/// </summary>
/// <remarks>
/// Task 1.2/1.4 cutover: the LDAP connection settings that used to live here as
/// flat <c>Ldap*</c> keys (server, port, transport, search base, service account,
/// attributes, timeout) moved into a nested <c>ScadaBridge:Security:Ldap</c>
/// sub-section bound to the shared <c>ZB.MOM.WW.Auth.Abstractions.Ldap.LdapOptions</c>
/// and registered via <c>AddZbLdapAuth</c>. This is a BREAKING config-key change —
/// see CHANGELOG. The non-LDAP fields below are unchanged and still bound from
/// <c>ScadaBridge:Security</c>.
/// </remarks>
public class SecurityOptions
{
/// <summary>Hostname or IP address of the LDAP server.</summary>
public string LdapServer { get; set; } = string.Empty;
/// <summary>TCP port for the LDAP connection (default 389; 636 for LDAPS).</summary>
public int LdapPort { get; set; } = 389;
/// <summary>
/// Transport security mode for the LDAP connection. Defaults to LDAPS.
/// Use <see cref="LdapTransport.StartTls"/> to connect on the plaintext port
/// and upgrade the session before binding.
/// </summary>
public LdapTransport LdapTransport { get; set; } = LdapTransport.Ldaps;
/// <summary>
/// True when the configured transport provides encryption (LDAPS or StartTLS).
/// Retained for backward compatibility: assigning a value maps onto
/// <see cref="LdapTransport"/> (true =&gt; LDAPS, false =&gt; None).
/// </summary>
public bool LdapUseTls
{
get => LdapTransport != LdapTransport.None;
set => LdapTransport = value ? LdapTransport.Ldaps : LdapTransport.None;
}
/// <summary>
/// Allow insecure (non-TLS) LDAP connections. ONLY for dev/test with GLAuth.
/// Must be false in production.
/// </summary>
public bool AllowInsecureLdap { get; set; } = false;
/// <summary>
/// Base DN for LDAP searches (e.g., "dc=example,dc=com").
/// </summary>
public string LdapSearchBase { get; set; } = string.Empty;
/// <summary>
/// Service account DN for LDAP user searches (e.g., "cn=admin,dc=example,dc=com").
/// Required for search-then-bind authentication. If empty, direct bind with
/// {LdapUserIdAttribute}={username},{LdapSearchBase} is attempted instead.
/// </summary>
public string LdapServiceAccountDn { get; set; } = string.Empty;
/// <summary>
/// LDAP attribute that identifies a user. Used both for the search-then-bind
/// filter (<c>({LdapUserIdAttribute}={username})</c>) and for constructing the
/// fallback bind DN when no service account is configured, so the two
/// authentication modes are interchangeable. Common values: <c>uid</c> (OpenLDAP),
/// <c>sAMAccountName</c> (Active Directory).
/// </summary>
public string LdapUserIdAttribute { get; set; } = "uid";
/// <summary>
/// Service account password for LDAP user searches.
/// </summary>
public string LdapServiceAccountPassword { get; set; } = string.Empty;
/// <summary>
/// LDAP attribute that contains the user's display name.
/// </summary>
public string LdapDisplayNameAttribute { get; set; } = "cn";
/// <summary>
/// LDAP attribute that contains group membership.
/// </summary>
public string LdapGroupAttribute { get; set; } = "memberOf";
/// <summary>
/// Network timeout, in milliseconds, applied to the LDAP socket connect and to
/// LDAP operations (bind/search). The synchronous Novell LDAP calls are wrapped
/// in <c>Task.Run</c>, where the <c>CancellationToken</c> only guards work-item
/// scheduling — it cannot interrupt an in-progress blocking call. This timeout is
/// the real safeguard: it bounds how long a hung LDAP server can pin a thread-pool
/// thread (Security-009). Default 10 seconds.
/// </summary>
public int LdapConnectionTimeoutMs { get; set; } = 10_000;
/// <summary>
/// Symmetric HMAC-SHA256 signing key for cookie-embedded JWTs. Must be at least
/// 32 bytes (256 bits) — validated at <see cref="JwtTokenService"/> construction.