Skip to content

Commit bc9f4da

Browse files
authored
Fail properly when Oracle url format is not supported (eclipse-vertx#1157)
Fixes eclipse-vertx#1155 The client should fail with a meaningful error message when an unsupported connection format is used, that is: - LDAP syntax - Oracle TNS URL Signed-off-by: Thomas Segismont <tsegismont@gmail.com>
1 parent 48cd465 commit bc9f4da

File tree

3 files changed

+97
-48
lines changed

3 files changed

+97
-48
lines changed

vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleConnectionUriParser.java

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@
1515

1616
import java.net.URLDecoder;
1717
import java.nio.charset.StandardCharsets;
18+
import java.util.Locale;
1819

1920
import static io.vertx.oracleclient.ServerMode.of;
2021

2122
public class OracleConnectionUriParser {
2223

23-
public static final String SCHEME = "oracle:thin:";
24-
public static final String TCPS_PROTOCOL = "tcps://";
25-
public static final String TCP_PROTOCOL = "tcp://";
24+
private static final String SCHEME = "oracle:thin:";
2625

2726
public static JsonObject parse(String connectionUri) {
2827
return parse(connectionUri, true);
@@ -77,6 +76,20 @@ static ParsingStage initial(String connectionUri, JsonObject configuration) {
7776

7877
abstract ParsingStage doParse();
7978

79+
ParsingStage afterAtSign(int i) {
80+
if (i == connectionUri.length()) {
81+
throw new VertxException("Empty net location", true);
82+
}
83+
int j = connectionUri.indexOf("://", i);
84+
if (j >= i) {
85+
return new Protocol(connectionUri, i, j, configuration);
86+
}
87+
if (connectionUri.charAt(i) == '(') {
88+
throw new VertxException("TNS URL Format is not supported", true);
89+
}
90+
return hostOrIpV6(i);
91+
}
92+
8093
ParsingStage hostOrIpV6(int i) {
8194
return connectionUri.charAt(i) == '[' ? new Ipv6(connectionUri, i + 1, configuration) : new Host(connectionUri, i, configuration);
8295
}
@@ -128,7 +141,7 @@ ParsingStage doParse() {
128141
throw new VertxException("Did not find '@' sign", true);
129142
}
130143
if (i == beginIdx) {
131-
return new Protocol(connectionUri, beginIdx + 1, configuration);
144+
return afterAtSign(beginIdx + 1);
132145
}
133146
String userInfo = connectionUri.substring(beginIdx, i);
134147
String[] split = userInfo.split(userInfo.indexOf('/') >= 0 ? "/" : ":");
@@ -146,28 +159,34 @@ ParsingStage doParse() {
146159
configuration.put("user", decodeUrl(user));
147160
configuration.put("password", decodeUrl(password));
148161

149-
return new Protocol(connectionUri, i + 1, configuration);
162+
return afterAtSign(i + 1);
150163
}
151164
}
152165

153166
static class Protocol extends ParsingStage {
154167

155-
Protocol(String connectionUri, int beginIdx, JsonObject configuration) {
168+
final int endIdx;
169+
170+
Protocol(String connectionUri, int beginIdx, int endIdx, JsonObject configuration) {
156171
super(connectionUri, beginIdx, configuration);
172+
this.endIdx = endIdx;
157173
}
158174

159175
@Override
160176
ParsingStage doParse() {
161-
int i;
162-
if (connectionUri.startsWith(TCPS_PROTOCOL, beginIdx)) {
177+
if (beginIdx == endIdx) {
178+
throw new VertxException("Empty protocol", true);
179+
}
180+
String protocol = connectionUri.substring(beginIdx, endIdx).toLowerCase(Locale.ROOT);
181+
if (protocol.equals("ldap") || protocol.equals("ldaps")) {
182+
throw new VertxException("LDAP Syntax is not supported", true);
183+
}
184+
if (protocol.equals("tcps")) {
163185
configuration.put("ssl", true);
164-
i = beginIdx + TCPS_PROTOCOL.length();
165-
} else if (connectionUri.startsWith(TCP_PROTOCOL, beginIdx)) {
166-
i = beginIdx + TCP_PROTOCOL.length();
167-
} else {
168-
i = beginIdx;
186+
} else if (!protocol.equals("tcp")) {
187+
throw new VertxException("Unsupported protocol", true);
169188
}
170-
return hostOrIpV6(i);
189+
return hostOrIpV6(endIdx + 3);
171190
}
172191
}
173192

vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleDatabaseHelper.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222

2323
import static io.vertx.oracleclient.impl.Helper.getOrHandleSQLException;
2424
import static io.vertx.oracleclient.impl.Helper.runOrHandleSQLException;
25-
import static io.vertx.oracleclient.impl.OracleConnectionUriParser.SCHEME;
26-
import static io.vertx.oracleclient.impl.OracleConnectionUriParser.TCPS_PROTOCOL;
2725

2826
public class OracleDatabaseHelper {
2927

@@ -50,9 +48,9 @@ public static OracleDataSource createDataSource(OracleConnectOptions options) {
5048
* @return An Oracle Connection JDBC URL
5149
*/
5250
private static String composeJdbcUrl(OracleConnectOptions options) {
53-
StringBuilder url = new StringBuilder("jdbc:").append(SCHEME).append("@");
51+
StringBuilder url = new StringBuilder("jdbc:oracle:thin:@");
5452
if (options.isSsl()) {
55-
url.append(TCPS_PROTOCOL);
53+
url.append("tcps://");
5654
}
5755
String host = options.getHost();
5856
if (host.indexOf(':') >= 0) { // IPv6 address

vertx-oracle-client/src/test/java/io/vertx/oracleclient/impl/InvalidOracleConnectionUriParsingTest.java

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,52 +16,81 @@
1616
import org.junit.runners.Parameterized;
1717
import org.junit.runners.Parameterized.Parameters;
1818

19+
import java.util.function.BiConsumer;
20+
21+
import static java.util.Locale.ENGLISH;
1922
import static org.hamcrest.CoreMatchers.instanceOf;
2023
import static org.hamcrest.CoreMatchers.is;
2124
import static org.hamcrest.MatcherAssert.assertThat;
22-
import static org.junit.Assert.fail;
25+
import static org.junit.Assert.*;
2326

2427
@RunWith(Parameterized.class)
2528
public class InvalidOracleConnectionUriParsingTest {
2629

2730
@Parameters(name = "{0}: {1}")
28-
public static Object[][] data() {
31+
public static Object[][] testData() {
2932
Object[][] params = {
30-
{"null uri", null},
31-
{"uri with invalid scheme", "postgresql://user@?host=localhost&port=1234"},
32-
{"uri with no separated user/password", "oracle:thin:scott@myhost:1521:orcl"},
33-
{"uri with no separated user/password", "oracle:thin:scott@myhost:1521:orcl"},
34-
{"uri without password", "oracle:thin:scott/@myhost:1521:orcl"},
35-
{"uri without user", "oracle:thin:/tiger@myhost:1521:orcl"},
36-
{"uri with multiple user/password splitters", "oracle:thin:scott/tiger/dragon@myhost:1521:orcl"},
37-
{"uri without net location", "oracle:thin:scott/tiger"},
38-
{"uri without SID after host", "oracle:thin:scott/tiger@myhost"},
39-
{"uri without SID after port", "oracle:thin:scott/tiger@myhost:1521"},
40-
{"uri with empty SID", "oracle:thin:scott/tiger@myhost:1521:"},
41-
{"uri with invalid content after host", "oracle:thin:@[::1]sss:1521:orcl"},
42-
{"uri with invalid IPv6 address", "oracle:thin:@[:1521:orcl"},
43-
{"uri with empty host", "oracle:thin:@:1521:orcl"},
44-
{"uri with empty IPv6 address", "oracle:thin:@[]:1521:orcl"},
45-
{"uri with empty port", "oracle:thin:@myhost::orcl"},
46-
{"uri with invalid port", "oracle:thin:@myhost:7654645:orcl"},
47-
{"uri with multiple hosts and ports", "oracle:thin:scott/tiger@myhost1:1521,myhost2:1521:orcl"},
48-
{"uri with multiple hosts", "oracle:thin:scott/tiger@myhost1,myhost2:1521:orcl"},
49-
{"uri with empty props", "oracle:thin:scott/tiger@myhost:1521:orcl?"},
50-
{"uri with empty service name", "oracle:thin:scott/tiger@myhost:1521/"},
51-
{"uri with empty server mode", "oracle:thin:scott/tiger@myhost:1521/orcl:?prop=val"},
52-
{"uri with invalid server mode", "oracle:thin:scott/tiger@myhost:1521/orcl:foo"},
53-
{"uri with service name but empty instance name", "oracle:thin:scott/tiger@myhost:1521/orcl/"},
54-
{"uri with service name and server mode but empty instance name", "oracle:thin:scott/tiger@myhost:1521/orcl:shared/"},
55-
{"uri with empty prop", "oracle:thin:scott/tiger@myhost:1521:orcl?&prop2"},
56-
{"uri with prop having no value", "oracle:thin:scott/tiger@myhost:1521:orcl?prop1&prop2=val2"},
33+
testData("null uri", null),
34+
testData("uri with invalid scheme", "postgresql://user@?host=localhost&port=1234"),
35+
testData("uri with no separated user/password", "oracle:thin:scott@myhost:1521:orcl"),
36+
testData("uri with no separated user/password", "oracle:thin:scott@myhost:1521:orcl"),
37+
testData("uri without password", "oracle:thin:scott/@myhost:1521:orcl"),
38+
testData("uri without user", "oracle:thin:/tiger@myhost:1521:orcl"),
39+
testData("uri with multiple user/password splitters", "oracle:thin:scott/tiger/dragon@myhost:1521:orcl"),
40+
testData("uri without net location", "oracle:thin:scott/tiger"),
41+
testData("uri without SID after host", "oracle:thin:scott/tiger@myhost"),
42+
testData("uri without SID after port", "oracle:thin:scott/tiger@myhost:1521"),
43+
testData("uri with empty SID", "oracle:thin:scott/tiger@myhost:1521:"),
44+
testData("uri with invalid content after host", "oracle:thin:@[::1]sss:1521:orcl"),
45+
testData("uri with invalid IPv6 address", "oracle:thin:@[:1521:orcl"),
46+
testData("uri with empty host", "oracle:thin:@:1521:orcl"),
47+
testData("uri with empty IPv6 address", "oracle:thin:@[]:1521:orcl"),
48+
testData("uri with empty port", "oracle:thin:@myhost::orcl"),
49+
testData("uri with invalid port", "oracle:thin:@myhost:7654645:orcl"),
50+
testData("uri with multiple hosts and ports", "oracle:thin:scott/tiger@myhost1:1521,myhost2:1521:orcl"),
51+
testData("uri with multiple hosts", "oracle:thin:scott/tiger@myhost1,myhost2:1521:orcl"),
52+
testData("uri with empty props", "oracle:thin:scott/tiger@myhost:1521:orcl?"),
53+
testData("uri with empty service name", "oracle:thin:scott/tiger@myhost:1521/"),
54+
testData("uri with empty server mode", "oracle:thin:scott/tiger@myhost:1521/orcl:?prop=val"),
55+
testData("uri with invalid server mode", "oracle:thin:scott/tiger@myhost:1521/orcl:foo"),
56+
testData("uri with service name but empty instance name", "oracle:thin:scott/tiger@myhost:1521/orcl/"),
57+
testData("uri with service name and server mode but empty instance name", "oracle:thin:scott/tiger@myhost:1521/orcl:shared/"),
58+
testData("uri with empty prop", "oracle:thin:scott/tiger@myhost:1521:orcl?&prop2"),
59+
testData("uri with prop having no value", "oracle:thin:scott/tiger@myhost:1521:orcl?prop1&prop2=val2"),
60+
testData(
61+
"uri with ldap syntax", "oracle:thin:@ldap://ldap.acme.com:7777/sales,cn=OracleContext,dc=com",
62+
(s, e) -> {
63+
assertNotNull(e.getCause());
64+
assertTrue(e.getCause().getMessage().toLowerCase(ENGLISH).contains("ldap"));
65+
}),
66+
testData("uri with Oracle Net connection descriptor", "oracle:thin:@(DESCRIPTION=\n" +
67+
" (LOAD_BALANCE=on)\n" +
68+
"(ADDRESS_LIST=\n" +
69+
" (ADDRESS=(PROTOCOL=TCP)(HOST=host1) (PORT=1521))\n" +
70+
" (ADDRESS=(PROTOCOL=TCP)(HOST=host2)(PORT=1521)))\n" +
71+
" (CONNECT_DATA=(SERVICE_NAME=service_name)))",
72+
(s, e) -> {
73+
assertNotNull(e.getCause());
74+
assertTrue(e.getCause().getMessage().toLowerCase(ENGLISH).contains("tns url"));
75+
}),
5776
};
5877
return params;
5978
}
6079

80+
private static Object[] testData(String testName, String uri) {
81+
return testData(testName, uri, null);
82+
}
83+
84+
private static Object[] testData(String testName, String uri, BiConsumer<String, Exception> assertions) {
85+
return new Object[]{testName, uri, assertions};
86+
}
87+
6188
private final String connectionUri;
89+
private final BiConsumer<String, Exception> assertions;
6290

63-
public InvalidOracleConnectionUriParsingTest(@SuppressWarnings("unused") String name, String connectionUri) {
91+
public InvalidOracleConnectionUriParsingTest(@SuppressWarnings("unused") String name, String connectionUri, BiConsumer<String, Exception> assertions) {
6492
this.connectionUri = connectionUri;
93+
this.assertions = assertions;
6594
}
6695

6796
@Test
@@ -75,6 +104,9 @@ public void shouldFailToParseInvalidUri() {
75104
} else {
76105
assertThat(e, is(instanceOf(IllegalArgumentException.class)));
77106
}
107+
if (assertions != null) {
108+
assertions.accept(connectionUri, e);
109+
}
78110
}
79111
}
80112
}

0 commit comments

Comments
 (0)