Repository: quarkusio/quarkus
Issue: reactive-pg-client sslMode=verify-full not working

## Describe the bug
When using reactive-pg-client it is not possible to use sslMode verify_full because it fails with:

```java
2021-04-13 17:23:24,498 ERROR [org.hib.rea.errors] (vert.x-eventloop-thread-3) could not execute query: java.util.concurrent.CompletionException: java.lang.IllegalArgumentException: Host verification algorithm must be specified under verify-full sslmode
	at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:331)
	at java.base/java.util.concurrent.CompletableFuture.uniApplyNow(CompletableFuture.java:670)
	at java.base/java.util.concurrent.CompletableFuture.uniApplyStage(CompletableFuture.java:658)
	at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:2094)
	at java.base/java.util.concurrent.CompletableFuture.thenApply(CompletableFuture.java:143)
	at org.hibernate.reactive.pool.impl.ProxyConnection.withConnection(ProxyConnection.java:45)
	at org.hibernate.reactive.pool.impl.ProxyConnection.selectJdbc(ProxyConnection.java:109)
	at org.hibernate.reactive.loader.ReactiveLoader.executeReactiveQueryStatement(ReactiveLoader.java:129)
	at org.hibernate.reactive.loader.ReactiveLoader.doReactiveQueryAndInitializeNonLazyCollections(ReactiveLoader.java:69)
	at org.hibernate.reactive.loader.CachingReactiveLoader.doReactiveList(CachingReactiveLoader.java:62)
	at org.hibernate.reactive.loader.CachingReactiveLoader.reactiveListIgnoreQueryCache(CachingReactiveLoader.java:80)
	at org.hibernate.reactive.loader.custom.impl.ReactiveCustomLoader.reactiveList(ReactiveCustomLoader.java:94)
	at org.hibernate.reactive.session.impl.ReactiveSessionImpl.lambda$listReactiveCustomQuery$12(ReactiveSessionImpl.java:462)
	at java.base/java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:1106)
	at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2235)
	at java.base/java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:143)
	at org.hibernate.reactive.session.impl.ReactiveSessionImpl.listReactiveCustomQuery(ReactiveSessionImpl.java:462)
	at org.hibernate.reactive.session.impl.ReactiveSessionImpl.reactiveList(ReactiveSessionImpl.java:450)
	at org.hibernate.reactive.session.impl.ReactiveNativeQueryImpl.getReactiveResultList(ReactiveNativeQueryImpl.java:98)
	at org.hibernate.reactive.session.impl.ReactiveNativeQueryImpl.getReactiveSingleResult(ReactiveNativeQueryImpl.java:80)
	at io.smallrye.context.impl.wrappers.SlowContextualSupplier.get(SlowContextualSupplier.java:21)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage.subscribe(UniCreateFromCompletionStage.java:24)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.lambda$subscribe$0(UniRunSubscribeOn.java:27)
	at org.hibernate.reactive.mutiny.impl.MutinySessionFactoryImpl.lambda$null$0(MutinySessionFactoryImpl.java:56)
	at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366)
	at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.IllegalArgumentException: Host verification algorithm must be specified under verify-full sslmode
	at io.vertx.pgclient.impl.PgConnectionFactory.connect(PgConnectionFactory.java:141)
	at io.vertx.pgclient.impl.PgConnectionFactory.connectAndInit(PgConnectionFactory.java:105)
	at io.vertx.pgclient.impl.PgPoolImpl.connect(PgPoolImpl.java:47)
	at io.vertx.sqlclient.impl.ConnectionPool.check(ConnectionPool.java:207)
	at io.vertx.sqlclient.impl.ConnectionPool.acquire(ConnectionPool.java:76)
	at io.vertx.sqlclient.impl.PoolBase.getConnection(PoolBase.java:59)
	at io.quarkus.reactive.pg.client.runtime.ThreadLocalPgPool$PgPoolWrapper.getConnection(ThreadLocalPgPool.java:42)
	at io.quarkus.reactive.datasource.runtime.ThreadLocalPool.getConnection(ThreadLocalPool.java:104)
	at io.vertx.pgclient.PgPool_1d09fb569cbf9d284c8a4c30125d6bc55c456596_Synthetic_ClientProxy.getConnection(PgPool_1d09fb569cbf9d284c8a4c30125d6bc55c456596_Synthetic_ClientProxy.zig:116)
	at org.hibernate.reactive.pool.impl.SqlClientPool.lambda$getConnectionFromPool$1(SqlClientPool.java:76)
	at org.hibernate.reactive.pool.impl.Handlers.toCompletionStage(Handlers.java:24)
	at org.hibernate.reactive.pool.impl.SqlClientPool.getConnectionFromPool(SqlClientPool.java:75)
	at org.hibernate.reactive.pool.impl.SqlClientPool.getConnection(SqlClientPool.java:66)
	at org.hibernate.reactive.pool.impl.ProxyConnection.withConnection(ProxyConnection.java:44)
	... 28 more
```

