diff --git a/src/MongoDB.Driver/Core/Configuration/ConnectionString.cs b/src/MongoDB.Driver/Core/Configuration/ConnectionString.cs index a72a6d39b4b..79349c035cc 100644 --- a/src/MongoDB.Driver/Core/Configuration/ConnectionString.cs +++ b/src/MongoDB.Driver/Core/Configuration/ConnectionString.cs @@ -684,7 +684,7 @@ private ConnectionString BuildResolvedConnectionString(ConnectionStringScheme re .AllKeys .SelectMany(key => resolvedOptions .GetValues(key) - .Select(value => $"{key}={Uri.EscapeDataString(value)}"))); + .Select(value => $"{key}={EscapeOptionValue(key, value)}"))); if (mergedOptions.Count > 0) { @@ -692,21 +692,22 @@ private ConnectionString BuildResolvedConnectionString(ConnectionStringScheme re } return new ConnectionString(connectionString, isResolved: true); + + string EscapeOptionValue(string key, string value) + => string.Equals(key, "authmechanismproperties", StringComparison.OrdinalIgnoreCase) ? value : Uri.EscapeDataString(value); + } private void ExtractScheme(Match match) { var schemeGroup = match.Groups["scheme"]; - if (schemeGroup.Success) + if (schemeGroup.Success && schemeGroup.Value == "mongodb+srv") { - if (schemeGroup.Value == "mongodb+srv") + _scheme = ConnectionStringScheme.MongoDBPlusSrv; + if (!_tls.HasValue) { - _scheme = ConnectionStringScheme.MongoDBPlusSrv; - if (!_tls.HasValue) - { - _tls = true; - _allOptions.Add("tls", "true"); - } + _tls = true; + _allOptions.Add("tls", "true"); } } } @@ -761,7 +762,13 @@ private void ExtractOptions(Match match) var parts = option.Value.Split('='); var name = parts[0].Trim(); var value = parts[1].Trim(); - _allOptions.Add(name, Uri.UnescapeDataString(value)); + // Should not decode authmechanismproperties before splitting by separator. + if (!string.Equals(name, "authmechanismproperties", StringComparison.OrdinalIgnoreCase)) + { + value = Uri.UnescapeDataString(value); + } + + _allOptions.Add(name, value); ParseOption(name, value); } } @@ -905,12 +912,6 @@ string ProtectConnectionString(string connectionString) private void ParseOption(string name, string value) { - // Should not decode authmechanismproperties before splitting by separator. - if (!string.Equals(name, "authmechanismproperties", StringComparison.OrdinalIgnoreCase)) - { - value = Uri.UnescapeDataString(value); - } - switch (name.ToLowerInvariant()) { case "appname": diff --git a/tests/MongoDB.Driver.Tests/MongoCredentialTests.cs b/tests/MongoDB.Driver.Tests/MongoCredentialTests.cs index a3e9d69b039..8b1c38ee667 100644 --- a/tests/MongoDB.Driver.Tests/MongoCredentialTests.cs +++ b/tests/MongoDB.Driver.Tests/MongoCredentialTests.cs @@ -155,5 +155,29 @@ public void TestMechanismProperty() Assert.Equal("awesome", withProperties.GetMechanismProperty("SPN", null)); Assert.Equal(10, withProperties.GetMechanismProperty("OTHER", 0)); } + + [Theory] + [InlineData("mongodb+srv:///?retryWrites=true&authMechanism=MONGODB-OIDC&authSource=%24external&authMechanismProperties=ENVIRONMENT:azure,prop:ab%2Ccd%2Cef%2Cjh,TOKEN_RESOURCE:mongodb%3A%2F%2Ftest-cluster,ANOTHER:test")] + [InlineData("mongodb+srv:///?retryWrites=true&authMechanism=MONGODB-OIDC&authSource=%24external&authMechanismProperties=ENVIRONMENT:azure,prop:ab%2Ccd%2Cef%2Cjh,TOKEN_RESOURCE:mongodb://test-cluster,ANOTHER:test")] + public void TestMechanismPropertyFromUnresolvedConnectionString(string url) + { + var mongoConnection = MongoClientSettings.FromConnectionString(url); + mongoConnection.Credential.GetMechanismProperty("ENVIRONMENT", "").Should().Be("azure"); + mongoConnection.Credential.GetMechanismProperty("prop", "").Should().Be("ab,cd,ef,jh"); + mongoConnection.Credential.GetMechanismProperty("TOKEN_RESOURCE", "").Should().Be("mongodb://test-cluster"); + mongoConnection.Credential.GetMechanismProperty("ANOTHER", "").Should().Be("test"); + } + + [Theory] + [InlineData("mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authSource=$external&authMechanismProperties=ENVIRONMENT:azure,prop:ab%2Ccd%2Cef%2Cjh,TOKEN_RESOURCE:mongodb%3A%2F%2Ftest-cluster,ANOTHER:test")] + [InlineData("mongodb://user@localhost/?authMechanism=MONGODB-OIDC&authSource=$external&authMechanismProperties=ENVIRONMENT:azure,prop:ab%2Ccd%2Cef%2Cjh,TOKEN_RESOURCE:mongodb://test-cluster,ANOTHER:test")] + public void TestMechanismPropertyFromResolvedConnectionString(string url) + { + var mongoConnection = MongoClientSettings.FromConnectionString(url); + mongoConnection.Credential.GetMechanismProperty("ENVIRONMENT", "").Should().Be("azure"); + mongoConnection.Credential.GetMechanismProperty("prop", "").Should().Be("ab,cd,ef,jh"); + mongoConnection.Credential.GetMechanismProperty("TOKEN_RESOURCE", "").Should().Be("mongodb://test-cluster"); + mongoConnection.Credential.GetMechanismProperty("ANOTHER", "").Should().Be("test"); + } } }