From ea59586b5136d227bd97d18915598897f283482b Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Wed, 20 Sep 2023 08:47:54 +0200 Subject: [PATCH] SqlConnectOptions do extend NetClientOptions which eventually leads to use a TCP client per socket forcing to keep a map of clients in the connection factory. We should avoiding this design and instead move the relevant bits of NetClientOptions to SqlConnectOptions like the new ClientSSLOptions. After this, SqlConnectOptions does not extend NetClientOptions anymore and we can use a single TCP client in the connection factory which makes this easier to use. Thanks to the new TCP ConnectOptions the connection factory can specify the ClientSSLOptions when upgrading the connection to SSL. We will provide another way to specify NetClientOptions for a pool as this can still be useful for other reasons. --- .../db2client/DB2ConnectOptionsConverter.java | 6 + .../main/java/examples/DB2ClientExamples.java | 8 +- .../io/vertx/db2client/DB2ConnectOptions.java | 96 ++------ .../db2client/impl/DB2ConnectionFactory.java | 5 +- .../io/vertx/db2client/junit/DB2Resource.java | 7 +- .../MSSQLConnectOptionsConverter.java | 6 + .../java/examples/MSSQLClientExamples.java | 5 +- .../mssqlclient/MSSQLConnectOptions.java | 231 +++--------------- .../impl/MSSQLConnectionFactory.java | 14 +- .../impl/MSSQLSocketConnection.java | 17 +- .../mssqlclient/MSSQLEncryptionTestBase.java | 5 +- .../java/examples/MySQLClientExamples.java | 4 +- .../mysqlclient/MySQLConnectOptions.java | 213 +--------------- .../impl/MySQLConnectionFactory.java | 24 +- .../impl/MySQLSocketConnection.java | 8 +- .../codec/InitialHandshakeCommandCodec.java | 2 +- .../impl/command/InitialHandshakeCommand.java | 8 + .../io/vertx/mysqlclient/MySQLTLSTest.java | 94 +++---- .../MySQLUnixDomainSocketTest.java | 15 +- .../oracleclient/OracleConnectOptions.java | 21 +- .../impl/OracleConnectionFactory.java | 2 +- .../impl/OracleDatabaseHelper.java | 8 +- .../main/java/examples/PgClientExamples.java | 3 +- .../io/vertx/pgclient/PgConnectOptions.java | 211 +--------------- .../pgclient/impl/InitiateSslHandler.java | 9 +- .../pgclient/impl/PgConnectionFactory.java | 27 +- .../pgclient/impl/PgSocketConnection.java | 5 +- .../io/vertx/pgclient/PgClientTestBase.java | 3 +- .../test/java/io/vertx/pgclient/TLSTest.java | 12 +- .../vertx/pgclient/UnixDomainSocketTest.java | 46 ++-- .../src/test/resources/tls/another.crt | 17 ++ .../templates/TemplateBuilderTest.java | 2 - .../sqlclient/SqlConnectOptionsConverter.java | 20 ++ .../io/vertx/sqlclient/SqlConnectOptions.java | 76 +++++- .../sqlclient/impl/ConnectionFactoryBase.java | 51 +--- .../java/io/vertx/sqlclient/spi/Driver.java | 11 +- 36 files changed, 389 insertions(+), 903 deletions(-) create mode 100644 vertx-pg-client/src/test/resources/tls/another.crt diff --git a/vertx-db2-client/src/main/generated/io/vertx/db2client/DB2ConnectOptionsConverter.java b/vertx-db2-client/src/main/generated/io/vertx/db2client/DB2ConnectOptionsConverter.java index 0c6b237ff4..29fa7c041f 100644 --- a/vertx-db2-client/src/main/generated/io/vertx/db2client/DB2ConnectOptionsConverter.java +++ b/vertx-db2-client/src/main/generated/io/vertx/db2client/DB2ConnectOptionsConverter.java @@ -20,6 +20,11 @@ public class DB2ConnectOptionsConverter { public static void fromJson(Iterable> json, DB2ConnectOptions obj) { for (java.util.Map.Entry member : json) { switch (member.getKey()) { + case "ssl": + if (member.getValue() instanceof Boolean) { + obj.setSsl((Boolean)member.getValue()); + } + break; case "pipeliningLimit": break; } @@ -31,6 +36,7 @@ public static void toJson(DB2ConnectOptions obj, JsonObject json) { } public static void toJson(DB2ConnectOptions obj, java.util.Map json) { + json.put("ssl", obj.isSsl()); json.put("pipeliningLimit", obj.getPipeliningLimit()); } } diff --git a/vertx-db2-client/src/main/java/examples/DB2ClientExamples.java b/vertx-db2-client/src/main/java/examples/DB2ClientExamples.java index 10b70dd7fb..62c94a9715 100644 --- a/vertx-db2-client/src/main/java/examples/DB2ClientExamples.java +++ b/vertx-db2-client/src/main/java/examples/DB2ClientExamples.java @@ -21,6 +21,7 @@ import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.JksOptions; import io.vertx.db2client.DB2ConnectOptions; import io.vertx.db2client.DB2Connection; @@ -258,9 +259,9 @@ public void connectSsl(Vertx vertx) { .setUser("user") .setPassword("secret") .setSsl(true) - .setTrustStoreOptions(new JksOptions() - .setPath("/path/to/keystore.p12") - .setPassword("keystoreSecret")); + .setSslOptions(new ClientSSLOptions().setTrustOptions(new JksOptions() + .setPath("/path/to/keystore.p12") + .setPassword("keystoreSecret"))); DB2Connection.connect(vertx, options) .onComplete(res -> { @@ -396,5 +397,4 @@ public void enumIntValues(SqlClient client) { } }); } - } diff --git a/vertx-db2-client/src/main/java/io/vertx/db2client/DB2ConnectOptions.java b/vertx-db2-client/src/main/java/io/vertx/db2client/DB2ConnectOptions.java index 1b8544cc7d..fde8993f4c 100644 --- a/vertx-db2-client/src/main/java/io/vertx/db2client/DB2ConnectOptions.java +++ b/vertx-db2-client/src/main/java/io/vertx/db2client/DB2ConnectOptions.java @@ -25,16 +25,7 @@ import io.vertx.codegen.annotations.DataObject; import io.vertx.codegen.annotations.GenIgnore; import io.vertx.core.json.JsonObject; -import io.vertx.core.net.ClientOptionsBase; -import io.vertx.core.net.JdkSSLEngineOptions; -import io.vertx.core.net.JksOptions; -import io.vertx.core.net.KeyCertOptions; -import io.vertx.core.net.NetClientOptions; -import io.vertx.core.net.OpenSSLEngineOptions; -import io.vertx.core.net.PemKeyCertOptions; -import io.vertx.core.net.PemTrustOptions; -import io.vertx.core.net.SSLEngineOptions; -import io.vertx.core.net.TrustOptions; +import io.vertx.core.net.*; import io.vertx.core.tracing.TracingPolicy; import io.vertx.db2client.impl.DB2ConnectionUriParser; import io.vertx.db2client.impl.drda.SQLState; @@ -77,6 +68,7 @@ public static DB2ConnectOptions fromUri(String connectionUri) throws IllegalArgu public static final boolean DEFAULT_USE_AFFECTED_ROWS = false; public static final int DEFAULT_PIPELINING_LIMIT = 1; // 256; // TODO default to 256 once implemented properly public static final Map DEFAULT_CONNECTION_ATTRIBUTES; + public static final boolean DEFAULT_SSL = false; static { Map defaultAttributes = new HashMap<>(); @@ -84,6 +76,7 @@ public static DB2ConnectOptions fromUri(String connectionUri) throws IllegalArgu DEFAULT_CONNECTION_ATTRIBUTES = Collections.unmodifiableMap(defaultAttributes); } + private boolean ssl = DEFAULT_SSL; private int pipeliningLimit = DEFAULT_PIPELINING_LIMIT; public DB2ConnectOptions() { @@ -100,12 +93,14 @@ public DB2ConnectOptions(SqlConnectOptions other) { if (other instanceof DB2ConnectOptions) { DB2ConnectOptions opts = (DB2ConnectOptions) other; this.pipeliningLimit = opts.pipeliningLimit; + this.ssl = opts.ssl; } } public DB2ConnectOptions(DB2ConnectOptions other) { super(other); this.pipeliningLimit = other.pipeliningLimit; + this.ssl = other.ssl; } @Override @@ -169,69 +164,23 @@ public DB2ConnectOptions setPreparedStatementCacheSqlLimit(int preparedStatement return (DB2ConnectOptions) super.setPreparedStatementCacheSqlLimit(preparedStatementCacheSqlLimit); } - @Override - public DB2ConnectOptions setSsl(boolean ssl) { - return (DB2ConnectOptions) super.setSsl(ssl); - } - - @Override - public DB2ConnectOptions setSslHandshakeTimeout(long sslHandshakeTimeout) { - return (DB2ConnectOptions) super.setSslHandshakeTimeout(sslHandshakeTimeout); - } - - @Override - public DB2ConnectOptions setSslHandshakeTimeoutUnit(TimeUnit sslHandshakeTimeoutUnit) { - return (DB2ConnectOptions) super.setSslHandshakeTimeoutUnit(sslHandshakeTimeoutUnit); - } - - @Override - public DB2ConnectOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) { - return (DB2ConnectOptions) super.setSslEngineOptions(sslEngineOptions); - } - - @Override - public DB2ConnectOptions setJdkSslEngineOptions(JdkSSLEngineOptions sslEngineOptions) { - return (DB2ConnectOptions) super.setJdkSslEngineOptions(sslEngineOptions); - } - - @Override - public DB2ConnectOptions setKeyCertOptions(KeyCertOptions options) { - return (DB2ConnectOptions) super.setKeyCertOptions(options); - } - - @Override - public DB2ConnectOptions setKeyStoreOptions(JksOptions options) { - return (DB2ConnectOptions) super.setKeyStoreOptions(options); - } - - @Override - public DB2ConnectOptions setOpenSslEngineOptions(OpenSSLEngineOptions sslEngineOptions) { - return (DB2ConnectOptions) super.setOpenSslEngineOptions(sslEngineOptions); - } - - @Override - public DB2ConnectOptions setPemKeyCertOptions(PemKeyCertOptions options) { - return (DB2ConnectOptions) super.setPemKeyCertOptions(options); - } - - @Override - public DB2ConnectOptions setPemTrustOptions(PemTrustOptions options) { - return (DB2ConnectOptions) super.setPemTrustOptions(options); - } - - @Override - public DB2ConnectOptions setTrustAll(boolean trustAll) { - return (DB2ConnectOptions) super.setTrustAll(trustAll); - } - - @Override - public DB2ConnectOptions setTrustOptions(TrustOptions options) { - return (DB2ConnectOptions) super.setTrustOptions(options); + /** + * + * @return is SSL/TLS enabled? + */ + public boolean isSsl() { + return ssl; } - @Override - public DB2ConnectOptions setTrustStoreOptions(JksOptions options) { - return (DB2ConnectOptions) super.setTrustStoreOptions(options); + /** + * Set whether SSL/TLS is enabled + * + * @param ssl true if enabled + * @return a reference to this, so the API can be used fluently + */ + public DB2ConnectOptions setSsl(boolean ssl) { + this.ssl = ssl; + return this; } public int getPipeliningLimit() { @@ -271,6 +220,11 @@ public DB2ConnectOptions addProperty(String key, String value) { return (DB2ConnectOptions) super.addProperty(key, value); } + @Override + public DB2ConnectOptions setSslOptions(ClientSSLOptions sslOptions) { + return (DB2ConnectOptions) super.setSslOptions(sslOptions); + } + /** * Initialize with the default options. */ diff --git a/vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2ConnectionFactory.java b/vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2ConnectionFactory.java index 47163934d6..d90c4dbbfb 100644 --- a/vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2ConnectionFactory.java +++ b/vertx-db2-client/src/main/java/io/vertx/db2client/impl/DB2ConnectionFactory.java @@ -50,10 +50,9 @@ protected Future doConnectInternal(DB2ConnectOptions options, Contex String database = options.getDatabase(); Map properties = options.getProperties(); int pipeliningLimit = options.getPipeliningLimit(); - NetClient netClient = netClient(options); - return netClient.connect(server).flatMap(so -> { + return client.connect(server).flatMap(so -> { VertxMetrics vertxMetrics = vertx.metricsSPI(); - ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", options.getMetricsName()) : null; + ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", tcpOptions.getMetricsName()) : null; DB2SocketConnection conn = new DB2SocketConnection((NetSocketInternal) so, metrics, options, cachePreparedStatements, preparedStatementCacheSize, preparedStatementCacheSqlFilter, pipeliningLimit, context); conn.init(); diff --git a/vertx-db2-client/src/test/java/io/vertx/db2client/junit/DB2Resource.java b/vertx-db2-client/src/test/java/io/vertx/db2client/junit/DB2Resource.java index 84bacba92c..4efd195c8f 100644 --- a/vertx-db2-client/src/test/java/io/vertx/db2client/junit/DB2Resource.java +++ b/vertx-db2-client/src/test/java/io/vertx/db2client/junit/DB2Resource.java @@ -15,6 +15,7 @@ */ package io.vertx.db2client.junit; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.JksOptions; import io.vertx.db2client.DB2ConnectOptions; import org.junit.rules.ExternalResource; @@ -101,9 +102,9 @@ public DB2ConnectOptions secureOptions() { return new DB2ConnectOptions(options()) .setPort(securePort) .setSsl(true) - .setTrustStoreOptions(new JksOptions() - .setPath("src/test/resources/tls/db2-keystore.p12") - .setPassword("db2test")); + .setSslOptions(new ClientSSLOptions().setTrustOptions(new JksOptions() + .setPath("src/test/resources/tls/db2-keystore.p12") + .setPassword("db2test"))); } public boolean isZOS() { diff --git a/vertx-mssql-client/src/main/generated/io/vertx/mssqlclient/MSSQLConnectOptionsConverter.java b/vertx-mssql-client/src/main/generated/io/vertx/mssqlclient/MSSQLConnectOptionsConverter.java index 36bf404647..2049da0db8 100644 --- a/vertx-mssql-client/src/main/generated/io/vertx/mssqlclient/MSSQLConnectOptionsConverter.java +++ b/vertx-mssql-client/src/main/generated/io/vertx/mssqlclient/MSSQLConnectOptionsConverter.java @@ -25,6 +25,11 @@ public static void fromJson(Iterable> json, obj.setPacketSize(((Number)member.getValue()).intValue()); } break; + case "ssl": + if (member.getValue() instanceof Boolean) { + obj.setSsl((Boolean)member.getValue()); + } + break; } } } @@ -35,5 +40,6 @@ public static void toJson(MSSQLConnectOptions obj, JsonObject json) { public static void toJson(MSSQLConnectOptions obj, java.util.Map json) { json.put("packetSize", obj.getPacketSize()); + json.put("ssl", obj.isSsl()); } } diff --git a/vertx-mssql-client/src/main/java/examples/MSSQLClientExamples.java b/vertx-mssql-client/src/main/java/examples/MSSQLClientExamples.java index 9b65d1606a..78962d2b64 100644 --- a/vertx-mssql-client/src/main/java/examples/MSSQLClientExamples.java +++ b/vertx-mssql-client/src/main/java/examples/MSSQLClientExamples.java @@ -12,6 +12,7 @@ package examples; import io.vertx.core.Vertx; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.PemTrustOptions; import io.vertx.docgen.Source; import io.vertx.mssqlclient.MSSQLConnectOptions; @@ -307,13 +308,13 @@ public void setSsl() { public void disableHostnameValidation() { MSSQLConnectOptions connectOptions = new MSSQLConnectOptions() .setSsl(true) - .setTrustAll(true); + .setSslOptions(new ClientSSLOptions().setTrustAll(true)); } public void usingTrustOptions() { MSSQLConnectOptions connectOptions = new MSSQLConnectOptions() .setSsl(true) - .setPemTrustOptions(new PemTrustOptions().addCertPath("/path/to/server-cert.pem")); + .setSslOptions(new ClientSSLOptions().setTrustOptions(new PemTrustOptions().addCertPath("/path/to/server-cert.pem"))); } public void infoHandler(MSSQLConnection connection) { diff --git a/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/MSSQLConnectOptions.java b/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/MSSQLConnectOptions.java index 982ce428fd..4be50010ae 100644 --- a/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/MSSQLConnectOptions.java +++ b/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/MSSQLConnectOptions.java @@ -12,18 +12,14 @@ package io.vertx.mssqlclient; import io.vertx.codegen.annotations.DataObject; -import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; import io.vertx.core.net.*; -import io.vertx.core.tracing.TracingPolicy; import io.vertx.mssqlclient.impl.MSSQLConnectionUriParser; import io.vertx.sqlclient.SqlConnectOptions; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; /** * Connect options for configuring {@link MSSQLConnection}. @@ -65,6 +61,7 @@ public static MSSQLConnectOptions fromUri(String connectionUri) throws IllegalAr public static final int MIN_PACKET_SIZE = 512; public static final int MAX_PACKET_SIZE = 32767; public static final int DEFAULT_PACKET_SIZE = 4096; + public static final boolean DEFAULT_SSL = false; static { Map defaultProperties = new HashMap<>(); @@ -73,6 +70,7 @@ public static MSSQLConnectOptions fromUri(String connectionUri) throws IllegalAr DEFAULT_PROPERTIES = defaultProperties; } + private boolean ssl; private int packetSize; public MSSQLConnectOptions() { @@ -99,6 +97,7 @@ public MSSQLConnectOptions(MSSQLConnectOptions other) { private void copyFields(MSSQLConnectOptions other) { packetSize = other.packetSize; + ssl = other.ssl; } @Override @@ -163,169 +162,23 @@ public MSSQLConnectOptions setPacketSize(int packetSize) { return this; } - @Override - public MSSQLConnectOptions setSendBufferSize(int sendBufferSize) { - return (MSSQLConnectOptions) super.setSendBufferSize(sendBufferSize); - } - - @Override - public MSSQLConnectOptions setReceiveBufferSize(int receiveBufferSize) { - return (MSSQLConnectOptions) super.setReceiveBufferSize(receiveBufferSize); - } - - @Override - public MSSQLConnectOptions setReuseAddress(boolean reuseAddress) { - return (MSSQLConnectOptions) super.setReuseAddress(reuseAddress); - } - - @Override - public MSSQLConnectOptions setReusePort(boolean reusePort) { - return (MSSQLConnectOptions) super.setReusePort(reusePort); - } - - @Override - public MSSQLConnectOptions setTrafficClass(int trafficClass) { - return (MSSQLConnectOptions) super.setTrafficClass(trafficClass); - } - - @Override - public MSSQLConnectOptions setTcpNoDelay(boolean tcpNoDelay) { - return (MSSQLConnectOptions) super.setTcpNoDelay(tcpNoDelay); - } - - @Override - public MSSQLConnectOptions setTcpKeepAlive(boolean tcpKeepAlive) { - return (MSSQLConnectOptions) super.setTcpKeepAlive(tcpKeepAlive); - } - - @Override - public MSSQLConnectOptions setSoLinger(int soLinger) { - return (MSSQLConnectOptions) super.setSoLinger(soLinger); - } - - @Override - public MSSQLConnectOptions setIdleTimeout(int idleTimeout) { - return (MSSQLConnectOptions) super.setIdleTimeout(idleTimeout); - } - - @Override - public MSSQLConnectOptions setIdleTimeoutUnit(TimeUnit idleTimeoutUnit) { - return (MSSQLConnectOptions) super.setIdleTimeoutUnit(idleTimeoutUnit); - } - - @Override - public MSSQLConnectOptions setKeyCertOptions(KeyCertOptions options) { - return (MSSQLConnectOptions) super.setKeyCertOptions(options); - } - - @Override - public MSSQLConnectOptions setKeyStoreOptions(JksOptions options) { - return (MSSQLConnectOptions) super.setKeyStoreOptions(options); - } - - @Override - public MSSQLConnectOptions setPfxKeyCertOptions(PfxOptions options) { - return (MSSQLConnectOptions) super.setPfxKeyCertOptions(options); - } - - @Override - public MSSQLConnectOptions setPemKeyCertOptions(PemKeyCertOptions options) { - return (MSSQLConnectOptions) super.setPemKeyCertOptions(options); - } - - @Override - public MSSQLConnectOptions setTrustOptions(TrustOptions options) { - return (MSSQLConnectOptions) super.setTrustOptions(options); - } - - @Override - public MSSQLConnectOptions setTrustStoreOptions(JksOptions options) { - return (MSSQLConnectOptions) super.setTrustStoreOptions(options); - } - - @Override - public MSSQLConnectOptions setPemTrustOptions(PemTrustOptions options) { - return (MSSQLConnectOptions) super.setPemTrustOptions(options); - } - - @Override - public MSSQLConnectOptions setPfxTrustOptions(PfxOptions options) { - return (MSSQLConnectOptions) super.setPfxTrustOptions(options); - } - - @Override - public MSSQLConnectOptions addEnabledCipherSuite(String suite) { - return (MSSQLConnectOptions) super.addEnabledCipherSuite(suite); - } - - @Override - public MSSQLConnectOptions addEnabledSecureTransportProtocol(String protocol) { - return (MSSQLConnectOptions) super.addEnabledSecureTransportProtocol(protocol); - } - - @Override - public MSSQLConnectOptions removeEnabledSecureTransportProtocol(String protocol) { - return (MSSQLConnectOptions) super.removeEnabledSecureTransportProtocol(protocol); - } - - @Override - public MSSQLConnectOptions setUseAlpn(boolean useAlpn) { - return (MSSQLConnectOptions) super.setUseAlpn(useAlpn); - } - - @Override - public MSSQLConnectOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) { - return (MSSQLConnectOptions) super.setSslEngineOptions(sslEngineOptions); - } - - @Override - public MSSQLConnectOptions setJdkSslEngineOptions(JdkSSLEngineOptions sslEngineOptions) { - return (MSSQLConnectOptions) super.setJdkSslEngineOptions(sslEngineOptions); - } - - @Override - public MSSQLConnectOptions setTcpFastOpen(boolean tcpFastOpen) { - return (MSSQLConnectOptions) super.setTcpFastOpen(tcpFastOpen); - } - - @Override - public MSSQLConnectOptions setTcpCork(boolean tcpCork) { - return (MSSQLConnectOptions) super.setTcpCork(tcpCork); - } - - @Override - public MSSQLConnectOptions setTcpQuickAck(boolean tcpQuickAck) { - return (MSSQLConnectOptions) super.setTcpQuickAck(tcpQuickAck); - } - - @Override - public MSSQLConnectOptions setOpenSslEngineOptions(OpenSSLEngineOptions sslEngineOptions) { - return (MSSQLConnectOptions) super.setOpenSslEngineOptions(sslEngineOptions); - } - - @Override - public MSSQLConnectOptions addCrlPath(String crlPath) throws NullPointerException { - return (MSSQLConnectOptions) super.addCrlPath(crlPath); - } - - @Override - public MSSQLConnectOptions addCrlValue(Buffer crlValue) throws NullPointerException { - return (MSSQLConnectOptions) super.addCrlValue(crlValue); - } - - @Override - public MSSQLConnectOptions setTrustAll(boolean trustAll) { - return (MSSQLConnectOptions) super.setTrustAll(trustAll); - } - - @Override - public MSSQLConnectOptions setConnectTimeout(int connectTimeout) { - return (MSSQLConnectOptions) super.setConnectTimeout(connectTimeout); + /** + * + * @return is SSL/TLS enabled? + */ + public boolean isSsl() { + return ssl; } - @Override - public MSSQLConnectOptions setMetricsName(String metricsName) { - return (MSSQLConnectOptions) super.setMetricsName(metricsName); + /** + * Set whether SSL/TLS is enabled + * + * @param ssl true if enabled + * @return a reference to this, so the API can be used fluently + */ + public MSSQLConnectOptions setSsl(boolean ssl) { + this.ssl = ssl; + return this; } @Override @@ -339,53 +192,28 @@ public MSSQLConnectOptions setReconnectInterval(long interval) { } @Override - public MSSQLConnectOptions setHostnameVerificationAlgorithm(String hostnameVerificationAlgorithm) { - return (MSSQLConnectOptions) super.setHostnameVerificationAlgorithm(hostnameVerificationAlgorithm); - } - - @Override - public MSSQLConnectOptions setLogActivity(boolean logEnabled) { - return (MSSQLConnectOptions) super.setLogActivity(logEnabled); - } - - @Override - public MSSQLConnectOptions setProxyOptions(ProxyOptions proxyOptions) { - return (MSSQLConnectOptions) super.setProxyOptions(proxyOptions); - } - - @Override - public MSSQLConnectOptions setLocalAddress(String localAddress) { - return (MSSQLConnectOptions) super.setLocalAddress(localAddress); + public MSSQLConnectOptions setCachePreparedStatements(boolean cachePreparedStatements) { + return (MSSQLConnectOptions) super.setCachePreparedStatements(cachePreparedStatements); } @Override - public MSSQLConnectOptions setEnabledSecureTransportProtocols(Set enabledSecureTransportProtocols) { - return (MSSQLConnectOptions) super.setEnabledSecureTransportProtocols(enabledSecureTransportProtocols); + public MSSQLConnectOptions setPreparedStatementCacheMaxSize(int preparedStatementCacheMaxSize) { + return (MSSQLConnectOptions) super.setPreparedStatementCacheMaxSize(preparedStatementCacheMaxSize); } @Override - public MSSQLConnectOptions setSslHandshakeTimeout(long sslHandshakeTimeout) { - return (MSSQLConnectOptions) super.setSslHandshakeTimeout(sslHandshakeTimeout); + public MSSQLConnectOptions setPreparedStatementCacheSqlFilter(Predicate predicate) { + return (MSSQLConnectOptions) super.setPreparedStatementCacheSqlFilter(predicate); } @Override - public MSSQLConnectOptions setSslHandshakeTimeoutUnit(TimeUnit sslHandshakeTimeoutUnit) { - return (MSSQLConnectOptions) super.setSslHandshakeTimeoutUnit(sslHandshakeTimeoutUnit); - } - - @Override - public MSSQLConnectOptions setTracingPolicy(TracingPolicy tracingPolicy) { - return (MSSQLConnectOptions) super.setTracingPolicy(tracingPolicy); - } - - @Override - public MSSQLConnectOptions setSsl(boolean ssl) { - return (MSSQLConnectOptions) super.setSsl(ssl); + public MSSQLConnectOptions setPreparedStatementCacheSqlLimit(int preparedStatementCacheSqlLimit) { + return (MSSQLConnectOptions) super.setPreparedStatementCacheSqlLimit(preparedStatementCacheSqlLimit); } @Override - public MSSQLConnectOptions setNonProxyHosts(List nonProxyHosts) { - return (MSSQLConnectOptions) super.setNonProxyHosts(nonProxyHosts); + public MSSQLConnectOptions setSslOptions(ClientSSLOptions sslOptions) { + return (MSSQLConnectOptions) super.setSslOptions(sslOptions); } /** @@ -399,6 +227,7 @@ protected void init() { this.setDatabase(DEFAULT_DATABASE); this.setProperties(new HashMap<>(DEFAULT_PROPERTIES)); packetSize = DEFAULT_PACKET_SIZE; + ssl = DEFAULT_SSL; } @Override diff --git a/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLConnectionFactory.java b/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLConnectionFactory.java index 3a2a16726e..3a0e372004 100644 --- a/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLConnectionFactory.java +++ b/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLConnectionFactory.java @@ -16,11 +16,10 @@ import io.vertx.core.Promise; import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.VertxInternal; -import io.vertx.core.net.NetClient; -import io.vertx.core.net.NetClientOptions; import io.vertx.core.net.NetSocket; import io.vertx.core.net.SocketAddress; import io.vertx.core.net.impl.NetSocketInternal; +import io.vertx.core.net.impl.SSLHelper; import io.vertx.core.spi.metrics.ClientMetrics; import io.vertx.core.spi.metrics.VertxMetrics; import io.vertx.mssqlclient.MSSQLConnectOptions; @@ -29,14 +28,16 @@ import io.vertx.sqlclient.impl.ConnectionFactoryBase; import java.util.Map; -import java.util.function.Supplier; import static io.vertx.mssqlclient.impl.codec.EncryptionLevel.*; public class MSSQLConnectionFactory extends ConnectionFactoryBase { + private final SSLHelper sslHelper; + public MSSQLConnectionFactory(VertxInternal vertx) { super(vertx); + sslHelper = new SSLHelper(SSLHelper.resolveEngineOptions(tcpOptions.getSslEngineOptions(), tcpOptions.isUseAlpn())); } @Override @@ -52,8 +53,7 @@ private Future connectOrRedirect(MSSQLConnectOptions options, Contex boolean clientSslConfig = options.isSsl(); int desiredPacketSize = options.getPacketSize(); // Always start unencrypted, the connection will be upgraded if client and server agree - NetClient netClient = netClient(new NetClientOptions(options).setSsl(false)); - return netClient.connect(server) + return client.connect(server) .map(so -> createSocketConnection(so, options, desiredPacketSize, context)) .compose(conn -> conn.sendPreLoginMessage(clientSslConfig) .compose(encryptionLevel -> login(conn, options, encryptionLevel, context)) @@ -72,8 +72,8 @@ private Future connectOrRedirect(MSSQLConnectOptions options, Contex private MSSQLSocketConnection createSocketConnection(NetSocket so, MSSQLConnectOptions options, int desiredPacketSize, ContextInternal context) { VertxMetrics vertxMetrics = vertx.metricsSPI(); - ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", options.getMetricsName()) : null; - MSSQLSocketConnection conn = new MSSQLSocketConnection((NetSocketInternal) so, metrics, options, desiredPacketSize, false, 0, sql -> true, 1, context); + ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", tcpOptions.getMetricsName()) : null; + MSSQLSocketConnection conn = new MSSQLSocketConnection((NetSocketInternal) so, sslHelper, metrics, options, desiredPacketSize, false, 0, sql -> true, 1, context); conn.init(); return conn; } diff --git a/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLSocketConnection.java b/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLSocketConnection.java index 640c3276a6..0d34832fbb 100644 --- a/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLSocketConnection.java +++ b/vertx-mssql-client/src/main/java/io/vertx/mssqlclient/impl/MSSQLSocketConnection.java @@ -17,7 +17,6 @@ import io.vertx.core.AsyncResult; import io.vertx.core.Future; import io.vertx.core.Handler; -import io.vertx.core.http.ClientAuth; import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.future.PromiseInternal; import io.vertx.core.net.ClientSSLOptions; @@ -50,11 +49,13 @@ public class MSSQLSocketConnection extends SocketConnectionBase { private final MSSQLConnectOptions connectOptions; private final int packetSize; + private final SSLHelper sslHelper; private MSSQLDatabaseMetadata databaseMetadata; private SocketAddress alternateServer; MSSQLSocketConnection(NetSocketInternal socket, + SSLHelper sslHelper, ClientMetrics clientMetrics, MSSQLConnectOptions connectOptions, int packetSize, @@ -66,6 +67,7 @@ public class MSSQLSocketConnection extends SocketConnectionBase { super(socket, clientMetrics, cachePreparedStatements, preparedStatementCacheSize, preparedStatementCacheSqlFilter, pipeliningLimit, context); this.connectOptions = connectOptions; this.packetSize = packetSize; + this.sslHelper = sslHelper; } @Override @@ -102,21 +104,18 @@ Future enableSsl(boolean clientConfigSsl, byte encryptionLevel, MSSQLConne } }); + ClientSSLOptions sslOptions = options.getSslOptions() == null ? new ClientSSLOptions() : options.getSslOptions().copy(); + // Do not perform hostname validation if the client did not require encryption if (!clientConfigSsl) { - options.setTrustAll(true); + sslOptions.setTrustAll(true); } // 2. Create and set up an SSLHelper and SSLHandler // options.getApplicationLayerProtocols() - SSLHelper helper = new SSLHelper(SSLHelper.resolveEngineOptions(options.getSslEngineOptions(), options.isUseAlpn())); - ClientSSLOptions sslOptions = options.getSslOptions(); - if (sslOptions == null) { - sslOptions = new ClientSSLOptions(); - } - Future f = helper.resolveSslChannelProvider(sslOptions, "", false, null, null, context); + Future f = sslHelper.resolveSslChannelProvider(sslOptions, "", false, null, null, context); return f.compose(provider -> { - SslHandler sslHandler = provider.createClientSslHandler(socket.remoteAddress(), null, options.isUseAlpn(), options.isTrustAll(), options.getSslHandshakeTimeout(), options.getSslHandshakeTimeoutUnit()); + SslHandler sslHandler = provider.createClientSslHandler(socket.remoteAddress(), null, sslOptions.isUseAlpn(), sslOptions.isTrustAll(), sslOptions.getSslHandshakeTimeout(), sslOptions.getSslHandshakeTimeoutUnit()); // 3. TdsSslHandshakeCodec manages SSL payload encapsulated in TDS packets TdsSslHandshakeCodec tdsSslHandshakeCodec = new TdsSslHandshakeCodec(); diff --git a/vertx-mssql-client/src/test/java/io/vertx/mssqlclient/MSSQLEncryptionTestBase.java b/vertx-mssql-client/src/test/java/io/vertx/mssqlclient/MSSQLEncryptionTestBase.java index cc1e060b91..05e074e72d 100644 --- a/vertx-mssql-client/src/test/java/io/vertx/mssqlclient/MSSQLEncryptionTestBase.java +++ b/vertx-mssql-client/src/test/java/io/vertx/mssqlclient/MSSQLEncryptionTestBase.java @@ -15,6 +15,7 @@ import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.PemTrustOptions; import io.vertx.ext.unit.TestContext; import io.vertx.mssqlclient.junit.MSSQLRule; @@ -93,7 +94,7 @@ public void testHostnameValidationFails(TestContext ctx) { public void testTrustAll(TestContext ctx) { setOptions(rule().options() .setSsl(true) - .setTrustAll(true)); + .setSslOptions(new ClientSSLOptions().setTrustAll(true))); asyncAssertConnectionEncrypted(ctx); } @@ -102,7 +103,7 @@ public void testTrustOptions(TestContext ctx) { Buffer certValue = vertx.fileSystem().readFileBlocking("mssql.pem"); setOptions(rule().options() .setSsl(true) - .setPemTrustOptions(new PemTrustOptions().addCertValue(certValue))); + .setSslOptions(new ClientSSLOptions().setTrustOptions(new PemTrustOptions().addCertValue(certValue)))); asyncAssertConnectionEncrypted(ctx); } } diff --git a/vertx-mysql-client/src/main/java/examples/MySQLClientExamples.java b/vertx-mysql-client/src/main/java/examples/MySQLClientExamples.java index b61d8ebe6d..66a06c621c 100644 --- a/vertx-mysql-client/src/main/java/examples/MySQLClientExamples.java +++ b/vertx-mysql-client/src/main/java/examples/MySQLClientExamples.java @@ -15,7 +15,9 @@ import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.PemTrustOptions; +import io.vertx.core.net.SSLOptions; import io.vertx.docgen.Source; import io.vertx.mysqlclient.*; import io.vertx.mysqlclient.data.spatial.Point; @@ -580,7 +582,7 @@ public void tlsExample(Vertx vertx) { .setUser("user") .setPassword("secret") .setSslMode(SslMode.VERIFY_CA) - .setPemTrustOptions(new PemTrustOptions().addCertPath("/path/to/cert.pem")); + .setSslOptions(new ClientSSLOptions().setTrustOptions(new PemTrustOptions().addCertPath("/path/to/cert.pem"))); MySQLConnection.connect(vertx, options) .onComplete(res -> { diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/MySQLConnectOptions.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/MySQLConnectOptions.java index d0bef295c8..9af09ddc34 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/MySQLConnectOptions.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/MySQLConnectOptions.java @@ -255,16 +255,6 @@ public MySQLConnectOptions setAuthenticationPlugin(MySQLAuthenticationPlugin aut return this; } - @Override - public MySQLConnectOptions setSsl(boolean ssl) { - if (ssl) { - setSslMode(SslMode.VERIFY_CA); - } else { - setSslMode(SslMode.DISABLED); - } - return this; - } - /** * Set the path of server RSA public key which is mostly used for encrypting password under insecure connections when performing authentication. * @@ -385,171 +375,6 @@ public MySQLConnectOptions addProperty(String key, String value) { return (MySQLConnectOptions) super.addProperty(key, value); } - @Override - public MySQLConnectOptions setSendBufferSize(int sendBufferSize) { - return (MySQLConnectOptions) super.setSendBufferSize(sendBufferSize); - } - - @Override - public MySQLConnectOptions setReceiveBufferSize(int receiveBufferSize) { - return (MySQLConnectOptions) super.setReceiveBufferSize(receiveBufferSize); - } - - @Override - public MySQLConnectOptions setReuseAddress(boolean reuseAddress) { - return (MySQLConnectOptions) super.setReuseAddress(reuseAddress); - } - - @Override - public MySQLConnectOptions setReusePort(boolean reusePort) { - return (MySQLConnectOptions) super.setReusePort(reusePort); - } - - @Override - public MySQLConnectOptions setTrafficClass(int trafficClass) { - return (MySQLConnectOptions) super.setTrafficClass(trafficClass); - } - - @Override - public MySQLConnectOptions setTcpNoDelay(boolean tcpNoDelay) { - return (MySQLConnectOptions) super.setTcpNoDelay(tcpNoDelay); - } - - @Override - public MySQLConnectOptions setTcpKeepAlive(boolean tcpKeepAlive) { - return (MySQLConnectOptions) super.setTcpKeepAlive(tcpKeepAlive); - } - - @Override - public MySQLConnectOptions setSoLinger(int soLinger) { - return (MySQLConnectOptions) super.setSoLinger(soLinger); - } - - @Override - public MySQLConnectOptions setIdleTimeout(int idleTimeout) { - return (MySQLConnectOptions) super.setIdleTimeout(idleTimeout); - } - - @Override - public MySQLConnectOptions setIdleTimeoutUnit(TimeUnit idleTimeoutUnit) { - return (MySQLConnectOptions) super.setIdleTimeoutUnit(idleTimeoutUnit); - } - - @Override - public MySQLConnectOptions setKeyCertOptions(KeyCertOptions options) { - return (MySQLConnectOptions) super.setKeyCertOptions(options); - } - - @Override - public MySQLConnectOptions setKeyStoreOptions(JksOptions options) { - return (MySQLConnectOptions) super.setKeyStoreOptions(options); - } - - @Override - public MySQLConnectOptions setPfxKeyCertOptions(PfxOptions options) { - return (MySQLConnectOptions) super.setPfxKeyCertOptions(options); - } - - @Override - public MySQLConnectOptions setPemKeyCertOptions(PemKeyCertOptions options) { - return (MySQLConnectOptions) super.setPemKeyCertOptions(options); - } - - @Override - public MySQLConnectOptions setTrustOptions(TrustOptions options) { - return (MySQLConnectOptions) super.setTrustOptions(options); - } - - @Override - public MySQLConnectOptions setTrustStoreOptions(JksOptions options) { - return (MySQLConnectOptions) super.setTrustStoreOptions(options); - } - - @Override - public MySQLConnectOptions setPemTrustOptions(PemTrustOptions options) { - return (MySQLConnectOptions) super.setPemTrustOptions(options); - } - - @Override - public MySQLConnectOptions setPfxTrustOptions(PfxOptions options) { - return (MySQLConnectOptions) super.setPfxTrustOptions(options); - } - - @Override - public MySQLConnectOptions addEnabledCipherSuite(String suite) { - return (MySQLConnectOptions) super.addEnabledCipherSuite(suite); - } - - @Override - public MySQLConnectOptions addEnabledSecureTransportProtocol(String protocol) { - return (MySQLConnectOptions) super.addEnabledSecureTransportProtocol(protocol); - } - - @Override - public MySQLConnectOptions removeEnabledSecureTransportProtocol(String protocol) { - return (MySQLConnectOptions) super.removeEnabledSecureTransportProtocol(protocol); - } - - @Override - public MySQLConnectOptions setUseAlpn(boolean useAlpn) { - return (MySQLConnectOptions) super.setUseAlpn(useAlpn); - } - - @Override - public MySQLConnectOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) { - return (MySQLConnectOptions) super.setSslEngineOptions(sslEngineOptions); - } - - @Override - public MySQLConnectOptions setJdkSslEngineOptions(JdkSSLEngineOptions sslEngineOptions) { - return (MySQLConnectOptions) super.setJdkSslEngineOptions(sslEngineOptions); - } - - @Override - public MySQLConnectOptions setTcpFastOpen(boolean tcpFastOpen) { - return (MySQLConnectOptions) super.setTcpFastOpen(tcpFastOpen); - } - - @Override - public MySQLConnectOptions setTcpCork(boolean tcpCork) { - return (MySQLConnectOptions) super.setTcpCork(tcpCork); - } - - @Override - public MySQLConnectOptions setTcpQuickAck(boolean tcpQuickAck) { - return (MySQLConnectOptions) super.setTcpQuickAck(tcpQuickAck); - } - - @Override - public ClientOptionsBase setOpenSslEngineOptions(OpenSSLEngineOptions sslEngineOptions) { - return super.setOpenSslEngineOptions(sslEngineOptions); - } - - @Override - public MySQLConnectOptions addCrlPath(String crlPath) throws NullPointerException { - return (MySQLConnectOptions) super.addCrlPath(crlPath); - } - - @Override - public MySQLConnectOptions addCrlValue(Buffer crlValue) throws NullPointerException { - return (MySQLConnectOptions) super.addCrlValue(crlValue); - } - - @Override - public MySQLConnectOptions setTrustAll(boolean trustAll) { - return (MySQLConnectOptions) super.setTrustAll(trustAll); - } - - @Override - public MySQLConnectOptions setConnectTimeout(int connectTimeout) { - return (MySQLConnectOptions) super.setConnectTimeout(connectTimeout); - } - - @Override - public MySQLConnectOptions setMetricsName(String metricsName) { - return (MySQLConnectOptions) super.setMetricsName(metricsName); - } - @Override public MySQLConnectOptions setReconnectAttempts(int attempts) { return (MySQLConnectOptions) super.setReconnectAttempts(attempts); @@ -561,43 +386,13 @@ public MySQLConnectOptions setReconnectInterval(long interval) { } @Override - public MySQLConnectOptions setHostnameVerificationAlgorithm(String hostnameVerificationAlgorithm) { - return (MySQLConnectOptions) super.setHostnameVerificationAlgorithm(hostnameVerificationAlgorithm); - } - - @Override - public MySQLConnectOptions setLogActivity(boolean logEnabled) { - return (MySQLConnectOptions) super.setLogActivity(logEnabled); - } - - @Override - public MySQLConnectOptions setProxyOptions(ProxyOptions proxyOptions) { - return (MySQLConnectOptions) super.setProxyOptions(proxyOptions); - } - - @Override - public MySQLConnectOptions setLocalAddress(String localAddress) { - return (MySQLConnectOptions) super.setLocalAddress(localAddress); - } - - @Override - public MySQLConnectOptions setEnabledSecureTransportProtocols(Set enabledSecureTransportProtocols) { - return (MySQLConnectOptions) super.setEnabledSecureTransportProtocols(enabledSecureTransportProtocols); - } - - @Override - public MySQLConnectOptions setSslHandshakeTimeout(long sslHandshakeTimeout) { - return (MySQLConnectOptions) super.setSslHandshakeTimeout(sslHandshakeTimeout); - } - - @Override - public MySQLConnectOptions setSslHandshakeTimeoutUnit(TimeUnit sslHandshakeTimeoutUnit) { - return (MySQLConnectOptions) super.setSslHandshakeTimeoutUnit(sslHandshakeTimeoutUnit); + public MySQLConnectOptions setTracingPolicy(TracingPolicy tracingPolicy) { + return (MySQLConnectOptions) super.setTracingPolicy(tracingPolicy); } @Override - public MySQLConnectOptions setTracingPolicy(TracingPolicy tracingPolicy) { - return (MySQLConnectOptions) super.setTracingPolicy(tracingPolicy); + public MySQLConnectOptions setSslOptions(ClientSSLOptions sslOptions) { + return (MySQLConnectOptions) super.setSslOptions(sslOptions); } /** diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLConnectionFactory.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLConnectionFactory.java index f71cf10b4d..1a4b03e003 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLConnectionFactory.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLConnectionFactory.java @@ -17,7 +17,8 @@ import io.vertx.core.buffer.Buffer; import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.VertxInternal; -import io.vertx.core.net.NetClientOptions; +import io.vertx.core.net.ConnectOptions; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.NetSocket; import io.vertx.core.net.SocketAddress; import io.vertx.core.net.TrustOptions; @@ -46,25 +47,29 @@ public MySQLConnectionFactory(VertxInternal vertx) { @Override protected Future doConnectInternal(MySQLConnectOptions options, ContextInternal context) { SslMode sslMode = options.isUsingDomainSocket() ? SslMode.DISABLED : options.getSslMode(); + ClientSSLOptions sslOptions = options.getSslOptions(); switch (sslMode) { case VERIFY_IDENTITY: - String hostnameVerificationAlgorithm = options.getHostnameVerificationAlgorithm(); + String hostnameVerificationAlgorithm = sslOptions.getHostnameVerificationAlgorithm(); if (hostnameVerificationAlgorithm == null || hostnameVerificationAlgorithm.isEmpty()) { return context.failedFuture(new IllegalArgumentException("Host verification algorithm must be specified under VERIFY_IDENTITY ssl-mode.")); } break; case VERIFY_CA: - TrustOptions trustOptions = options.getTrustOptions(); + TrustOptions trustOptions = sslOptions.getTrustOptions(); if (trustOptions == null) { return context.failedFuture(new IllegalArgumentException("Trust options must be specified under " + sslMode.name() + " ssl-mode.")); } break; + case DISABLED: + sslOptions = null; + break; } int capabilitiesFlag = capabilitiesFlags(options); if (sslMode == SslMode.PREFERRED) { - return doConnect(options, sslMode, capabilitiesFlag, context).recover(err -> doConnect(options, SslMode.DISABLED, capabilitiesFlag, context)); + return doConnect(options, sslMode, sslOptions, capabilitiesFlag, context).recover(err -> doConnect(options, SslMode.DISABLED, null, capabilitiesFlag, context)); } else { - return doConnect(options, sslMode, capabilitiesFlag, context); + return doConnect(options, sslMode, sslOptions, capabilitiesFlag, context); } } @@ -82,7 +87,7 @@ private int capabilitiesFlags(MySQLConnectOptions options) { return capabilitiesFlags; } - private Future doConnect(MySQLConnectOptions options, SslMode sslMode, int initialCapabilitiesFlags, ContextInternal context) { + private Future doConnect(MySQLConnectOptions options, SslMode sslMode, ClientSSLOptions sslOptions, int initialCapabilitiesFlags, ContextInternal context) { String username = options.getUser(); String password = options.getPassword(); String database = options.getDatabase(); @@ -122,13 +127,14 @@ private Future doConnect(MySQLConnectOptions options, SslMode sslMod } int pipeliningLimit = options.getPipeliningLimit(); MySQLAuthenticationPlugin authenticationPlugin = options.getAuthenticationPlugin(); - Future fut = netClient(new NetClientOptions(options).setSsl(false)).connect(server); + ConnectOptions connectOptions = new ConnectOptions().setRemoteAddress(server); + Future fut = client.connect(connectOptions); return fut.flatMap(so -> { VertxMetrics vertxMetrics = vertx.metricsSPI(); - ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", options.getMetricsName()) : null; + ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", tcpOptions.getMetricsName()) : null; MySQLSocketConnection conn = new MySQLSocketConnection((NetSocketInternal) so, metrics, options, cachePreparedStatements, preparedStatementCacheMaxSize, preparedStatementCacheSqlFilter, pipeliningLimit, context); conn.init(); - return Future.future(promise -> conn.sendStartupMessage(username, password, database, collation, serverRsaPublicKey, properties, sslMode, initialCapabilitiesFlags, charsetEncoding, authenticationPlugin, promise)); + return Future.future(promise -> conn.sendStartupMessage(username, password, database, collation, serverRsaPublicKey, properties, sslMode, sslOptions, initialCapabilitiesFlags, charsetEncoding, authenticationPlugin, promise)); }); } diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLSocketConnection.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLSocketConnection.java index 5394bbff5b..1541d7dc58 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLSocketConnection.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/MySQLSocketConnection.java @@ -24,6 +24,7 @@ import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; import io.vertx.core.impl.ContextInternal; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.impl.NetSocketInternal; import io.vertx.core.spi.metrics.ClientMetrics; import io.vertx.mysqlclient.MySQLAuthenticationPlugin; @@ -74,11 +75,12 @@ void sendStartupMessage(String username, Buffer serverRsaPublicKey, Map properties, SslMode sslMode, + ClientSSLOptions sslOptions, int initialCapabilitiesFlags, Charset charsetEncoding, MySQLAuthenticationPlugin authenticationPlugin, Promise completionHandler) { - InitialHandshakeCommand cmd = new InitialHandshakeCommand(this, username, password, database, collation, serverRsaPublicKey, properties, sslMode, initialCapabilitiesFlags, charsetEncoding, authenticationPlugin); + InitialHandshakeCommand cmd = new InitialHandshakeCommand(this, username, password, database, collation, serverRsaPublicKey, properties, sslMode, sslOptions, initialCapabilitiesFlags, charsetEncoding, authenticationPlugin); schedule(context, cmd).onComplete(completionHandler); } @@ -112,8 +114,8 @@ protected void doSchedule(CommandBase cmd, Handler> handle } } - public Future upgradeToSsl() { - return socket.upgradeToSsl(); + public Future upgradeToSsl(ClientSSLOptions sslOptions) { + return socket.upgradeToSsl(sslOptions); } @Override diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/InitialHandshakeCommandCodec.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/InitialHandshakeCommandCodec.java index 0973fce365..379de40201 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/InitialHandshakeCommandCodec.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/codec/InitialHandshakeCommandCodec.java @@ -143,7 +143,7 @@ private void handleInitialHandshake(ByteBuf payload) { encoder.clientCapabilitiesFlag |= CLIENT_SSL; sendSslRequest(); - encoder.socketConnection.upgradeToSsl().onComplete(upgrade -> { + encoder.socketConnection.upgradeToSsl(cmd.sslOptions()).onComplete(upgrade -> { if (upgrade.succeeded()) { doSendHandshakeResponseMessage(serverAuthPluginName, cmd.authenticationPlugin(), authPluginData, serverCapabilitiesFlags); } else { diff --git a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/command/InitialHandshakeCommand.java b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/command/InitialHandshakeCommand.java index 252e5b6d43..fe03c0b99a 100644 --- a/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/command/InitialHandshakeCommand.java +++ b/vertx-mysql-client/src/main/java/io/vertx/mysqlclient/impl/command/InitialHandshakeCommand.java @@ -12,6 +12,7 @@ package io.vertx.mysqlclient.impl.command; import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.mysqlclient.MySQLAuthenticationPlugin; import io.vertx.mysqlclient.SslMode; import io.vertx.mysqlclient.impl.MySQLCollation; @@ -24,6 +25,7 @@ public class InitialHandshakeCommand extends AuthenticationCommandBase { private final SocketConnectionBase conn; private final SslMode sslMode; + private final ClientSSLOptions sslOptions; private final int initialCapabilitiesFlags; private final Charset charsetEncoding; private final MySQLAuthenticationPlugin authenticationPlugin; @@ -36,12 +38,14 @@ public InitialHandshakeCommand(SocketConnectionBase conn, Buffer serverRsaPublicKey, Map connectionAttributes, SslMode sslMode, + ClientSSLOptions sslOptions, int initialCapabilitiesFlags, Charset charsetEncoding, MySQLAuthenticationPlugin authenticationPlugin) { super(username, password, database, collation, serverRsaPublicKey, connectionAttributes); this.conn = conn; this.sslMode = sslMode; + this.sslOptions = sslOptions; this.initialCapabilitiesFlags = initialCapabilitiesFlags; this.charsetEncoding = charsetEncoding; this.authenticationPlugin = authenticationPlugin; @@ -55,6 +59,10 @@ public SslMode sslMode() { return sslMode; } + public ClientSSLOptions sslOptions() { + return sslOptions; + } + public int initialCapabilitiesFlags() { return initialCapabilitiesFlags; } diff --git a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/MySQLTLSTest.java b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/MySQLTLSTest.java index 02de2e5c46..680cac4ec8 100644 --- a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/MySQLTLSTest.java +++ b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/MySQLTLSTest.java @@ -13,6 +13,7 @@ import io.vertx.core.Future; import io.vertx.core.Vertx; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.PemKeyCertOptions; import io.vertx.core.net.PemTrustOptions; import io.vertx.ext.unit.TestContext; @@ -42,7 +43,7 @@ public class MySQLTLSTest { @Before public void setup() { vertx = Vertx.vertx(); - options = new MySQLConnectOptions(rule.options()); + options = new MySQLConnectOptions(rule.options()).setSslOptions(new ClientSSLOptions()); nonTlsOptions = new MySQLConnectOptions(nonTlsRule.options()); /* * For testing we have to drop using the TLSv1.2. @@ -53,7 +54,7 @@ public void setup() { * and https://dev.mysql.com/doc/refman/5.7/en/encrypted-connection-protocols-ciphers.html for more details. */ if (rule.isUsingMySQL5_6()) { - options.removeEnabledSecureTransportProtocol("TLSv1.2"); + options.getSslOptions().removeEnabledSecureTransportProtocol("TLSv1.2"); } } @@ -89,10 +90,11 @@ public void testSuccessWithDisabledSslMode(TestContext ctx) { @Test public void testTlsSuccessWithPreferredSslMode(TestContext ctx) { options.setSslMode(SslMode.PREFERRED); - options.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); - options.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); MySQLConnection.connect(vertx, options).onComplete(ctx.asyncAssertSuccess(conn -> { ctx.assertTrue(conn.isSSL()); @@ -109,10 +111,11 @@ public void testTlsSuccessWithPreferredSslMode(TestContext ctx) { @Test public void testTlsHandshakeFailWithPreferredSslMode(TestContext ctx) { options.setSslMode(SslMode.PREFERRED); - options.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/client-cert.pem")); // wrong file - options.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/client-cert.pem")) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); MySQLConnection.connect(vertx, options).onComplete(ctx.asyncAssertSuccess(conn -> { ctx.assertFalse(conn.isSSL()); @@ -129,10 +132,11 @@ public void testTlsHandshakeFailWithPreferredSslMode(TestContext ctx) { @Test public void testNonTlsConnWithPreferredSslMode(TestContext ctx) { nonTlsOptions.setSslMode(SslMode.PREFERRED); - nonTlsOptions.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); - nonTlsOptions.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); MySQLConnection.connect(vertx, nonTlsOptions).onComplete( ctx.asyncAssertSuccess(conn -> { ctx.assertFalse(conn.isSSL()); @@ -149,10 +153,11 @@ public void testNonTlsConnWithPreferredSslMode(TestContext ctx) { @Test public void testSuccessWithRequiredSslMode(TestContext ctx) { options.setSslMode(SslMode.REQUIRED); - options.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); - options.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); MySQLConnection.connect(vertx, options).onComplete( ctx.asyncAssertSuccess(conn -> { ctx.assertTrue(conn.isSSL()); @@ -169,10 +174,11 @@ public void testSuccessWithRequiredSslMode(TestContext ctx) { @Test public void testPoolSuccessWithRequiredSslMode(TestContext ctx) { options.setSslMode(SslMode.REQUIRED); - options.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); - options.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); MySQLPool pool = MySQLPool.pool(vertx, options, new PoolOptions().setMaxSize(5)); @@ -191,7 +197,8 @@ public void testPoolSuccessWithRequiredSslMode(TestContext ctx) { @Test public void testSuccessWithOnlyCertificate(TestContext ctx) { options.setSslMode(SslMode.REQUIRED); - options.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); MySQLConnection.connect(vertx, options).onComplete(ctx.asyncAssertSuccess(conn -> { ctx.assertTrue(conn.isSSL()); @@ -208,7 +215,7 @@ public void testSuccessWithOnlyCertificate(TestContext ctx) { @Test public void testSuccessWithoutCertificate(TestContext ctx) { options.setSslMode(SslMode.REQUIRED); - options.setTrustAll(true); + options.getSslOptions().setTrustAll(true); MySQLConnection.connect(vertx, options).onComplete( ctx.asyncAssertSuccess(conn -> { ctx.assertTrue(conn.isSSL()); @@ -225,10 +232,11 @@ public void testSuccessWithoutCertificate(TestContext ctx) { @Test public void testSuccessWithVerifyCaSslMode(TestContext ctx) { options.setSslMode(SslMode.VERIFY_CA); - options.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); - options.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); MySQLConnection.connect(vertx, options).onComplete( ctx.asyncAssertSuccess(conn -> { ctx.assertTrue(conn.isSSL()); @@ -245,10 +253,11 @@ public void testSuccessWithVerifyCaSslMode(TestContext ctx) { @Test public void testConnFailWithVerifyCaSslMode(TestContext ctx) { options.setSslMode(SslMode.VERIFY_CA); - options.setTrustAll(true); - options.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustAll(true) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); MySQLConnection.connect(vertx, options).onComplete( ctx.asyncAssertFailure(error -> { ctx.assertEquals("Trust options must be specified under VERIFY_CA ssl-mode.", error.getMessage()); @@ -258,10 +267,11 @@ public void testConnFailWithVerifyCaSslMode(TestContext ctx) { @Test public void testPoolFailWithVerifyCaSslMode(TestContext ctx) { options.setSslMode(SslMode.VERIFY_CA); - options.setTrustAll(true); - options.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustAll(true) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); try { MySQLPool.pool(vertx, options, new PoolOptions()); @@ -273,10 +283,11 @@ public void testPoolFailWithVerifyCaSslMode(TestContext ctx) { @Test public void testConnFailWithVerifyIdentitySslMode(TestContext ctx) { options.setSslMode(SslMode.VERIFY_IDENTITY); - options.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); - options.setPemKeyCertOptions(new PemKeyCertOptions() - .setCertPath("tls/files/client-cert.pem") - .setKeyPath("tls/files/client-key.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")) + .setKeyCertOptions(new PemKeyCertOptions() + .setCertPath("tls/files/client-cert.pem") + .setKeyPath("tls/files/client-key.pem")); MySQLConnection.connect(vertx, options).onComplete( ctx.asyncAssertFailure(error -> { ctx.assertEquals("Host verification algorithm must be specified under VERIFY_IDENTITY ssl-mode.", error.getMessage()); @@ -294,7 +305,8 @@ public void testConnFail(TestContext ctx) { @Test public void testChangeUser(TestContext ctx) { options.setSslMode(SslMode.REQUIRED); - options.setPemTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); + options.getSslOptions() + .setTrustOptions(new PemTrustOptions().addCertPath("tls/files/ca.pem")); MySQLConnection.connect(vertx, options).onComplete( ctx.asyncAssertSuccess(conn -> { conn diff --git a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/MySQLUnixDomainSocketTest.java b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/MySQLUnixDomainSocketTest.java index ec010f502e..340a009708 100644 --- a/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/MySQLUnixDomainSocketTest.java +++ b/vertx-mysql-client/src/test/java/io/vertx/mysqlclient/MySQLUnixDomainSocketTest.java @@ -35,6 +35,7 @@ public class MySQLUnixDomainSocketTest extends MySQLTestBase { private MySQLPool client; private MySQLConnectOptions options; + private Vertx vertx; @Before public void setUp() { @@ -47,12 +48,16 @@ public void setUp() { options.setHost(rule.domainSocketPath()); } assumeTrue(options.isUsingDomainSocket()); + vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true)); } @After - public void after() { + public void after(TestContext ctx) { + if (vertx != null) { + vertx.close().onComplete(ctx.asyncAssertSuccess()); + } if (client != null) { - client.close(); + client.close().onComplete(ctx.asyncAssertSuccess()); } } @@ -69,7 +74,7 @@ public void uriSocketAttributeTest(TestContext context) throws UnsupportedEncodi } private void uriTest(TestContext context, String uri) throws UnsupportedEncodingException { - client = MySQLPool.pool(uri); + client = MySQLPool.pool(vertx, uri); client .getConnection() .onComplete(context.asyncAssertSuccess(SqlClient::close)); @@ -77,7 +82,7 @@ private void uriTest(TestContext context, String uri) throws UnsupportedEncoding @Test public void simpleConnect(TestContext context) { - client = MySQLPool.pool(new MySQLConnectOptions(options), new PoolOptions()); + client = MySQLPool.pool(vertx, new MySQLConnectOptions(options), new PoolOptions()); client .getConnection() .onComplete(context.asyncAssertSuccess(SqlClient::close)); @@ -103,7 +108,7 @@ public void connectWithVertxInstance(TestContext context) { @Test public void testIgnoreSslMode(TestContext context) { - client = MySQLPool.pool(new MySQLConnectOptions(options).setSslMode(SslMode.REQUIRED), new PoolOptions()); + client = MySQLPool.pool(vertx, new MySQLConnectOptions(options).setSslMode(SslMode.REQUIRED), new PoolOptions()); client .getConnection() .onComplete(context.asyncAssertSuccess(conn -> { diff --git a/vertx-oracle-client/src/main/java/io/vertx/oracleclient/OracleConnectOptions.java b/vertx-oracle-client/src/main/java/io/vertx/oracleclient/OracleConnectOptions.java index d843bb3c4e..cd659f8eb0 100644 --- a/vertx-oracle-client/src/main/java/io/vertx/oracleclient/OracleConnectOptions.java +++ b/vertx-oracle-client/src/main/java/io/vertx/oracleclient/OracleConnectOptions.java @@ -40,6 +40,7 @@ public static OracleConnectOptions wrap(SqlConnectOptions options) { public static final String DEFAULT_USER = ""; public static final String DEFAULT_PASSWORD = ""; public static final String DEFAULT_DATABASE = ""; + public static final boolean DEFAULT_SSL = false; private String serviceId; private String serviceName; @@ -47,6 +48,7 @@ public static OracleConnectOptions wrap(SqlConnectOptions options) { private String instanceName; private String tnsAlias; private String tnsAdmin; + private boolean ssl; public OracleConnectOptions() { super(); @@ -64,6 +66,7 @@ private void copyFields(OracleConnectOptions other) { this.instanceName = other.instanceName; this.tnsAlias = other.tnsAlias; this.tnsAdmin = other.tnsAdmin; + this.ssl = other.ssl; } public OracleConnectOptions(SqlConnectOptions options) { @@ -329,9 +332,23 @@ public OracleConnectOptions setTracingPolicy(TracingPolicy tracingPolicy) { return (OracleConnectOptions) super.setTracingPolicy(tracingPolicy); } - @Override + /** + * + * @return is SSL/TLS enabled? + */ + public boolean isSsl() { + return ssl; + } + + /** + * Set whether SSL/TLS is enabled + * + * @param ssl true if enabled + * @return a reference to this, so the API can be used fluently + */ public OracleConnectOptions setSsl(boolean ssl) { - return (OracleConnectOptions) super.setSsl(ssl); + this.ssl = ssl; + return this; } @Override diff --git a/vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleConnectionFactory.java b/vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleConnectionFactory.java index fe2611d0d5..86829bf6e3 100644 --- a/vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleConnectionFactory.java +++ b/vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleConnectionFactory.java @@ -61,7 +61,7 @@ private OracleDataSource getDatasource(SqlConnectOptions options) { public Future connect(Context context, OracleConnectOptions options) { OracleDataSource datasource = getDatasource(options); VertxMetrics vertxMetrics = ((VertxInternal)context.owner()).metricsSPI(); - ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", options.getMetricsName()) : null; + ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", null) : null; ContextInternal ctx = (ContextInternal) context; return executeBlocking(context, () -> { OracleConnection orac = datasource.createConnectionBuilder().build(); diff --git a/vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleDatabaseHelper.java b/vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleDatabaseHelper.java index b41eeca30d..516f0d7d2a 100644 --- a/vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleDatabaseHelper.java +++ b/vertx-oracle-client/src/main/java/io/vertx/oracleclient/impl/OracleDatabaseHelper.java @@ -106,10 +106,10 @@ private static void configureStandardOptions(OracleDataSource oracleDataSource, runOrHandleSQLException(() -> oracleDataSource.setPassword(password.toString())); } - int connectTimeout = options.getConnectTimeout(); - if (connectTimeout > 0) { - runOrHandleSQLException(() -> oracleDataSource.setLoginTimeout(connectTimeout)); - } +// int connectTimeout = options.getConnectTimeout(); +// if (connectTimeout > 0) { +// runOrHandleSQLException(() -> oracleDataSource.setLoginTimeout(connectTimeout)); +// } } private static void configureExtendedOptions(OracleDataSource oracleDataSource, OracleConnectOptions options) { diff --git a/vertx-pg-client/src/main/java/examples/PgClientExamples.java b/vertx-pg-client/src/main/java/examples/PgClientExamples.java index a16fe2cc18..9745dc5502 100644 --- a/vertx-pg-client/src/main/java/examples/PgClientExamples.java +++ b/vertx-pg-client/src/main/java/examples/PgClientExamples.java @@ -20,6 +20,7 @@ import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.json.JsonObject; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.PemTrustOptions; import io.vertx.docgen.Source; import io.vertx.pgclient.PgConnectOptions; @@ -465,7 +466,7 @@ public void ex10(Vertx vertx) { .setUser("user") .setPassword("secret") .setSslMode(SslMode.VERIFY_CA) - .setPemTrustOptions(new PemTrustOptions().addCertPath("/path/to/cert.pem")); + .setSslOptions(new ClientSSLOptions().setTrustOptions(new PemTrustOptions().addCertPath("/path/to/cert.pem"))); PgConnection .connect(vertx, options) diff --git a/vertx-pg-client/src/main/java/io/vertx/pgclient/PgConnectOptions.java b/vertx-pg-client/src/main/java/io/vertx/pgclient/PgConnectOptions.java index 3d7f0c6490..3b4fc1ab68 100644 --- a/vertx-pg-client/src/main/java/io/vertx/pgclient/PgConnectOptions.java +++ b/vertx-pg-client/src/main/java/io/vertx/pgclient/PgConnectOptions.java @@ -22,7 +22,6 @@ import io.vertx.core.tracing.TracingPolicy; import io.vertx.pgclient.impl.PgConnectionUriParser; import io.vertx.codegen.annotations.DataObject; -import io.vertx.core.buffer.Buffer; import io.vertx.core.json.JsonObject; import io.vertx.core.net.*; import io.vertx.sqlclient.SqlConnectOptions; @@ -30,8 +29,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import static java.lang.Integer.parseInt; @@ -259,224 +256,24 @@ public PgConnectOptions setUseLayer7Proxy(boolean useLayer7Proxy) { return this; } - @Override - public PgConnectOptions setSendBufferSize(int sendBufferSize) { - return (PgConnectOptions)super.setSendBufferSize(sendBufferSize); - } - - @Override - public PgConnectOptions setReceiveBufferSize(int receiveBufferSize) { - return (PgConnectOptions)super.setReceiveBufferSize(receiveBufferSize); - } - - @Override - public PgConnectOptions setReuseAddress(boolean reuseAddress) { - return (PgConnectOptions)super.setReuseAddress(reuseAddress); - } - - @Override - public PgConnectOptions setTrafficClass(int trafficClass) { - return (PgConnectOptions)super.setTrafficClass(trafficClass); - } - - @Override - public PgConnectOptions setTcpNoDelay(boolean tcpNoDelay) { - return (PgConnectOptions)super.setTcpNoDelay(tcpNoDelay); - } - - @Override - public PgConnectOptions setTcpKeepAlive(boolean tcpKeepAlive) { - return (PgConnectOptions)super.setTcpKeepAlive(tcpKeepAlive); - } - - @Override - public PgConnectOptions setSoLinger(int soLinger) { - return (PgConnectOptions)super.setSoLinger(soLinger); - } - - @Override - public PgConnectOptions setIdleTimeout(int idleTimeout) { - return (PgConnectOptions)super.setIdleTimeout(idleTimeout); - } - - @Override - public PgConnectOptions setIdleTimeoutUnit(TimeUnit idleTimeoutUnit) { - return (PgConnectOptions) super.setIdleTimeoutUnit(idleTimeoutUnit); - } - - @Override - public PgConnectOptions setSsl(boolean ssl) { - if (ssl) { - setSslMode(SslMode.VERIFY_CA); - } else { - setSslMode(SslMode.DISABLE); - } - return this; - } - - @Override - public PgConnectOptions setKeyCertOptions(KeyCertOptions options) { - return (PgConnectOptions)super.setKeyCertOptions(options); - } - - @Override - public PgConnectOptions setKeyStoreOptions(JksOptions options) { - return (PgConnectOptions)super.setKeyStoreOptions(options); - } - - @Override - public PgConnectOptions setPfxKeyCertOptions(PfxOptions options) { - return (PgConnectOptions)super.setPfxKeyCertOptions(options); - } - - @Override - public PgConnectOptions setPemKeyCertOptions(PemKeyCertOptions options) { - return (PgConnectOptions)super.setPemKeyCertOptions(options); - } - - @Override - public PgConnectOptions setTrustOptions(TrustOptions options) { - return (PgConnectOptions)super.setTrustOptions(options); - } - - @Override - public PgConnectOptions setTrustStoreOptions(JksOptions options) { - return (PgConnectOptions)super.setTrustStoreOptions(options); - } - - @Override - public PgConnectOptions setPemTrustOptions(PemTrustOptions options) { - return (PgConnectOptions)super.setPemTrustOptions(options); - } - - @Override - public PgConnectOptions setPfxTrustOptions(PfxOptions options) { - return (PgConnectOptions)super.setPfxTrustOptions(options); - } - - @Override - public PgConnectOptions addEnabledCipherSuite(String suite) { - return (PgConnectOptions)super.addEnabledCipherSuite(suite); - } - - @Override - public PgConnectOptions addEnabledSecureTransportProtocol(String protocol) { - return (PgConnectOptions)super.addEnabledSecureTransportProtocol(protocol); - } - - @Override - public PgConnectOptions addCrlPath(String crlPath) throws NullPointerException { - return (PgConnectOptions)super.addCrlPath(crlPath); - } - - @Override - public PgConnectOptions addCrlValue(Buffer crlValue) throws NullPointerException { - return (PgConnectOptions)super.addCrlValue(crlValue); - } - - @Override - public PgConnectOptions setTrustAll(boolean trustAll) { - return (PgConnectOptions)super.setTrustAll(trustAll); - } - - @Override - public PgConnectOptions setConnectTimeout(int connectTimeout) { - return (PgConnectOptions)super.setConnectTimeout(connectTimeout); - } - - @Override - public PgConnectOptions setMetricsName(String metricsName) { - return (PgConnectOptions)super.setMetricsName(metricsName); - } - @Override public PgConnectOptions setReconnectAttempts(int attempts) { return (PgConnectOptions)super.setReconnectAttempts(attempts); } - @Override - public PgConnectOptions setHostnameVerificationAlgorithm(String hostnameVerificationAlgorithm) { - return (PgConnectOptions)super.setHostnameVerificationAlgorithm(hostnameVerificationAlgorithm); - } - - @Override - public PgConnectOptions setLogActivity(boolean logEnabled) { - return (PgConnectOptions)super.setLogActivity(logEnabled); - } - @Override public PgConnectOptions setReconnectInterval(long interval) { return (PgConnectOptions)super.setReconnectInterval(interval); } @Override - public PgConnectOptions setProxyOptions(ProxyOptions proxyOptions) { - return (PgConnectOptions)super.setProxyOptions(proxyOptions); - } - - @Override - public PgConnectOptions setLocalAddress(String localAddress) { - return (PgConnectOptions)super.setLocalAddress(localAddress); - } - - @Override - public PgConnectOptions setUseAlpn(boolean useAlpn) { - return (PgConnectOptions)super.setUseAlpn(useAlpn); - } - - @Override - public PgConnectOptions setSslEngineOptions(SSLEngineOptions sslEngineOptions) { - return (PgConnectOptions)super.setSslEngineOptions(sslEngineOptions); - } - - @Override - public PgConnectOptions setJdkSslEngineOptions(JdkSSLEngineOptions sslEngineOptions) { - return (PgConnectOptions)super.setJdkSslEngineOptions(sslEngineOptions); - } - - @Override - public PgConnectOptions setOpenSslEngineOptions(OpenSSLEngineOptions sslEngineOptions) { - return (PgConnectOptions)super.setOpenSslEngineOptions(sslEngineOptions); - } - - @Override - public PgConnectOptions setReusePort(boolean reusePort) { - return (PgConnectOptions) super.setReusePort(reusePort); - } - - @Override - public PgConnectOptions setTcpFastOpen(boolean tcpFastOpen) { - return (PgConnectOptions) super.setTcpFastOpen(tcpFastOpen); - } - - @Override - public PgConnectOptions setTcpCork(boolean tcpCork) { - return (PgConnectOptions) super.setTcpCork(tcpCork); - } - - @Override - public PgConnectOptions setTcpQuickAck(boolean tcpQuickAck) { - return (PgConnectOptions) super.setTcpQuickAck(tcpQuickAck); - } - - @Override - public PgConnectOptions setEnabledSecureTransportProtocols(Set enabledSecureTransportProtocols) { - return (PgConnectOptions) super.setEnabledSecureTransportProtocols(enabledSecureTransportProtocols); - } - - @Override - public PgConnectOptions setSslHandshakeTimeout(long sslHandshakeTimeout) { - return (PgConnectOptions) super.setSslHandshakeTimeout(sslHandshakeTimeout); - } - - @Override - public PgConnectOptions setSslHandshakeTimeoutUnit(TimeUnit sslHandshakeTimeoutUnit) { - return (PgConnectOptions) super.setSslHandshakeTimeoutUnit(sslHandshakeTimeoutUnit); + public PgConnectOptions setTracingPolicy(TracingPolicy tracingPolicy) { + return (PgConnectOptions) super.setTracingPolicy(tracingPolicy); } @Override - public PgConnectOptions setTracingPolicy(TracingPolicy tracingPolicy) { - return (PgConnectOptions) super.setTracingPolicy(tracingPolicy); + public PgConnectOptions setSslOptions(ClientSSLOptions sslOptions) { + return (PgConnectOptions) super.setSslOptions(sslOptions); } /** diff --git a/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/InitiateSslHandler.java b/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/InitiateSslHandler.java index b4819dc0a8..1f67953398 100644 --- a/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/InitiateSslHandler.java +++ b/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/InitiateSslHandler.java @@ -22,9 +22,8 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.codec.DecoderException; -import io.vertx.core.AsyncResult; -import io.vertx.core.Handler; import io.vertx.core.Promise; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.pgclient.impl.codec.PgProtocolConstants; import io.vertx.sqlclient.impl.SocketConnectionBase; import io.vertx.core.VertxException; @@ -33,10 +32,12 @@ public class InitiateSslHandler extends ChannelInboundHandlerAdapter { private static final int code = 80877103; private final SocketConnectionBase conn; + private final ClientSSLOptions sslOptions; private final Promise upgradePromise; - public InitiateSslHandler(SocketConnectionBase conn, Promise upgradePromise) { + public InitiateSslHandler(SocketConnectionBase conn, ClientSSLOptions sslOptions, Promise upgradePromise) { this.conn = conn; + this.sslOptions = sslOptions; this.upgradePromise = upgradePromise; } @@ -61,7 +62,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception case PgProtocolConstants.MESSAGE_TYPE_SSL_YES: { conn .socket() - .upgradeToSsl() + .upgradeToSsl(sslOptions) .onComplete(ar -> { if (ar.succeeded()) { ctx.pipeline().remove(this); diff --git a/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgConnectionFactory.java b/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgConnectionFactory.java index 53ff12295b..82d0b2e253 100644 --- a/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgConnectionFactory.java +++ b/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgConnectionFactory.java @@ -24,6 +24,7 @@ import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.VertxInternal; import io.vertx.core.impl.future.PromiseInternal; +import io.vertx.core.net.ConnectOptions; import io.vertx.core.net.NetSocket; import io.vertx.core.net.SocketAddress; import io.vertx.core.net.TrustOptions; @@ -52,12 +53,12 @@ public PgConnectionFactory(VertxInternal context) { private void checkSslMode(PgConnectOptions options) { switch (options.getSslMode()) { case VERIFY_FULL: - String hostnameVerificationAlgorithm = options.getHostnameVerificationAlgorithm(); + String hostnameVerificationAlgorithm = options.getSslOptions().getHostnameVerificationAlgorithm(); if (hostnameVerificationAlgorithm == null || hostnameVerificationAlgorithm.isEmpty()) { throw new IllegalArgumentException("Host verification algorithm must be specified under verify-full sslmode"); } case VERIFY_CA: - TrustOptions trustOptions = options.getTrustOptions(); + TrustOptions trustOptions = options.getSslOptions().getTrustOptions(); if (trustOptions == null) { throw new IllegalArgumentException("Trust options must be specified under verify-full or verify-ca sslmode"); } @@ -77,7 +78,7 @@ protected Future doConnectInternal(PgConnectOptions options, Context String database = options.getDatabase(); SocketAddress server = options.getSocketAddress(); Map properties = options.getProperties() != null ? Collections.unmodifiableMap(options.getProperties()) : null; - return doConnect(server, context, (PgConnectOptions) options).flatMap(conn -> { + return doConnect(server, context, options).flatMap(conn -> { PgSocketConnection socket = (PgSocketConnection) conn; socket.init(); return Future.future(p -> socket.sendStartupMessage(username, password, database, properties, p)) @@ -98,21 +99,23 @@ public void cancelRequest(PgConnectOptions options, int processId, int secretKey private Future doConnect(SocketAddress server, ContextInternal context, PgConnectOptions options) { SslMode sslMode = options.isUsingDomainSocket() ? SslMode.DISABLE : options.getSslMode(); + ConnectOptions connectOptions = new ConnectOptions() + .setRemoteAddress(server); Future connFuture; switch (sslMode) { case DISABLE: - connFuture = doConnect(server, context, false, options); + connFuture = doConnect(connectOptions, context, false, options); break; case ALLOW: - connFuture = doConnect(server, context,false, options).recover(err -> doConnect(server, context,true, options)); + connFuture = doConnect(connectOptions, context, false, options).recover(err -> doConnect(connectOptions, context, true, options)); break; case PREFER: - connFuture = doConnect(server, context,true, options).recover(err -> doConnect(server, context,false, options)); + connFuture = doConnect(connectOptions, context, true, options).recover(err -> doConnect(connectOptions, context, false, options)); break; case REQUIRE: case VERIFY_CA: case VERIFY_FULL: - connFuture = doConnect(server, context, true, options); + connFuture = doConnect(connectOptions, context, true, options); break; default: return context.failedFuture(new IllegalArgumentException("Unsupported SSL mode")); @@ -120,20 +123,20 @@ private Future doConnect(SocketAddress server, ContextInternal conte return connFuture; } - private Future doConnect(SocketAddress server, ContextInternal context, boolean ssl, PgConnectOptions options) { + private Future doConnect(ConnectOptions connectOptions, ContextInternal context, boolean ssl, PgConnectOptions options) { Future soFut; try { - soFut = netClient(options).connect(server, (String) null); + soFut = client.connect(connectOptions); } catch (Exception e) { // Client is closed return context.failedFuture(e); } Future connFut = soFut.map(so -> newSocketConnection(context, (NetSocketInternal) so, options)); - if (ssl && !server.isDomainSocket()) { + if (ssl && !connectOptions.getRemoteAddress().isDomainSocket()) { // upgrade connection to SSL if needed connFut = connFut.flatMap(conn -> Future.future(p -> { PgSocketConnection socket = (PgSocketConnection) conn; - socket.upgradeToSSLConnection(ar2 -> { + socket.upgradeToSSLConnection(options.getSslOptions(), ar2 -> { if (ar2.succeeded()) { p.complete(conn); } else { @@ -169,7 +172,7 @@ private PgSocketConnection newSocketConnection(ContextInternal context, NetSocke int pipeliningLimit = options.getPipeliningLimit(); boolean useLayer7Proxy = options.getUseLayer7Proxy(); VertxMetrics vertxMetrics = vertx.metricsSPI(); - ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", options.getMetricsName()) : null; + ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(options.getSocketAddress(), "sql", tcpOptions.getMetricsName()) : null; PgSocketConnection conn = new PgSocketConnection(socket, metrics, options, cachePreparedStatements, preparedStatementCacheMaxSize, preparedStatementCacheSqlFilter, pipeliningLimit, useLayer7Proxy, context); return conn; } diff --git a/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgSocketConnection.java b/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgSocketConnection.java index ac5bff03a6..378c96789c 100644 --- a/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgSocketConnection.java +++ b/vertx-pg-client/src/main/java/io/vertx/pgclient/impl/PgSocketConnection.java @@ -25,6 +25,7 @@ import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; import io.vertx.core.impl.ContextInternal; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.impl.NetSocketInternal; import io.vertx.core.spi.metrics.ClientMetrics; import io.vertx.pgclient.PgConnectOptions; @@ -145,7 +146,7 @@ public DatabaseMetadata getDatabaseMetaData() { return dbMetaData; } - void upgradeToSSLConnection(Handler> completionHandler) { + void upgradeToSSLConnection(ClientSSLOptions sslOptions, Handler> completionHandler) { ChannelPipeline pipeline = socket.channelHandlerContext().pipeline(); Promise upgradePromise = Promise.promise(); upgradePromise.future().onComplete(ar->{ @@ -160,7 +161,7 @@ void upgradeToSSLConnection(Handler> completionHandler) { completionHandler.handle(Future.failedFuture(cause)); } }); - pipeline.addBefore("handler", "initiate-ssl-handler", new InitiateSslHandler(this, upgradePromise)); + pipeline.addBefore("handler", "initiate-ssl-handler", new InitiateSslHandler(this, sslOptions, upgradePromise)); } @Override diff --git a/vertx-pg-client/src/test/java/io/vertx/pgclient/PgClientTestBase.java b/vertx-pg-client/src/test/java/io/vertx/pgclient/PgClientTestBase.java index 90160aa82f..a983df71dd 100644 --- a/vertx-pg-client/src/test/java/io/vertx/pgclient/PgClientTestBase.java +++ b/vertx-pg-client/src/test/java/io/vertx/pgclient/PgClientTestBase.java @@ -20,6 +20,7 @@ import io.vertx.core.AsyncResult; import io.vertx.core.Handler; import io.vertx.core.Vertx; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.NetSocket; import io.vertx.ext.unit.Async; import io.vertx.ext.unit.TestContext; @@ -64,7 +65,7 @@ public void tearDown(TestContext ctx) { @Test public void testConnectNonSSLServer(TestContext ctx) { Async async = ctx.async(); - options.setSslMode(SslMode.REQUIRE).setTrustAll(true); + options.setSslMode(SslMode.REQUIRE).setSslOptions(new ClientSSLOptions().setTrustAll(true)); connector.accept(ctx.asyncAssertFailure(err -> { ctx.assertEquals("Postgres Server does not handle SSL connection", err.getMessage()); async.complete(); diff --git a/vertx-pg-client/src/test/java/io/vertx/pgclient/TLSTest.java b/vertx-pg-client/src/test/java/io/vertx/pgclient/TLSTest.java index 9f7d34cfe6..bc455c428f 100644 --- a/vertx-pg-client/src/test/java/io/vertx/pgclient/TLSTest.java +++ b/vertx-pg-client/src/test/java/io/vertx/pgclient/TLSTest.java @@ -18,6 +18,7 @@ package io.vertx.pgclient; import io.vertx.core.Vertx; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.PemTrustOptions; import io.vertx.ext.unit.Async; import io.vertx.ext.unit.TestContext; @@ -54,7 +55,7 @@ public void testTLS(TestContext ctx) { PgConnectOptions options = new PgConnectOptions(rule.options()) .setSslMode(SslMode.REQUIRE) - .setPemTrustOptions(new PemTrustOptions().addCertPath("tls/server.crt")); + .setSslOptions(new ClientSSLOptions().setTrustOptions(new PemTrustOptions().addCertPath("tls/server.crt"))); PgConnection.connect(vertx, options.setSslMode(SslMode.REQUIRE)).onComplete(ctx.asyncAssertSuccess(conn -> { ctx.assertTrue(conn.isSSL()); conn @@ -73,7 +74,7 @@ public void testTLS(TestContext ctx) { @Test public void testTLSTrustAll(TestContext ctx) { Async async = ctx.async(); - PgConnection.connect(vertx, rule.options().setSslMode(SslMode.REQUIRE).setTrustAll(true)).onComplete(ctx.asyncAssertSuccess(conn -> { + PgConnection.connect(vertx, rule.options().setSslMode(SslMode.REQUIRE).setSslOptions(new ClientSSLOptions().setTrustAll(true))).onComplete(ctx.asyncAssertSuccess(conn -> { ctx.assertTrue(conn.isSSL()); async.complete(); })); @@ -82,7 +83,7 @@ public void testTLSTrustAll(TestContext ctx) { @Test public void testTLSInvalidCertificate(TestContext ctx) { Async async = ctx.async(); - PgConnection.connect(vertx, rule.options().setSslMode(SslMode.REQUIRE)).onComplete(ctx.asyncAssertFailure(err -> { + PgConnection.connect(vertx, rule.options().setSslMode(SslMode.REQUIRE).setSslOptions(new ClientSSLOptions().setTrustOptions(new PemTrustOptions().addCertPath("tls/another.crt")))).onComplete(ctx.asyncAssertFailure(err -> { // ctx.assertEquals(err.getClass(), VertxException.class); ctx.assertEquals(err.getMessage(), "SSL handshake failed"); async.complete(); @@ -116,7 +117,7 @@ public void testSslModePrefer(TestContext ctx) { Async async = ctx.async(); PgConnectOptions options = rule.options() .setSslMode(SslMode.PREFER) - .setTrustAll(true); + .setSslOptions(new ClientSSLOptions().setTrustAll(true)); PgConnection.connect(vertx, new PgConnectOptions(options)).onComplete(ctx.asyncAssertSuccess(conn -> { ctx.assertTrue(conn.isSSL()); async.complete(); @@ -127,7 +128,7 @@ public void testSslModePrefer(TestContext ctx) { public void testSslModeVerifyCaConf(TestContext ctx) { PgConnectOptions options = rule.options() .setSslMode(SslMode.VERIFY_CA) - .setTrustAll(true); + .setSslOptions(new ClientSSLOptions().setTrustAll(true)); PgConnection.connect(vertx, new PgConnectOptions(options)).onComplete(ctx.asyncAssertFailure(error -> { ctx.assertEquals("Trust options must be specified under verify-full or verify-ca sslmode", error.getMessage()); })); @@ -136,6 +137,7 @@ public void testSslModeVerifyCaConf(TestContext ctx) { @Test public void testSslModeVerifyFullConf(TestContext ctx) { PgConnectOptions options = rule.options() + .setSslOptions(new ClientSSLOptions().setTrustOptions(new PemTrustOptions().addCertPath("tls/another.crt"))) .setSslMode(SslMode.VERIFY_FULL); PgConnection.connect(vertx, new PgConnectOptions(options)).onComplete(ctx.asyncAssertFailure(error -> { ctx.assertEquals("Host verification algorithm must be specified under verify-full sslmode", error.getMessage()); diff --git a/vertx-pg-client/src/test/java/io/vertx/pgclient/UnixDomainSocketTest.java b/vertx-pg-client/src/test/java/io/vertx/pgclient/UnixDomainSocketTest.java index 05aaf06972..1e7b978b89 100644 --- a/vertx-pg-client/src/test/java/io/vertx/pgclient/UnixDomainSocketTest.java +++ b/vertx-pg-client/src/test/java/io/vertx/pgclient/UnixDomainSocketTest.java @@ -19,7 +19,6 @@ import io.vertx.pgclient.junit.PgRule; import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; -import io.vertx.ext.unit.Async; import io.vertx.ext.unit.TestContext; import io.vertx.ext.unit.junit.VertxUnitRunner; import io.vertx.sqlclient.PoolOptions; @@ -30,7 +29,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; @RunWith(VertxUnitRunner.class) @@ -50,9 +48,11 @@ public class UnixDomainSocketTest { public static PgRule rule = new PgRule().domainSockets(nativeTransportEnabled); private PgPool client; private PgConnectOptions options; + private Vertx vertx; @Before public void before() { + vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true)); options = rule.options(); if (unixSocketDirectory != null && !unixSocketDirectory.isEmpty()) { options.setHost(unixSocketDirectory); @@ -64,6 +64,9 @@ public void before() { @After public void after(TestContext ctx) { + if (vertx != null) { + vertx.close().onComplete(ctx.asyncAssertSuccess()); + } if (client != null) { client.close().onComplete(ctx.asyncAssertSuccess()); } @@ -73,7 +76,7 @@ public void after(TestContext ctx) { public void uriTest(TestContext context) { assumeTrue(options.isUsingDomainSocket()); String uri = "postgresql://postgres:postgres@/postgres?host=" + options.getHost() + "&port=" + options.getPort(); - client = PgPool.pool(uri); + client = PgPool.pool(vertx, uri); client .getConnection() .onComplete(context.asyncAssertSuccess(SqlClient::close)); @@ -82,7 +85,7 @@ public void uriTest(TestContext context) { @Test public void simpleConnect(TestContext context) { assumeTrue(options.isUsingDomainSocket()); - client = PgPool.pool(new PgConnectOptions(options), new PoolOptions()); + client = PgPool.pool(vertx, new PgConnectOptions(options), new PoolOptions()); client .getConnection() .onComplete(context.asyncAssertSuccess(pgConnection -> pgConnection.close().onComplete(context.asyncAssertSuccess()))); @@ -91,26 +94,19 @@ public void simpleConnect(TestContext context) { @Test public void connectWithVertxInstance(TestContext context) { assumeTrue(options.isUsingDomainSocket()); - Vertx vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true)); - try { - client = PgPool.pool(vertx, new PgConnectOptions(options), new PoolOptions()); - Async async = context.async(); - client - .getConnection() - .onComplete(context.asyncAssertSuccess(pgConnection -> { - async.complete(); + client = PgPool.pool(vertx, new PgConnectOptions(options), new PoolOptions()); + client + .getConnection() + .onComplete(context.asyncAssertSuccess(pgConnection -> { pgConnection.close(); })); - async.await(); - } finally { - vertx.close(); - } } + @Ignore @Test public void testIgnoreSslMode(TestContext context) { assumeTrue(options.isUsingDomainSocket()); - client = PgPool.pool(new PgConnectOptions(options).setSslMode(SslMode.REQUIRE), new PoolOptions()); + client = PgPool.pool(vertx, new PgConnectOptions(options).setSslMode(SslMode.REQUIRE), new PoolOptions()); client .getConnection() .onComplete(context.asyncAssertSuccess(pgConnection -> { @@ -121,17 +117,9 @@ public void testIgnoreSslMode(TestContext context) { @Test public void testNativeTransportMustBeEnabled(TestContext ctx) { - Vertx vertx = Vertx.vertx(); - try { - PgPool pool = PgPool.pool(vertx, PgConnectOptions.fromUri("postgresql:///dbname?host=/var/lib/postgresql"), new PoolOptions()); - Async async = ctx.async(); - pool.getConnection().onComplete(ctx.asyncAssertFailure(err -> { - assertEquals(ConnectionFactoryBase.NATIVE_TRANSPORT_REQUIRED, err.getMessage()); - async.complete(); - })); - async.await(20_000); - } finally { - vertx.close(); - } + PgPool pool = PgPool.pool(PgConnectOptions.fromUri("postgresql:///dbname?host=/var/lib/postgresql"), new PoolOptions()); + pool.getConnection().onComplete(ctx.asyncAssertFailure(err -> { + assertEquals(ConnectionFactoryBase.NATIVE_TRANSPORT_REQUIRED, err.getMessage()); + })); } } diff --git a/vertx-pg-client/src/test/resources/tls/another.crt b/vertx-pg-client/src/test/resources/tls/another.crt new file mode 100644 index 0000000000..241347df80 --- /dev/null +++ b/vertx-pg-client/src/test/resources/tls/another.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICwTCCAamgAwIBAgIEBeVm4jANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDEwZj +bGllbnQwHhcNMTgwNTI2MTEzNjUxWhcNMjEwNTI1MTEzNjUxWjARMQ8wDQYDVQQD +EwZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVmCecLdUZ +U917hweVz4JqvZ9vZEi1rH+BG98HYfRR/h3QaobxPImZu3hzKHZ+MPbm94HunLPA +VA9yZhvZMToNfOuD4TUPBPloBuNzwBfZk2O4CaXeG4ailVWUfm5t/l+RD/55zYKu +hw1/Vl9lcOryF2XAmPQ2F1gwEKK7wt1Ak8zw8/yeYgBv1/F+ibCMvR6FVj9ABBEf +TM+oOs4oy51otUv0h63GqYgXMJyLX7q+AGWdC3srwwLQROtkzi7y00g/YryXUoIq +dXEI7CrNL35rZXcZ5LfGRwFX9evX11PpT3OShYlsJBcFE9KMatRoIWd6xUKlxTk0 +yLjoOUE2tsMJAgMBAAGjITAfMB0GA1UdDgQWBBQ6xJBQsJCJdj/u0iTLYYD2qQsB +DDANBgkqhkiG9w0BAQsFAAOCAQEAfoquV375+eAGmfnlLxB30v9VhsFckrxFVpYs +XXC6h2G8MtXLpIEpgJo+4SZ4YjNwf/8m9J5j/duU8RukYanyzJdgkFFqKDBYCX7U +SD1nQP7729KnQgxtbR/+i3zkNgo7FATdkLq+HOxklNOEE24Ldenya39bsG779B9n +Sskcbq++7rMM+onDYBv6PbUKCm6nfqPspq809CLxSaUJg9+9ykut6hiyke/i7GEP +XIZHrM+mEvG00ES/zBIdV6TE0AIBP7q2MN7ylT509Ko9sUBMOZdEzikYp5GaRdiv +zG9q6rqK5COK614BwJFOD1DKV1BoDFsgugvfvm/mrc3QfIUPDA== +-----END CERTIFICATE----- diff --git a/vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/TemplateBuilderTest.java b/vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/TemplateBuilderTest.java index 55a144322b..890ff0b1f0 100644 --- a/vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/TemplateBuilderTest.java +++ b/vertx-sql-client-templates/src/test/java/io/vertx/sqlclient/templates/TemplateBuilderTest.java @@ -1,6 +1,5 @@ package io.vertx.sqlclient.templates; -import io.vertx.core.AsyncResult; import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; @@ -23,7 +22,6 @@ import org.junit.Test; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.function.Supplier; diff --git a/vertx-sql-client/src/main/generated/io/vertx/sqlclient/SqlConnectOptionsConverter.java b/vertx-sql-client/src/main/generated/io/vertx/sqlclient/SqlConnectOptionsConverter.java index b8e98e3321..4a38b086cb 100644 --- a/vertx-sql-client/src/main/generated/io/vertx/sqlclient/SqlConnectOptionsConverter.java +++ b/vertx-sql-client/src/main/generated/io/vertx/sqlclient/SqlConnectOptionsConverter.java @@ -77,6 +77,21 @@ public static void fromJson(Iterable> json, break; case "usingDomainSocket": break; + case "reconnectAttempts": + if (member.getValue() instanceof Number) { + obj.setReconnectAttempts(((Number)member.getValue()).intValue()); + } + break; + case "reconnectInterval": + if (member.getValue() instanceof Number) { + obj.setReconnectInterval(((Number)member.getValue()).longValue()); + } + break; + case "sslOptions": + if (member.getValue() instanceof JsonObject) { + obj.setSslOptions(new io.vertx.core.net.ClientSSLOptions((io.vertx.core.json.JsonObject)member.getValue())); + } + break; } } } @@ -110,5 +125,10 @@ public static void toJson(SqlConnectOptions obj, java.util.Map j json.put("tracingPolicy", obj.getTracingPolicy().name()); } json.put("usingDomainSocket", obj.isUsingDomainSocket()); + json.put("reconnectAttempts", obj.getReconnectAttempts()); + json.put("reconnectInterval", obj.getReconnectInterval()); + if (obj.getSslOptions() != null) { + json.put("sslOptions", obj.getSslOptions().toJson()); + } } } diff --git a/vertx-sql-client/src/main/java/io/vertx/sqlclient/SqlConnectOptions.java b/vertx-sql-client/src/main/java/io/vertx/sqlclient/SqlConnectOptions.java index 389c56c0d1..e30cf54acb 100644 --- a/vertx-sql-client/src/main/java/io/vertx/sqlclient/SqlConnectOptions.java +++ b/vertx-sql-client/src/main/java/io/vertx/sqlclient/SqlConnectOptions.java @@ -13,16 +13,13 @@ import io.vertx.codegen.annotations.DataObject; import io.vertx.codegen.annotations.GenIgnore; -import io.vertx.core.json.Json; import io.vertx.core.json.JsonObject; -import io.vertx.core.net.NetClientOptions; -import io.vertx.core.net.NetClientOptionsConverter; +import io.vertx.core.net.ClientSSLOptions; import io.vertx.core.net.SocketAddress; import io.vertx.core.tracing.TracingPolicy; import io.vertx.sqlclient.spi.Driver; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -35,7 +32,7 @@ * Connect options for configuring {@link SqlConnection} or {@link Pool}. */ @DataObject(generateConverter = true) -public class SqlConnectOptions extends NetClientOptions { +public class SqlConnectOptions { /** * Provide a {@link SqlConnectOptions} subclass configured from {@code connectionUri}. @@ -50,7 +47,7 @@ public class SqlConnectOptions extends NetClientOptions { */ public static SqlConnectOptions fromUri(String connectionUri) throws IllegalArgumentException, ServiceConfigurationError { List candidates = new ArrayList<>(1); - for (Driver d : ServiceLoader.load(Driver.class)) { + for (Driver d : ServiceLoader.load(Driver.class)) { SqlConnectOptions options = d.parseConnectionUri(connectionUri); if (options != null) { candidates.add(options); @@ -65,6 +62,8 @@ public static SqlConnectOptions fromUri(String connectionUri) throws IllegalArgu } } + public static final int DEFAULT_RECONNECT_ATTEMPTS = 0; + public static final long DEFAULT_RECONNECT_INTERVAL = 1000; public static final boolean DEFAULT_CACHE_PREPARED_STATEMENTS = false; public static final int DEFAULT_PREPARED_STATEMENT_CACHE_MAX_SIZE = 256; public static final int DEFAULT_PREPARED_STATEMENT_CACHE_SQL_LIMIT = 2048; @@ -80,20 +79,20 @@ public static SqlConnectOptions fromUri(String connectionUri) throws IllegalArgu private Predicate preparedStatementCacheSqlFilter = DEFAULT_PREPARED_STATEMENT_CACHE_FILTER; private Map properties = new HashMap<>(4); private TracingPolicy tracingPolicy; + private int reconnectAttempts; + private long reconnectInterval; + private ClientSSLOptions sslOptions; public SqlConnectOptions() { - super(); init(); } public SqlConnectOptions(JsonObject json) { - super(json); init(); SqlConnectOptionsConverter.fromJson(json, this); } public SqlConnectOptions(SqlConnectOptions other) { - super(other); this.host = other.host; this.port = other.port; this.user = other.user; @@ -105,6 +104,10 @@ public SqlConnectOptions(SqlConnectOptions other) { if (other.properties != null) { this.properties = new HashMap<>(other.properties); } + this.reconnectAttempts = other.reconnectAttempts; + this.reconnectInterval = other.reconnectInterval; + ClientSSLOptions sslOptions = other.sslOptions; + this.sslOptions = sslOptions != null ? sslOptions.copy() : null; } /** @@ -323,7 +326,6 @@ public SqlConnectOptions addProperty(String key, String value) { return this; } - @GenIgnore public SocketAddress getSocketAddress() { return SocketAddress.inetSocketAddress(getPort(), getHost()); @@ -351,9 +353,59 @@ public boolean isUsingDomainSocket() { return false; } - @Override + /** + * @return the value of reconnect attempts + */ + public int getReconnectAttempts() { + return reconnectAttempts; + } + + /** + * Set the value of reconnect attempts + * + * @param attempts the maximum number of reconnect attempts + * @return a reference to this, so the API can be used fluently + */ + public SqlConnectOptions setReconnectAttempts(int attempts) { + if (attempts < -1) { + throw new IllegalArgumentException("reconnect attempts must be >= -1"); + } + this.reconnectAttempts = attempts; + return this; + } + + /** + * @return the value of reconnect interval + */ + public long getReconnectInterval() { + return reconnectInterval; + } + + /** + * Set the reconnect interval + * + * @param interval the reconnect interval in ms + * @return a reference to this, so the API can be used fluently + */ + public SqlConnectOptions setReconnectInterval(long interval) { + if (interval < 1) { + throw new IllegalArgumentException("reconnect interval must be >= 1"); + } + this.reconnectInterval = interval; + return this; + } + + public ClientSSLOptions getSslOptions() { + return sslOptions; + } + + public SqlConnectOptions setSslOptions(ClientSSLOptions sslOptions) { + this.sslOptions = sslOptions; + return this; + } + public JsonObject toJson() { - JsonObject json = super.toJson(); + JsonObject json = new JsonObject(); SqlConnectOptionsConverter.toJson(this, json); return json; } diff --git a/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/ConnectionFactoryBase.java b/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/ConnectionFactoryBase.java index 00ec34d705..995e7c9a28 100644 --- a/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/ConnectionFactoryBase.java +++ b/vertx-sql-client/src/main/java/io/vertx/sqlclient/impl/ConnectionFactoryBase.java @@ -10,24 +10,15 @@ */ package io.vertx.sqlclient.impl; -import io.vertx.core.CompositeFuture; import io.vertx.core.Future; import io.vertx.core.Promise; import io.vertx.core.impl.*; import io.vertx.core.impl.future.PromiseInternal; -import io.vertx.core.json.JsonObject; -import io.vertx.core.net.NetClient; import io.vertx.core.net.NetClientOptions; -import io.vertx.core.net.impl.NetClientBuilder; import io.vertx.core.net.impl.NetClientInternal; import io.vertx.sqlclient.SqlConnectOptions; import io.vertx.sqlclient.spi.ConnectionFactory; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - /** * An base connection factory for creating database connections */ @@ -36,48 +27,24 @@ public abstract class ConnectionFactoryBase impleme public static final String NATIVE_TRANSPORT_REQUIRED = "The Vertx instance must use a native transport in order to connect to connect through domain sockets"; protected final VertxInternal vertx; - private final Map clients; + protected final NetClientInternal client; + protected final NetClientOptions tcpOptions; // close hook protected final CloseSequence clientCloseFuture = new CloseSequence(this::doClose); protected ConnectionFactoryBase(VertxInternal vertx) { - this.vertx = vertx; - this.clients = new HashMap<>(); - } - - private void doClose(Promise p) { - List> futures = clients.values().stream().map(client -> client.close()).collect(Collectors.toList()); - - CompositeFuture join = Future.join(futures); - - join.onComplete(ar -> p.complete()); + this(vertx, new NetClientOptions()); } - private NetClient createNetClient(NetClientOptions options) { - options.setReconnectAttempts(0); // auto-retry is handled on the protocol level instead of network level - - NetClientInternal netClient = new NetClientBuilder(vertx, options).build(); - - - // return new NetClientBuilder(vertx, options).closeFuture(clientCloseFuture).build(); - return netClient; + protected ConnectionFactoryBase(VertxInternal vertx, NetClientOptions tcpOptions) { + this.vertx = vertx; + this.client = (NetClientInternal) vertx.createNetClient(new NetClientOptions(tcpOptions).setReconnectAttempts(0)); // auto-retry is handled on the protocol level instead of network level + this.tcpOptions = tcpOptions; } - protected NetClient netClient(NetClientOptions options) { - if (options.getClass() != NetClientOptions.class) { - options = new NetClientOptions(options); - } - JsonObject key = options.toJson(); - NetClient client; - synchronized (this) { - client = clients.get(key); - if (client == null) { - client = createNetClient(options); - clients.put(key, client); - } - } - return client; + private void doClose(Promise p) { + client.close().onComplete(ar -> p.complete()); } public static ContextInternal asEventLoopContext(ContextInternal ctx) { diff --git a/vertx-sql-client/src/main/java/io/vertx/sqlclient/spi/Driver.java b/vertx-sql-client/src/main/java/io/vertx/sqlclient/spi/Driver.java index 6f19f333fe..f89386e43f 100644 --- a/vertx-sql-client/src/main/java/io/vertx/sqlclient/spi/Driver.java +++ b/vertx-sql-client/src/main/java/io/vertx/sqlclient/spi/Driver.java @@ -42,7 +42,7 @@ public interface Driver { *

The returned pool will automatically closed when {@code vertx} is not {@code null} and is closed or when the creating * context is closed (e.g verticle undeployment). * - * @param vertx the Vertx instance to be used with the connection pool or {@code null} to create an auto closed Vertx instance + * @param vertx the Vertx instance to be used with the connection pool or {@code null} to create an auto closed Vertx instance * @param databases the list of databases * @param options the options for creating the pool * @return the connection pool @@ -53,12 +53,7 @@ default Pool createPool(Vertx vertx, Supplier> databases, PoolOptions if (Vertx.currentContext() != null) { throw new IllegalStateException("Running in a Vertx context => use Pool#pool(Vertx, SqlConnectOptions, PoolOptions) instead"); } - VertxOptions vertxOptions = new VertxOptions(); - if (databases instanceof SingletonSupplier) { - SqlConnectOptions connectOptions = ((SingletonSupplier) databases).unwrap(); - vertxOptions.setPreferNativeTransport(connectOptions.isUsingDomainSocket()); - } - vx = (VertxInternal) Vertx.vertx(vertxOptions); + vx = (VertxInternal) Vertx.vertx(new VertxOptions()); } else { vx = (VertxInternal) vertx; } @@ -131,7 +126,7 @@ default Pool newPool(Vertx vertx, List databases, PoolOptions options, CloseF /** * Create a connection factory to the given {@code database}. * - * @param vertx the Vertx instance t + * @param vertx the Vertx instance * @return the connection factory */ ConnectionFactory createConnectionFactory(Vertx vertx);