From 62394f5b85d8b9ae35ccec80a75673d038516586 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Wed, 12 Aug 2026 04:16:23 -0400 Subject: [PATCH] chore(deps): move every ZB.MOM.WW pin to the newest published version Auth 0.1.5 -> 0.2.0, Health 0.2.0 -> 0.3.0, Secrets/.Abstractions/.Ui 0.6.1 -> 0.6.2. Theme, GalaxyRepository, Audit, Configuration, Telemetry and Telemetry.Serilog were already at the newest version on the feed. Checked against the shared-lib source rather than the version numbers, because these packages are versioned as a family and a bump is not by itself evidence that the package changed: - Auth 0.2.0 is the only one carrying content for us: LDAP backup-DC failover (FallbackServers, endpoint walk with sticky preference, boot-time entry validation). Purely additive; the default is empty, which leaves single-endpoint behaviour unchanged. - Health 0.3.0 carries a breaking change, but every line of it is in ZB.MOM.WW.Health.Akka, which we do not reference. No commit touched the core ZB.MOM.WW.Health package between 0.2.0 and 0.3.0. - Secrets 0.6.2 is a message-only change: one validator string literal gains mounted-volume guidance. SecretsStorePathRules is untouched. The four non-csproj files are not a separate feature. Configuration/ LdapOptions is a deliberate shadow of the shared type and carries an explicit warning to mirror any new upstream field, because AddZbLdapAuth binds the whole MxGateway:Ldap section onto the shared options. So FallbackServers is live on our config surface the moment the package lands, and without the mirror an operator could configure a backup DC that works but is invisible on the dashboard's Settings page. The Settings row renders "none" when empty, since that is the answer someone who believes a backup DC is configured actually needs. Entry syntax is deliberately NOT re-validated here: the shared validator already fails the boot on a malformed entry and owns the (internal) parser, so a second copy would drift. Note both validators skip entirely when Ldap:Enabled is false. Verified the binder is non-strict (ErrorOnUnknownConfiguration is unused anywhere in the tree), so the upgrade could not break startup on a newly-recognised key either way. Build 0 warnings / 0 errors; gateway suite 892/892, unchanged. The live LDAP tests are opt-in and were not run, so the failover path itself is covered only by the shared library's own tests. --- docs/GatewayConfiguration.md | 1 + .../ZB.MOM.WW.MxGateway.IntegrationTests.csproj | 4 ++-- .../Configuration/EffectiveLdapConfiguration.cs | 3 ++- .../GatewayConfigurationProvider.cs | 3 ++- .../Configuration/LdapOptions.cs | 15 +++++++++++++++ .../Components/Pages/SettingsPage.razor | 15 +++++++++++++++ .../ZB.MOM.WW.MxGateway.Server.csproj | 16 ++++++++-------- 7 files changed, 45 insertions(+), 12 deletions(-) diff --git a/docs/GatewayConfiguration.md b/docs/GatewayConfiguration.md index 1dc80a9..23bf2a4 100644 --- a/docs/GatewayConfiguration.md +++ b/docs/GatewayConfiguration.md @@ -254,6 +254,7 @@ dev/test GLAuth posture (`glauth.md`), not a production posture. | `MxGateway:Ldap:UserNameAttribute` | `cn` | LDAP attribute holding the login user name. | | `MxGateway:Ldap:DisplayNameAttribute` | `cn` | LDAP attribute holding the display name. | | `MxGateway:Ldap:GroupAttribute` | `memberOf` | LDAP attribute enumerating group membership (mapped to dashboard roles via `MxGateway:Dashboard:GroupToRole`). | +| `MxGateway:Ldap:FallbackServers` | *(empty)* | Ordered backup LDAP endpoints tried when the primary fails with a system-side error (connect/TLS, service-account bind, or search) — **not** when a user's credentials are simply wrong. Each entry is `host` (adopting `Port`) or `host:port`. Empty leaves single-endpoint behaviour exactly as before. Endpoint preference is sticky: the last endpoint that answered keeps being used until it fails. The `Transport` / `AllowInsecure` policy applies to every endpoint — a fallback is not a way to downgrade TLS. Entries are parsed at startup and a malformed one fails the boot, so a typo'd backup DC cannot lie dormant until the outage it exists to survive. Requires ZB.MOM.WW.Auth 0.2.0+. | When LDAP is enabled, `Server`, `SearchBase`, `ServiceAccountDn`, `ServiceAccountPassword`, and the attribute names must be non-blank, and `Port` diff --git a/src/ZB.MOM.WW.MxGateway.IntegrationTests/ZB.MOM.WW.MxGateway.IntegrationTests.csproj b/src/ZB.MOM.WW.MxGateway.IntegrationTests/ZB.MOM.WW.MxGateway.IntegrationTests.csproj index e8be761..a24bce5 100644 --- a/src/ZB.MOM.WW.MxGateway.IntegrationTests/ZB.MOM.WW.MxGateway.IntegrationTests.csproj +++ b/src/ZB.MOM.WW.MxGateway.IntegrationTests/ZB.MOM.WW.MxGateway.IntegrationTests.csproj @@ -22,8 +22,8 @@ (IntegrationTests-028). --> - - + + diff --git a/src/ZB.MOM.WW.MxGateway.Server/Configuration/EffectiveLdapConfiguration.cs b/src/ZB.MOM.WW.MxGateway.Server/Configuration/EffectiveLdapConfiguration.cs index e1e82a4..168a297 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/Configuration/EffectiveLdapConfiguration.cs +++ b/src/ZB.MOM.WW.MxGateway.Server/Configuration/EffectiveLdapConfiguration.cs @@ -11,4 +11,5 @@ public sealed record EffectiveLdapConfiguration( string ServiceAccountPassword, string UserNameAttribute, string DisplayNameAttribute, - string GroupAttribute); + string GroupAttribute, + IReadOnlyList FallbackServers); diff --git a/src/ZB.MOM.WW.MxGateway.Server/Configuration/GatewayConfigurationProvider.cs b/src/ZB.MOM.WW.MxGateway.Server/Configuration/GatewayConfigurationProvider.cs index 8fb4071..ae66052 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/Configuration/GatewayConfigurationProvider.cs +++ b/src/ZB.MOM.WW.MxGateway.Server/Configuration/GatewayConfigurationProvider.cs @@ -30,7 +30,8 @@ public sealed class GatewayConfigurationProvider(IOptions option ServiceAccountPassword: RedactedValue, UserNameAttribute: value.Ldap.UserNameAttribute, DisplayNameAttribute: value.Ldap.DisplayNameAttribute, - GroupAttribute: value.Ldap.GroupAttribute), + GroupAttribute: value.Ldap.GroupAttribute, + FallbackServers: value.Ldap.FallbackServers), Worker: new EffectiveWorkerConfiguration( ExecutablePath: value.Worker.ExecutablePath, WorkingDirectory: value.Worker.WorkingDirectory, diff --git a/src/ZB.MOM.WW.MxGateway.Server/Configuration/LdapOptions.cs b/src/ZB.MOM.WW.MxGateway.Server/Configuration/LdapOptions.cs index ebfb9e3..b8f5330 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/Configuration/LdapOptions.cs +++ b/src/ZB.MOM.WW.MxGateway.Server/Configuration/LdapOptions.cs @@ -68,4 +68,19 @@ public sealed class LdapOptions /// Gets the LDAP attribute name for group membership. public string GroupAttribute { get; init; } = "memberOf"; + + /// + /// Gets the ordered fallback LDAP endpoints ("host" or "host:port") the shared + /// provider walks when the primary fails with a system-side error. Empty (the default) leaves + /// single-endpoint behaviour unchanged. Mirrors + /// , added in + /// ZB.MOM.WW.Auth 0.2.0. + /// + /// Carried here only so the effective-config display does not hide a configured backup DC — + /// nothing on the gateway side reads it. Entry syntax is validated at boot by the shared + /// LdapOptionsValidator, which owns the (internal) parser; re-validating here would + /// mean a second, drifting copy of that grammar. + /// + /// + public IReadOnlyList FallbackServers { get; init; } = []; } diff --git a/src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/SettingsPage.razor b/src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/SettingsPage.razor index 628be01..2d57f39 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/SettingsPage.razor +++ b/src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/SettingsPage.razor @@ -26,6 +26,21 @@ else Run migrations@Snapshot.Configuration.Authentication.RunMigrationsOnStartup LDAP enabled@Snapshot.Configuration.Ldap.Enabled LDAP server@Snapshot.Configuration.Ldap.Server:@Snapshot.Configuration.Ldap.Port + + LDAP fallback servers + @* Rendered even when empty: "none" is the operationally interesting answer + on a host someone believes has a backup DC configured. *@ + + @if (Snapshot.Configuration.Ldap.FallbackServers.Count == 0) + { + none + } + else + { + @string.Join(", ", Snapshot.Configuration.Ldap.FallbackServers) + } + + LDAP transport@Snapshot.Configuration.Ldap.Transport LDAP search base@Snapshot.Configuration.Ldap.SearchBase LDAP service account@Snapshot.Configuration.Ldap.ServiceAccountDn diff --git a/src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj b/src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj index 93162cf..22b0147 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj +++ b/src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj @@ -10,20 +10,20 @@ - - - - + + + + - + - - - + + +