From 0f57724a0c026381a16b9e8dca5c58d3757b6a02 Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Thu, 14 Aug 2025 11:10:08 +0200
Subject: [PATCH 1/5] Escape comma in Config Server environment setting, to fix
crash in URL masking
---
.../ConfigServer/ConfigServerClientOptions.cs | 2 +-
.../ConfigServerConfigurationProvider.cs | 2 +-
.../src/ConfigServer/ConfigurationSchema.json | 2 +-
...igServerConfigurationProviderTest.Settings.cs | 16 ++++++++++++++++
4 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs b/src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs
index 8a8c5f3e29..26f4183da7 100644
--- a/src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs
+++ b/src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs
@@ -32,7 +32,7 @@ public sealed class ConfigServerClientOptions : IValidateCertificatesOptions
public bool FailFast { get; set; }
///
- /// Gets or sets the environment used when accessing configuration data. Default value: "Production".
+ /// Gets or sets a comma-separated list of environments used when accessing configuration data. Default value: "Production".
///
[ConfigurationKeyName("Env")]
public string? Environment { get; set; } = "Production";
diff --git a/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs b/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
index 6c9441a596..ecd60535c6 100644
--- a/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
+++ b/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
@@ -638,7 +638,7 @@ internal Uri BuildConfigServerUri(string serverUri, string? label)
uriBuilder.Password = ClientOptions.Password;
}
- string pathSuffix = $"{ClientOptions.Name}/{ClientOptions.Environment}";
+ string pathSuffix = $"{ClientOptions.Name}/{WebUtility.UrlEncode(ClientOptions.Environment)}";
if (!string.IsNullOrWhiteSpace(label))
{
diff --git a/src/Configuration/src/ConfigServer/ConfigurationSchema.json b/src/Configuration/src/ConfigServer/ConfigurationSchema.json
index 18d867042d..8f9e677fc0 100644
--- a/src/Configuration/src/ConfigServer/ConfigurationSchema.json
+++ b/src/Configuration/src/ConfigServer/ConfigurationSchema.json
@@ -90,7 +90,7 @@
},
"Env": {
"type": "string",
- "description": "Gets or sets the environment used when accessing configuration data. Default value: \"Production\"."
+ "description": "Gets or sets a comma-separated list of environments used when accessing configuration data. Default value: \"Production\"."
},
"FailFast": {
"type": "boolean",
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
index f595ecb8aa..05587bba20 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
@@ -179,4 +179,20 @@ public void GetConfigServerUri_WithEndingSlash()
path.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
}
+
+ [Fact]
+ public void GetConfigServerUri_MultipleEnvironments_EncodesComma()
+ {
+ var options = new ConfigServerClientOptions
+ {
+ Name = "myName",
+ Environment = "one,two",
+ Label = "demo"
+ };
+
+ using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
+ string path = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+
+ path.Should().Be("http://localhost:8888/myName/one%2Ctwo/demo");
+ }
}
From c75c67e369237ebd9a4aafcd7f65df97ca3fea90 Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Thu, 14 Aug 2025 11:58:04 +0200
Subject: [PATCH 2/5] Additional hardening against special characters in Config
Server URL
---
.../ConfigServerConfigurationProvider.cs | 8 +--
...erverConfigurationProviderTest.Settings.cs | 51 +++++++++++++------
.../RegisterMultipleDiscoveryClientsTest.cs | 6 +--
3 files changed, 42 insertions(+), 23 deletions(-)
diff --git a/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs b/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
index ecd60535c6..8960c8607e 100644
--- a/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
+++ b/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
@@ -630,15 +630,15 @@ internal Uri BuildConfigServerUri(string serverUri, string? label)
if (!string.IsNullOrEmpty(ClientOptions.Username))
{
- uriBuilder.UserName = ClientOptions.Username;
+ uriBuilder.UserName = WebUtility.UrlEncode(ClientOptions.Username);
}
if (!string.IsNullOrEmpty(ClientOptions.Password))
{
- uriBuilder.Password = ClientOptions.Password;
+ uriBuilder.Password = WebUtility.UrlEncode(ClientOptions.Password);
}
- string pathSuffix = $"{ClientOptions.Name}/{WebUtility.UrlEncode(ClientOptions.Environment)}";
+ string pathSuffix = $"{WebUtility.UrlEncode(ClientOptions.Name)}/{WebUtility.UrlEncode(ClientOptions.Environment)}";
if (!string.IsNullOrWhiteSpace(label))
{
@@ -648,7 +648,7 @@ internal Uri BuildConfigServerUri(string serverUri, string? label)
label = label.Replace("/", "(_)", StringComparison.Ordinal);
}
- pathSuffix = $"{pathSuffix}/{label.Trim()}";
+ pathSuffix = $"{pathSuffix}/{WebUtility.UrlEncode(label)}";
}
if (!uriBuilder.Path.EndsWith('/'))
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
index 05587bba20..1cd6b6ccb9 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
@@ -79,9 +79,9 @@ public void GetConfigServerUri_NoLabel()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string path = provider.BuildConfigServerUri(options.Uri!, null).ToString();
+ string uri = provider.BuildConfigServerUri(options.Uri!, null).ToString();
- path.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}");
+ uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}");
}
[Fact]
@@ -95,9 +95,9 @@ public void GetConfigServerUri_WithLabel()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string path = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+ string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
- path.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}/{options.Label}");
+ uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}/{options.Label}");
}
[Fact]
@@ -111,9 +111,9 @@ public void GetConfigServerUri_WithLabelContainingSlash()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string path = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+ string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
- path.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}/myLabel(_)version");
+ uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}/myLabel(_)version");
}
[Fact]
@@ -127,9 +127,9 @@ public void GetConfigServerUri_WithExtraPathInfo()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string path = provider.BuildConfigServerUri(options.Uri, null).ToString();
+ string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
- path.Should().Be($"http://localhost:9999/myPath/path/{options.Name}/{options.Environment}");
+ uri.Should().Be($"http://localhost:9999/myPath/path/{options.Name}/{options.Environment}");
}
[Fact]
@@ -143,9 +143,9 @@ public void GetConfigServerUri_WithExtraPathInfo_NoEndingSlash()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string path = provider.BuildConfigServerUri(options.Uri, null).ToString();
+ string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
- path.Should().Be($"http://localhost:9999/myPath/path/{options.Name}/{options.Environment}");
+ uri.Should().Be($"http://localhost:9999/myPath/path/{options.Name}/{options.Environment}");
}
[Fact]
@@ -159,9 +159,9 @@ public void GetConfigServerUri_NoEndingSlash()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string path = provider.BuildConfigServerUri(options.Uri, null).ToString();
+ string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
- path.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
+ uri.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
}
[Fact]
@@ -175,9 +175,9 @@ public void GetConfigServerUri_WithEndingSlash()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string path = provider.BuildConfigServerUri(options.Uri, null).ToString();
+ string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
- path.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
+ uri.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
}
[Fact]
@@ -191,8 +191,27 @@ public void GetConfigServerUri_MultipleEnvironments_EncodesComma()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string path = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+ string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
- path.Should().Be("http://localhost:8888/myName/one%2Ctwo/demo");
+ uri.Should().Be("http://localhost:8888/myName/one%2Ctwo/demo");
+ }
+
+ [Fact]
+ public void GetConfigServerUri_EncodesSpecialCharacters()
+ {
+ var options = new ConfigServerClientOptions
+ {
+ Name = "my$<>:,\"'Name",
+ Environment = "@/&?:\"'",
+ Label = "^&$@#*<>+",
+ Username = "a\":?'*,b/\\&",
+ Password = "#&:$<>'/so,\"me"
+ };
+
+ using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
+ string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+
+ uri.Should().Be(
+ "http://a%22%3A%3F%27*%2Cb%2F%5C%26:%23%26%3A%24%3C%3E%27%2Fso%2C%22me@localhost:8888/my%24<>%3A%2C\"%27Name/%40%2F%26%3F%3A\"%27/^%26%24%40%23*<>%2B");
}
}
diff --git a/src/Discovery/test/HttpClients.Test/RegisterMultipleDiscoveryClientsTest.cs b/src/Discovery/test/HttpClients.Test/RegisterMultipleDiscoveryClientsTest.cs
index 5be363b7c8..98d8f09d57 100644
--- a/src/Discovery/test/HttpClients.Test/RegisterMultipleDiscoveryClientsTest.cs
+++ b/src/Discovery/test/HttpClients.Test/RegisterMultipleDiscoveryClientsTest.cs
@@ -602,8 +602,8 @@ public async Task EurekaWithUsernamePasswordInURL_SendsWithAuthHeader()
}
""";
- string username = WebUtility.UrlEncode("u$er?N@me");
- string password = WebUtility.UrlEncode(":p@ssw0rd=");
+ string username = WebUtility.UrlEncode("u$er?,N@me");
+ string password = WebUtility.UrlEncode(":p@ss,w0rd=");
var appSettings = new Dictionary
{
@@ -619,7 +619,7 @@ public async Task EurekaWithUsernamePasswordInURL_SendsWithAuthHeader()
var handler = new DelegateToMockHttpClientHandler();
- handler.Mock.Expect(HttpMethod.Get, "https://api.eureka-server.com/eureka/apps").WithHeaders("Authorization", "Basic dSRlcj9OQG1lOjpwQHNzdzByZD0=")
+ handler.Mock.Expect(HttpMethod.Get, "https://api.eureka-server.com/eureka/apps").WithHeaders("Authorization", "Basic dSRlcj8sTkBtZTo6cEBzcyx3MHJkPQ==")
.WithHeaders("X-Discovery-AllowRedirect", "false").Respond("application/json", applicationsResponse);
await using WebApplication webApplication = builder.Build();
From 33882da8705499ba798fd1056acd0f1c77082062 Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Thu, 14 Aug 2025 12:33:32 +0200
Subject: [PATCH 3/5] Fixed: allow colon to appear in password
---
src/Common/src/Common/Extensions/UriExtensions.cs | 2 +-
.../test/Common.Test/Extensions/UriExtensionsTest.cs | 12 ++++++++++++
.../src/RandomValue/RandomValueProvider.cs | 4 ++--
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/Common/src/Common/Extensions/UriExtensions.cs b/src/Common/src/Common/Extensions/UriExtensions.cs
index cbcf5f95fe..e1c400459b 100644
--- a/src/Common/src/Common/Extensions/UriExtensions.cs
+++ b/src/Common/src/Common/Extensions/UriExtensions.cs
@@ -48,7 +48,7 @@ public static bool TryGetUsernamePassword(this Uri uri, [NotNullWhen(true)] out
string userInfo = uri.GetComponents(UriComponents.UserInfo, UriFormat.UriEscaped);
- string[] parts = userInfo.Split(':');
+ string[] parts = userInfo.Split(':', 2);
if (parts.Length == 2)
{
diff --git a/src/Common/test/Common.Test/Extensions/UriExtensionsTest.cs b/src/Common/test/Common.Test/Extensions/UriExtensionsTest.cs
index 1372c85db6..fbfa1a9062 100644
--- a/src/Common/test/Common.Test/Extensions/UriExtensionsTest.cs
+++ b/src/Common/test/Common.Test/Extensions/UriExtensionsTest.cs
@@ -40,4 +40,16 @@ public void DoNotMaskIfNoBasicAuthentication()
masked.Should().Be(expected);
}
+
+ [Fact]
+ public void TryGetUsernamePassword_AllowsColonInPassword()
+ {
+ var uri = new Uri("http://username:pass::word@host.com");
+
+ bool result = uri.TryGetUsernamePassword(out string? username, out string? password);
+
+ result.Should().BeTrue();
+ username.Should().Be("username");
+ password.Should().Be("pass::word");
+ }
}
diff --git a/src/Configuration/src/RandomValue/RandomValueProvider.cs b/src/Configuration/src/RandomValue/RandomValueProvider.cs
index 6546a13633..8eed55e1c4 100644
--- a/src/Configuration/src/RandomValue/RandomValueProvider.cs
+++ b/src/Configuration/src/RandomValue/RandomValueProvider.cs
@@ -165,7 +165,7 @@ private long GetLong()
private int GetNextIntInRange(string range)
{
- string[] tokens = range.Split(',');
+ string[] tokens = range.Split(',', 2);
int.TryParse(tokens[0], CultureInfo.InvariantCulture, out int start);
if (tokens.Length == 1)
@@ -179,7 +179,7 @@ private int GetNextIntInRange(string range)
private long GetNextLongInRange(string range)
{
- string[] tokens = range.Split(',');
+ string[] tokens = range.Split(',', 2);
long.TryParse(tokens[0], CultureInfo.InvariantCulture, out long start);
if (tokens.Length == 1)
From 695de5f3d8697c25a19a34eb320c7fcfb5d214ef Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Fri, 15 Aug 2025 17:07:32 +0200
Subject: [PATCH 4/5] Throw early when Config Server URL(s) is/are invalid
---
.../ConfigServer/ConfigServerClientOptions.cs | 14 ++++++-
.../ConfigServerConfigurationProvider.cs | 24 +++++------
...rConfigurationBuilderExtensionsCoreTest.cs | 2 +-
...erverConfigurationBuilderExtensionsTest.cs | 2 +-
...ServerConfigurationProviderTest.Loading.cs | 41 +++++++++++++------
...erverConfigurationProviderTest.Settings.cs | 18 ++++----
.../ConfigServerConfigurationProviderTest.cs | 8 ++--
7 files changed, 67 insertions(+), 42 deletions(-)
diff --git a/src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs b/src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs
index 26f4183da7..d9ce59f505 100644
--- a/src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs
+++ b/src/Configuration/src/ConfigServer/ConfigServerClientOptions.cs
@@ -143,8 +143,18 @@ public bool ValidateCertificatesAlt
///
public IDictionary Headers { get; } = new Dictionary();
- internal IList GetUris()
+ internal List GetUris()
{
- return !string.IsNullOrEmpty(Uri) ? Uri.Split(CommaDelimiter, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) : [];
+ return Uri == null ? [] : Uri.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).Select(ParseSingleUri).ToList();
+ }
+
+ private static Uri ParseSingleUri(string uri)
+ {
+ if (!System.Uri.TryCreate(uri, UriKind.Absolute, out Uri? result))
+ {
+ throw new ConfigServerException("One or more Config Server URIs in configuration are invalid.");
+ }
+
+ return result;
}
}
diff --git a/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs b/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
index 8960c8607e..98be9996da 100644
--- a/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
+++ b/src/Configuration/src/ConfigServer/ConfigServerConfigurationProvider.cs
@@ -223,8 +223,6 @@ public override void Load()
// Adds client settings (e.g. spring:cloud:config:uri, etc.) to the Data dictionary
AddConfigServerClientOptions();
- string logUri = string.Join(',', ClientOptions.GetUris().Select(uri => new Uri(uri).ToMaskedString()));
-
if (ClientOptions is { Retry.Enabled: true, FailFast: true })
{
int attempts = 0;
@@ -232,7 +230,7 @@ public override void Load()
do
{
- _logger.LogDebug("Fetching configuration from server at: {Uri}", logUri);
+ _logger.LogDebug("Fetching configuration from server(s).");
try
{
@@ -240,7 +238,7 @@ public override void Load()
}
catch (ConfigServerException exception)
{
- _logger.LogWarning(exception, "Failed fetching configuration from server at: {Uri}.", logUri);
+ _logger.LogWarning(exception, "Failed fetching configuration from server(s).");
attempts++;
if (attempts < ClientOptions.Retry.MaxAttempts)
@@ -258,7 +256,7 @@ public override void Load()
while (true);
}
- _logger.LogDebug("Fetching configuration from server at: {Uri}", logUri);
+ _logger.LogDebug("Fetching configuration from server(s).");
return await DoLoadAsync(updateDictionary, cancellationToken);
}
@@ -266,8 +264,8 @@ public override void Load()
{
Exception? error = null;
- // Get arrays of Config Server uris to check
- IList uris = ClientOptions.GetUris();
+ // Get list of Config Server uris to check
+ List uris = ClientOptions.GetUris();
try
{
@@ -543,7 +541,7 @@ private void AddConfigServerClientOptions(Dictionary data)
}
}
- internal async Task RemoteLoadAsync(IEnumerable requestUris, string? label, CancellationToken cancellationToken)
+ internal async Task RemoteLoadAsync(List requestUris, string? label, CancellationToken cancellationToken)
{
_logger.LogTrace("Entered {Method}", nameof(RemoteLoadAsync));
@@ -552,11 +550,13 @@ private void AddConfigServerClientOptions(Dictionary data)
Exception? error = null;
- foreach (string requestUri in requestUris)
+ foreach (Uri requestUri in requestUris)
{
// Make Config Server URI from settings
Uri uri = BuildConfigServerUri(requestUri, label);
+ _logger.LogDebug("Trying to connect to Config Server at {RequestUri}", uri.ToMaskedString());
+
// Get the request message
_logger.LogTrace("Building HTTP request message");
HttpRequestMessage request = await GetRequestMessageAsync(uri, cancellationToken);
@@ -622,11 +622,11 @@ private void AddConfigServerClientOptions(Dictionary data)
///
/// The request URI for the Configuration Server.
///
- internal Uri BuildConfigServerUri(string serverUri, string? label)
+ internal Uri BuildConfigServerUri(Uri serverUri, string? label)
{
- ArgumentException.ThrowIfNullOrWhiteSpace(serverUri);
+ ArgumentNullException.ThrowIfNull(serverUri);
- var uriBuilder = new UriBuilder(new Uri(serverUri));
+ var uriBuilder = new UriBuilder(serverUri);
if (!string.IsNullOrEmpty(ClientOptions.Username))
{
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs
index 006a4608d5..9f3aa6f962 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs
@@ -44,7 +44,7 @@ public void AddConfigServer_WithLoggerFactorySucceeds()
IList logMessages = loggerProvider.GetAll();
logMessages.Should().Contain(
- "DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server at: http://localhost:8888/");
+ "DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server(s).");
}
[Fact]
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs
index 64a5630dd7..af3df14ae4 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs
@@ -185,7 +185,7 @@ public void AddConfigServer_WithLoggerFactorySucceeds()
IList logMessages = loggerProvider.GetAll();
logMessages.Should().Contain(
- "DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server at: http://localhost:8888/");
+ "DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server(s).");
}
[Theory]
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Loading.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Loading.cs
index a293e85687..e5f9f669ac 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Loading.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Loading.cs
@@ -13,18 +13,6 @@ namespace Steeltoe.Configuration.ConfigServer.Test;
public sealed partial class ConfigServerConfigurationProviderTest
{
- [Fact]
- public async Task RemoteLoadAsync_InvalidUri()
- {
- var options = new ConfigServerClientOptions();
- using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
-
- // ReSharper disable once AccessToDisposedClosure
- Func action = async () => await provider.RemoteLoadAsync([@"foobar\foobar\"], null, TestContext.Current.CancellationToken);
-
- await action.Should().ThrowExactlyAsync();
- }
-
[Fact]
public async Task RemoteLoadAsync_HostTimesOut()
{
@@ -35,9 +23,10 @@ public async Task RemoteLoadAsync_HostTimesOut()
var httpClientHandler = new SlowHttpClientHandler(1.Seconds(), new HttpResponseMessage());
using var provider = new ConfigServerConfigurationProvider(options, null, httpClientHandler, NullLoggerFactory.Instance);
+ List requestUris = [new("http://localhost:9999/app/profile")];
// ReSharper disable once AccessToDisposedClosure
- Func action = async () => await provider.RemoteLoadAsync(["http://localhost:9999/app/profile"], null, TestContext.Current.CancellationToken);
+ Func action = async () => await provider.RemoteLoadAsync(requestUris, null, TestContext.Current.CancellationToken);
(await action.Should().ThrowExactlyAsync()).WithInnerExceptionExactly();
}
@@ -506,6 +495,32 @@ public async Task Load_MultipleConfigServers_ReturnsNotFoundStatus__DoesNotConti
startup.RequestCount.Should().Be(1);
}
+ [Fact]
+ public async Task Load_UriInvalid_FailFastEnabled()
+ {
+ using var startup = new TestConfigServerStartup();
+ startup.ReturnStatus = [500];
+
+ await using WebApplication app = TestWebApplicationBuilderFactory.Create().Build();
+ startup.Configure(app);
+ await app.StartAsync(TestContext.Current.CancellationToken);
+
+ using TestServer server = app.GetTestServer();
+ server.BaseAddress = new Uri("http://localhost:8888");
+
+ ConfigServerClientOptions options = GetCommonOptions();
+ options.Uri = "http://username:p@ssword@localhost:8888";
+ options.FailFast = true;
+
+ using var httpClientHandler = new ForwardingHttpClientHandler(server.CreateHandler());
+ using var provider = new ConfigServerConfigurationProvider(options, null, httpClientHandler, NullLoggerFactory.Instance);
+
+ // ReSharper disable once AccessToDisposedClosure
+ Func action = async () => await provider.LoadInternalAsync(true, TestContext.Current.CancellationToken);
+
+ await action.Should().ThrowExactlyAsync().WithMessage("One or more Config Server URIs in configuration are invalid.");
+ }
+
[Fact]
public async Task Load_ConfigServerReturnsBadStatus_FailFastEnabled()
{
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
index 1cd6b6ccb9..8380debc6b 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.Settings.cs
@@ -79,7 +79,7 @@ public void GetConfigServerUri_NoLabel()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri!, null).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), null).ToString();
uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}");
}
@@ -95,7 +95,7 @@ public void GetConfigServerUri_WithLabel()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), options.Label).ToString();
uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}/{options.Label}");
}
@@ -111,7 +111,7 @@ public void GetConfigServerUri_WithLabelContainingSlash()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), options.Label).ToString();
uri.Should().Be($"{options.Uri}/{options.Name}/{options.Environment}/myLabel(_)version");
}
@@ -127,7 +127,7 @@ public void GetConfigServerUri_WithExtraPathInfo()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri), null).ToString();
uri.Should().Be($"http://localhost:9999/myPath/path/{options.Name}/{options.Environment}");
}
@@ -143,7 +143,7 @@ public void GetConfigServerUri_WithExtraPathInfo_NoEndingSlash()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri), null).ToString();
uri.Should().Be($"http://localhost:9999/myPath/path/{options.Name}/{options.Environment}");
}
@@ -159,7 +159,7 @@ public void GetConfigServerUri_NoEndingSlash()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri), null).ToString();
uri.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
}
@@ -175,7 +175,7 @@ public void GetConfigServerUri_WithEndingSlash()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri, null).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri), null).ToString();
uri.Should().Be($"http://localhost:9999/{options.Name}/{options.Environment}");
}
@@ -191,7 +191,7 @@ public void GetConfigServerUri_MultipleEnvironments_EncodesComma()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), options.Label).ToString();
uri.Should().Be("http://localhost:8888/myName/one%2Ctwo/demo");
}
@@ -209,7 +209,7 @@ public void GetConfigServerUri_EncodesSpecialCharacters()
};
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- string uri = provider.BuildConfigServerUri(options.Uri!, options.Label).ToString();
+ string uri = provider.BuildConfigServerUri(new Uri(options.Uri!), options.Label).ToString();
uri.Should().Be(
"http://a%22%3A%3F%27*%2Cb%2F%5C%26:%23%26%3A%24%3C%3E%27%2Fso%2C%22me@localhost:8888/my%24<>%3A%2C\"%27Name/%40%2F%26%3F%3A\"%27/^%26%24%40%23*<>%2B");
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs
index a25a8219e9..6638ca8c82 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationProviderTest.cs
@@ -145,7 +145,7 @@ public async Task GetRequestMessage_AddsBasicAuthIfUserNameAndPasswordInURL()
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- Uri requestUri = provider.BuildConfigServerUri(options.Uri, null);
+ Uri requestUri = provider.BuildConfigServerUri(new Uri(options.Uri), null);
HttpRequestMessage request = await provider.GetRequestMessageAsync(requestUri, TestContext.Current.CancellationToken);
request.Method.Should().Be(HttpMethod.Get);
@@ -169,7 +169,7 @@ public async Task GetRequestMessage_AddsBasicAuthIfUserNameAndPasswordInSettings
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- Uri requestUri = provider.BuildConfigServerUri(options.Uri, null);
+ Uri requestUri = provider.BuildConfigServerUri(new Uri(options.Uri), null);
HttpRequestMessage request = await provider.GetRequestMessageAsync(requestUri, TestContext.Current.CancellationToken);
request.Method.Should().Be(HttpMethod.Get);
@@ -193,7 +193,7 @@ public async Task GetRequestMessage_BasicAuthInSettingsOverridesUserNameAndPassw
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- Uri requestUri = provider.BuildConfigServerUri(options.Uri, null);
+ Uri requestUri = provider.BuildConfigServerUri(new Uri(options.Uri), null);
HttpRequestMessage request = await provider.GetRequestMessageAsync(requestUri, TestContext.Current.CancellationToken);
request.Method.Should().Be(HttpMethod.Get);
@@ -215,7 +215,7 @@ public async Task GetRequestMessage_AddsVaultToken_IfNeeded()
using var provider = new ConfigServerConfigurationProvider(options, null, null, NullLoggerFactory.Instance);
- Uri requestUri = provider.BuildConfigServerUri(options.Uri!, null);
+ Uri requestUri = provider.BuildConfigServerUri(new Uri(options.Uri!), null);
HttpRequestMessage request = await provider.GetRequestMessageAsync(requestUri, TestContext.Current.CancellationToken);
request.Method.Should().Be(HttpMethod.Get);
From b9edbb31f10acdced125d010a8c006c3add62d7c Mon Sep 17 00:00:00 2001
From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com>
Date: Fri, 15 Aug 2025 17:22:53 +0200
Subject: [PATCH 5/5] Code cleanup
---
.../ConfigServerConfigurationBuilderExtensionsCoreTest.cs | 3 +--
.../ConfigServerConfigurationBuilderExtensionsTest.cs | 3 +--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs
index 9f3aa6f962..b78ec586fa 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsCoreTest.cs
@@ -43,8 +43,7 @@ public void AddConfigServer_WithLoggerFactorySucceeds()
IList logMessages = loggerProvider.GetAll();
- logMessages.Should().Contain(
- "DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server(s).");
+ logMessages.Should().Contain("DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server(s).");
}
[Fact]
diff --git a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs
index af3df14ae4..57ed14e112 100644
--- a/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs
+++ b/src/Configuration/test/ConfigServer.Test/ConfigServerConfigurationBuilderExtensionsTest.cs
@@ -184,8 +184,7 @@ public void AddConfigServer_WithLoggerFactorySucceeds()
IList logMessages = loggerProvider.GetAll();
- logMessages.Should().Contain(
- "DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server(s).");
+ logMessages.Should().Contain("DBUG Steeltoe.Configuration.ConfigServer.ConfigServerConfigurationProvider: Fetching configuration from server(s).");
}
[Theory]