But it is not possible to set host verification algorithm. We tried to set it as an uri parameter (hostnameVerificationAlgorithm) which is normally used by vertx but this does not work either.



### Expected behavior
You can configure hostnameVerificationAlgorithm the same way as you can configure sslMode.

### Actual behavior
You can only configure sslMode but not hostnameVerificationAlgorithm


## To Reproduce
No reproducer. It is sufficient to set sslMode without an existing db.

### Configuration
```properties
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=${POSTGRESQL_USER}
quarkus.datasource.password=${POSTGRESQL_PASSWORD}
quarkus.datasource.reactive.url=postgresql://${POSTGRESQL_HOST}:${POSTGRESQL_PORT}/${POSTGRESQL_DB}?hostnameVerificationAlgorithm=HTTPS
quarkus.datasource.reactive.trust-certificate-pem=true
quarkus.datasource.reactive.trust-certificate-pem.certs=${POSTGRESQL_SSL_ROOT_CERT}
quarkus.datasource.reactive.postgresql.ssl-mode=verify-full
```

## Environment (please complete the following information):

### Output of `uname -a` or `ver`
Darwin LMUCM870527 19.6.0 Darwin Kernel Version 19.6.0: Tue Nov 10 00:10:30 PST 2020; root:xnu-6153.141.10~1/RELEASE_X86_64 x86_64

### Output of `java -version`
openjdk version "11.0.10" 2021-01-19 LTS
OpenJDK Runtime Environment Corretto-11.0.10.9.1 (build 11.0.10+9-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.10.9.1 (build 11.0.10+9-LTS, mixed mode)

### Quarkus version or git rev
1.13.1.Final

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)
3.6.3


Changed files:
extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java
extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java
extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java
extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java

diff --git a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java
index 641b819c3bf..12aca499601 100644
--- a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java
+++ b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/DataSourceReactiveRuntimeConfig.java
@@ -109,6 +109,13 @@ public class DataSourceReactiveRuntimeConfig {
     @ConfigItem(defaultValue = "PT1S")
     public Duration reconnectInterval = Duration.ofSeconds(1L);
 
+    /**
+     * The hostname verification algorithm to use in case the server's identity should be checked.
+     * Should be HTTPS, LDAPS or an empty string.
+     */
+    @ConfigItem
+    public Optional<String> hostnameVerificationAlgorithm = Optional.empty();
+
     /**
      * The maximum time a connection remains unused in the pool before it is closed.
      */
diff --git a/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java b/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java
index 14376023144..99974956ac6 100644
--- a/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java
+++ b/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java
@@ -149,6 +149,11 @@ private DB2ConnectOptions toConnectOptions(DataSourceRuntimeConfig dataSourceRun
 
         connectOptions.setReconnectInterval(dataSourceReactiveRuntimeConfig.reconnectInterval.toMillis());
 
+        if (dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm.isPresent()) {
+            connectOptions.setHostnameVerificationAlgorithm(
+                    dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm.get());
+        }
+
         return connectOptions;
     }
 }
diff --git a/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java b/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java
index 38eeaa87e1b..9ff2584bfcc 100644
--- a/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java
+++ b/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java
@@ -26,6 +26,7 @@
 import io.vertx.core.Vertx;
 import io.vertx.mysqlclient.MySQLConnectOptions;
 import io.vertx.mysqlclient.MySQLPool;
+import io.vertx.mysqlclient.SslMode;
 import io.vertx.sqlclient.PoolOptions;
 
 @Recorder
