diff --git a/docs/GatewayTesting.md b/docs/GatewayTesting.md index 89860d3..074a20f 100644 --- a/docs/GatewayTesting.md +++ b/docs/GatewayTesting.md @@ -236,10 +236,19 @@ LDAP groups resolve to the `Admin` role succeeds and emits the role claim; the password into `FailureMessage`; an unknown username fails authentication; and an unreachable LDAP server is absorbed into a failed result rather than throwing. +`appsettings.json` now ships the LDAP bind password as the unexpanded +`${secret:ldap/mxgateway/bind}` token (resolved at gateway startup by the +pre-host secrets expander, which this suite's bare `ConfigurationBuilder` +does not run). Before running the live LDAP suite, set +`MxGateway__Ldap__ServiceAccountPassword` to the real GLAuth service-account +password (dev value `serviceaccount123` for the shared GLAuth) so the suite +binds with the real password instead of the literal token. + Run the LDAP live tests explicitly: ```bash $env:MXGATEWAY_RUN_LIVE_LDAP_TESTS = "1" +$env:MxGateway__Ldap__ServiceAccountPassword = "serviceaccount123" dotnet test src/ZB.MOM.WW.MxGateway.IntegrationTests/ZB.MOM.WW.MxGateway.IntegrationTests.csproj --filter FullyQualifiedName~DashboardLdapLiveTests ``` diff --git a/src/ZB.MOM.WW.MxGateway.IntegrationTests/DashboardLdapLiveTests.cs b/src/ZB.MOM.WW.MxGateway.IntegrationTests/DashboardLdapLiveTests.cs index 513b60b..cd5cd69 100644 --- a/src/ZB.MOM.WW.MxGateway.IntegrationTests/DashboardLdapLiveTests.cs +++ b/src/ZB.MOM.WW.MxGateway.IntegrationTests/DashboardLdapLiveTests.cs @@ -161,12 +161,32 @@ public sealed class DashboardLdapLiveTests IConfiguration configuration = new ConfigurationBuilder() .AddJsonFile(appSettingsPath, optional: false) + .AddEnvironmentVariables() .Build(); // Same section production binds in AddZbLdapAuth(configuration, "MxGateway:Ldap"). // Get returns null only when the section is absent; appsettings.json always // carries it, so fall back to shared defaults defensively rather than throw. - return configuration.GetSection("MxGateway:Ldap").Get() + LibraryLdapOptions options = configuration.GetSection("MxGateway:Ldap").Get() ?? new LibraryLdapOptions(); + + // appsettings.json now ships the bind password as the unexpanded + // "${secret:ldap/mxgateway/bind}" token (resolved at gateway startup by the + // pre-host secrets expander, which this bare ConfigurationBuilder does not run). + // AddEnvironmentVariables() above lets MxGateway__Ldap__ServiceAccountPassword + // override the token with the real password. Fail loud rather than silently + // binding with the literal token string, which would make every live test in + // this file fail with a confusing LDAP bind error instead of an actionable one. + if (string.IsNullOrEmpty(options.ServiceAccountPassword) + || options.ServiceAccountPassword.StartsWith("${secret:", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Live LDAP tests require the real bind password via the " + + "MxGateway__Ldap__ServiceAccountPassword environment variable " + + "(appsettings now ships a ${secret:} token that this suite does not expand). " + + "Set it before running."); + } + + return options; } } diff --git a/src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs b/src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs index 93021d9..011e22c 100644 --- a/src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs +++ b/src/ZB.MOM.WW.MxGateway.Server/GatewayApplication.cs @@ -82,6 +82,9 @@ public static class GatewayApplication .BuildServiceProvider()) #pragma warning restore ASP0000 { + // Intentionally unconditional: the pre-host expander below needs the secrets + // store schema to exist before the first ${secret:} resolve. Secrets:RunMigrationsOnStartup + // governs only the runtime SecretsMigrationHostedService, not this bootstrap path. secretsProvider.GetRequiredService() .MigrateAsync(default).GetAwaiter().GetResult(); var resolver = secretsProvider.GetRequiredService();