using ZB.MOM.WW.Auth.Abstractions.Ldap; namespace ZB.MOM.WW.ScadaBridge.Security; /// /// Translates the shared enum returned by /// ZB.MOM.WW.Auth.Ldap's into the /// user-facing error strings ScadaBridge surfaced from its bespoke /// LdapAuthService before the Task 1.2 cutover. /// /// /// /// The cutover replaced ScadaBridge's hand-rolled LDAP client (which returned a /// pre-formatted ErrorMessage string) with the shared library service /// (which returns a structured code). This single /// adapter keeps the externally observable error text stable across the login /// (/auth/login, /auth/token) and Basic-Auth (ManagementService) /// surfaces so the user-visible behaviour does not regress. /// /// /// Message-mapping rationale, preserving the donor's deliberate security framing: /// /// and /// both map to the same generic /// "Invalid username or password." — a username-enumeration guard /// (Security): a "user not found" message must be indistinguishable from a /// "wrong password" message. /// (the directory returned /// two or more entries for the username) is a directory-data fault, not a /// user-credential one. The donor never attempted an ambiguous bind; the /// library rejects it outright. Surfaced as the misconfiguration message so /// the operator — not the user — is pointed at the cause. /// keeps the /// donor's distinct "service is misconfigured" wording (Security-019) so a /// system-side fault is not blamed on user input. NOTE: the library also maps /// connect/search infrastructure failures (directory unreachable) into this /// bucket, so this message now covers "directory unavailable at connect/search /// time" as well — see for the /// post-bind directory-outage case. /// keeps the donor's /// "directory is temporarily unavailable" wording (Security-012): a post-bind /// group-lookup failure means the directory is partially unavailable and the /// login is failed closed rather than admitting a roleless session. NOTE: the /// library additionally treats a successful-but-empty group set as /// , whereas the donor admitted /// an empty-group user as a successful (roleless) login — a documented /// behavioural deviation of the cutover. /// (the provider is turned off via /// Enabled = false) maps to a neutral "not available" message. /// /// /// public static class LdapAuthFailureMessages { /// The generic, enumeration-safe message for a bad-credentials / user-not-found failure. public const string InvalidCredentials = "Invalid username or password."; /// The system-misconfiguration message (service-account bind / ambiguous user / unreachable directory). public const string Misconfigured = "Authentication service is misconfigured. Contact an administrator."; /// The transient directory-outage message for a post-bind group-lookup failure. public const string DirectoryUnavailable = "The directory is temporarily unavailable. Please try again."; /// The provider-disabled message. public const string Disabled = "Authentication is not available."; /// The fallback message for an unrecognised failure code. public const string Generic = "Authentication failed."; /// /// Maps a to its user-facing message. A /// failure (which should not occur on a failed result) /// falls back to . /// /// The structured failure code from . /// The user-facing error string to surface. public static string ToMessage(LdapAuthFailure? failure) => failure switch { LdapAuthFailure.BadCredentials => InvalidCredentials, LdapAuthFailure.UserNotFound => InvalidCredentials, LdapAuthFailure.AmbiguousUser => Misconfigured, LdapAuthFailure.ServiceAccountBindFailed => Misconfigured, LdapAuthFailure.GroupLookupFailed => DirectoryUnavailable, LdapAuthFailure.Disabled => Disabled, _ => Generic, }; }