@@ -141,7 +142,15 @@ private MySQLConnectOptions toMySQLConnectOptions(DataSourceRuntimeConfig dataSo
         }
 
         if (dataSourceReactiveMySQLConfig.sslMode.isPresent()) {
-            mysqlConnectOptions.setSslMode(dataSourceReactiveMySQLConfig.sslMode.get());
+            final SslMode sslMode = dataSourceReactiveMySQLConfig.sslMode.get();
+            mysqlConnectOptions.setSslMode(sslMode);
+
+            // If sslMode is verify-identity, we also need a hostname verification algorithm
+            if (sslMode == SslMode.VERIFY_IDENTITY && (!dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm
+                    .isPresent() || "".equals(dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm.get()))) {
+                throw new IllegalArgumentException(
+                        "quarkus.datasource.reactive.hostname-verification-algorithm must be specified under verify-identity sslmode");
+            }
         }
 
         mysqlConnectOptions.setTrustAll(dataSourceReactiveRuntimeConfig.trustAll);
@@ -158,6 +167,11 @@ private MySQLConnectOptions toMySQLConnectOptions(DataSourceRuntimeConfig dataSo
 
         mysqlConnectOptions.setReconnectInterval(dataSourceReactiveRuntimeConfig.reconnectInterval.toMillis());
 
+        if (dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm.isPresent()) {
+            mysqlConnectOptions.setHostnameVerificationAlgorithm(
+                    dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm.get());
+        }
+
         return mysqlConnectOptions;
     }
 
diff --git a/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java b/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java
index c1dc0f2ac58..88e4971aff1 100644
--- a/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java
+++ b/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java
@@ -26,6 +26,7 @@
 import io.vertx.core.Vertx;
 import io.vertx.pgclient.PgConnectOptions;
 import io.vertx.pgclient.PgPool;
+import io.vertx.pgclient.SslMode;
 import io.vertx.sqlclient.PoolOptions;
 
 @Recorder
@@ -129,7 +130,8 @@ private PgConnectOptions toPgConnectOptions(DataSourceRuntimeConfig dataSourceRu
         if (dataSourceReactivePostgreSQLConfig.cachePreparedStatements.isPresent()) {
             log.warn(
                     "datasource.reactive.postgresql.cache-prepared-statements is deprecated, use datasource.reactive.cache-prepared-statements instead");
-            pgConnectOptions.setCachePreparedStatements(dataSourceReactivePostgreSQLConfig.cachePreparedStatements.get());
+            pgConnectOptions
+                    .setCachePreparedStatements(dataSourceReactivePostgreSQLConfig.cachePreparedStatements.get());
         } else {
             pgConnectOptions.setCachePreparedStatements(dataSourceReactiveRuntimeConfig.cachePreparedStatements);
         }
@@ -139,7 +141,15 @@ private PgConnectOptions toPgConnectOptions(DataSourceRuntimeConfig dataSourceRu
         }
 
         if (dataSourceReactivePostgreSQLConfig.sslMode.isPresent()) {
-            pgConnectOptions.setSslMode(dataSourceReactivePostgreSQLConfig.sslMode.get());
+            final SslMode sslMode = dataSourceReactivePostgreSQLConfig.sslMode.get();
+            pgConnectOptions.setSslMode(sslMode);
+
+            // If sslMode is verify-full, we also need a hostname verification algorithm
+            if (sslMode == SslMode.VERIFY_FULL && (!dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm
+                    .isPresent() || "".equals(dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm.get()))) {
+                throw new IllegalArgumentException(
+                        "quarkus.datasource.reactive.hostname-verification-algorithm must be specified under verify-full sslmode");
+            }
         }
 
         pgConnectOptions.setTrustAll(dataSourceReactiveRuntimeConfig.trustAll);
@@ -156,6 +166,11 @@ private PgConnectOptions toPgConnectOptions(DataSourceRuntimeConfig dataSourceRu
 
         pgConnectOptions.setReconnectInterval(dataSourceReactiveRuntimeConfig.reconnectInterval.toMillis());
 
+        if (dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm.isPresent()) {
+            pgConnectOptions.setHostnameVerificationAlgorithm(
+                    dataSourceReactiveRuntimeConfig.hostnameVerificationAlgorithm.get());
+        }
+
         return pgConnectOptions;
     }
 }