diff --git a/driver-core/src/main/com/mongodb/ConnectionString.java b/driver-core/src/main/com/mongodb/ConnectionString.java index f779ab7290..69db84eb07 100644 --- a/driver-core/src/main/com/mongodb/ConnectionString.java +++ b/driver-core/src/main/com/mongodb/ConnectionString.java @@ -1209,7 +1209,7 @@ private List parseHosts(final List rawHosts) { } int idx = host.indexOf("]:"); if (idx != -1) { - validatePort(host, host.substring(idx + 2)); + validatePort(host.substring(idx + 2)); } } else { int colonCount = countOccurrences(host, ":"); @@ -1218,7 +1218,7 @@ private List parseHosts(final List rawHosts) { + "Reserved characters such as ':' must be escaped according RFC 2396. " + "Any IPv6 address literal must be enclosed in '[' and ']' according to RFC 2732.", host)); } else if (colonCount == 1) { - validatePort(host, host.substring(host.indexOf(":") + 1)); + validatePort(host.substring(host.indexOf(":") + 1)); } } hosts.add(host); @@ -1227,19 +1227,17 @@ private List parseHosts(final List rawHosts) { return hosts; } - private void validatePort(final String host, final String port) { - boolean invalidPort = false; + private void validatePort(final String port) { try { int portInt = Integer.parseInt(port); if (portInt <= 0 || portInt > 65535) { - invalidPort = true; + throw new IllegalArgumentException("The connection string contains an invalid host and port. " + + "The port must be an integer between 0 and 65535."); } } catch (NumberFormatException e) { - invalidPort = true; - } - if (invalidPort) { - throw new IllegalArgumentException(format("The connection string contains an invalid host '%s'. " - + "The port '%s' is not a valid, it must be an integer between 0 and 65535", host, port)); + throw new IllegalArgumentException("The connection string contains an invalid host and port. " + + "The port contains non-digit characters, it must be an integer between 0 and 65535. " + + "Hint: username and password must be escaped according to RFC 3986."); } } diff --git a/driver-core/src/test/unit/com/mongodb/ConnectionStringUnitTest.java b/driver-core/src/test/unit/com/mongodb/ConnectionStringUnitTest.java index bc905c9c6d..539a60ea5d 100644 --- a/driver-core/src/test/unit/com/mongodb/ConnectionStringUnitTest.java +++ b/driver-core/src/test/unit/com/mongodb/ConnectionStringUnitTest.java @@ -19,6 +19,7 @@ import com.mongodb.connection.ServerMonitoringMode; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.ValueSource; import java.io.UnsupportedEncodingException; @@ -27,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -92,4 +94,20 @@ void serverMonitoringMode() { () -> new ConnectionString(DEFAULT_OPTIONS + "serverMonitoringMode=invalid")) ); } + + + @ParameterizedTest + @ValueSource(strings = {"mongodb://foo:bar/@hostname/java?", "mongodb://foo:bar?@hostname/java/", + "mongodb+srv://foo:bar/@hostname/java?", "mongodb+srv://foo:bar?@hostname/java/", + "mongodb://foo:bar/@[::1]:27018", "mongodb://foo:bar?@[::1]:27018", + "mongodb://foo:12345678/@hostname", "mongodb+srv://foo:12345678/@hostname", + "mongodb://foo:12345678/@hostname", "mongodb+srv://foo:12345678/@hostname", + "mongodb://foo:12345678%40hostname", "mongodb+srv://foo:12345678%40hostname", + "mongodb://foo:12345678@bar@hostname", "mongodb+srv://foo:12345678@bar@hostname" + }) + void unescapedPasswordsShouldNotBeLeakedInExceptionMessages(final String input) { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new ConnectionString(input)); + assertFalse(exception.getMessage().contains("bar")); + assertFalse(exception.getMessage().contains("12345678")); + } }