using Microsoft.Extensions.Options; using ZB.MOM.WW.Auth.Abstractions.Ldap; namespace ZB.MOM.WW.Auth.Ldap; /// /// Validates at startup so a misconfiguration fails fast at /// boot with a clear, field-naming message — rather than surfacing later as an opaque /// low-level error on the first real login attempt. /// /// /// Validation is skipped entirely when is false /// (a disabled provider's connection fields are inert). When enabled, four conditions /// are enforced: /// /// plaintext transport () is rejected unless /// is explicitly set (dev/test only); /// must be specified (no sane default host); /// must be specified (the DN root every /// search runs against); /// must be specified — an empty value /// would bind anonymously, defeating the search-then-bind authentication flow. /// /// public sealed class LdapOptionsValidator : IValidateOptions { /// public ValidateOptionsResult Validate(string? name, LdapOptions options) { ArgumentNullException.ThrowIfNull(options); // When LDAP is disabled, its connection fields are inert — do not require them. // A consumer that turns LDAP off should not have to supply a server/search-base/ // service-account just to satisfy startup validation. if (!options.Enabled) { return ValidateOptionsResult.Success; } if (options.Transport == LdapTransport.None && !options.AllowInsecure) { return ValidateOptionsResult.Fail( $"{nameof(LdapOptions.Transport)} is {nameof(LdapTransport.None)} (insecure/plaintext) " + $"but {nameof(LdapOptions.AllowInsecure)} is false. Enable TLS " + $"({nameof(LdapTransport.Ldaps)} or {nameof(LdapTransport.StartTls)}) " + $"or set {nameof(LdapOptions.AllowInsecure)} for dev/test."); } if (string.IsNullOrWhiteSpace(options.Server)) { return ValidateOptionsResult.Fail( $"{nameof(LdapOptions.Server)} is required but was empty or whitespace — " + "set it to the LDAP server hostname or IP (e.g. \"ldap.example.com\")."); } if (string.IsNullOrWhiteSpace(options.SearchBase)) { return ValidateOptionsResult.Fail( $"{nameof(LdapOptions.SearchBase)} is required but was empty or whitespace — " + "set it to the search-base DN (e.g. \"dc=example,dc=com\")."); } if (string.IsNullOrWhiteSpace(options.ServiceAccountDn)) { return ValidateOptionsResult.Fail( $"{nameof(LdapOptions.ServiceAccountDn)} is required but was empty or whitespace — " + "an empty value would bind anonymously. Set it to the service-account DN " + "(e.g. \"cn=svc,dc=example,dc=com\")."); } return ValidateOptionsResult.Success; } }