Skip to content

Commit 61ba88c

Browse files
committed
Refactoring sslContext creating and add AllTrustStrategy for cert verify
1 parent d27ac08 commit 61ba88c

File tree

12 files changed

+509
-84
lines changed

12 files changed

+509
-84
lines changed

client-v2/src/main/java/com/clickhouse/client/api/Client.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,16 @@ public Builder useBearerTokenAuth(String bearerToken) {
991991
return this;
992992
}
993993

994+
/**
995+
* Disable cert check.
996+
*
997+
* @return same instance of the builder
998+
*/
999+
public Builder setSslTrustAllStrategy() {
1000+
this.configuration.put(ClientConfigProperties.SSL_TRUST_ALL_STRATEGY.getKey(), "true");
1001+
return this;
1002+
}
1003+
9941004
/**
9951005
* Registers http client metrics with MeterRegistry.
9961006
*

client-v2/src/main/java/com/clickhouse/client/api/ClientConfigProperties.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ public enum ClientConfigProperties {
101101

102102
MAX_EXECUTION_TIME("max_execution_time", Integer.class,"0"),
103103

104+
/**
105+
* More information {@link org.apache.hc.client5.http.ssl.TrustAllStrategy}.
106+
*/
107+
SSL_TRUST_ALL_STRATEGY("trust_all", Boolean.class, "false"),
108+
109+
SSL_CERTIFICATE_TYPE("sslcerttype", String.class, "X.509"),
110+
111+
SSL_PROTOCOL("sslprotocol", String.class, "TLS"),
112+
113+
SSL_KEY_ALGORITHM("sslkeyalg", String.class, "RSA"),
114+
104115
SSL_TRUST_STORE("trust_store", String.class),
105116

106117
SSL_KEYSTORE_TYPE("key_store_type", String.class),

client-v2/src/main/java/com/clickhouse/client/api/internal/HttpAPIClientHelper.java

Lines changed: 42 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.clickhouse.client.api.ServerException;
1414
import com.clickhouse.client.api.enums.ProxyType;
1515
import com.clickhouse.client.api.http.ClickHouseHttpProto;
16+
import com.clickhouse.client.api.ssl.factory.SslContextStrategyFactory;
1617
import com.clickhouse.client.api.transport.Endpoint;
1718
import com.clickhouse.data.ClickHouseFormat;
1819
import net.jpountz.lz4.LZ4Factory;
@@ -106,7 +107,7 @@ public class HttpAPIClientHelper {
106107
private static final int ERROR_BODY_BUFFER_SIZE = 1024; // Error messages are usually small
107108

108109
private static final Pattern PATTERN_HEADER_VALUE_ASCII = Pattern.compile(
109-
"\\p{Graph}+(?:[ ]\\p{Graph}+)*");
110+
"\\p{Graph}+(?:[ ]\\p{Graph}+)*");
110111

111112
private final CloseableHttpClient httpClient;
112113

@@ -137,54 +138,13 @@ public HttpAPIClientHelper(Map<String, Object> configuration, Object metricsRegi
137138
this.defaultUserAgent = buildDefaultUserAgent();
138139
}
139140

140-
/**
141-
* Creates or returns default SSL context.
142-
*
143-
* @return SSLContext
144-
*/
145-
public SSLContext createSSLContext(Map<String, Object> configuration) {
146-
SSLContext sslContext;
147-
try {
148-
sslContext = SSLContext.getDefault();
149-
} catch (NoSuchAlgorithmException e) {
150-
throw new ClientException("Failed to create default SSL context", e);
151-
}
152-
ClickHouseSslContextProvider sslContextProvider = ClickHouseSslContextProvider.getProvider();
153-
String trustStorePath = (String) configuration.get(ClientConfigProperties.SSL_TRUST_STORE.getKey());
154-
if (trustStorePath != null) {
155-
try {
156-
sslContext = sslContextProvider.getSslContextFromKeyStore(
157-
trustStorePath,
158-
(String) configuration.get(ClientConfigProperties.SSL_KEY_STORE_PASSWORD.getKey()),
159-
(String) configuration.get(ClientConfigProperties.SSL_KEYSTORE_TYPE.getKey())
160-
);
161-
} catch (SSLException e) {
162-
throw new ClientMisconfigurationException("Failed to create SSL context from a keystore", e);
163-
}
164-
} else if (configuration.get(ClientConfigProperties.CA_CERTIFICATE.getKey()) != null ||
165-
configuration.get(ClientConfigProperties.SSL_CERTIFICATE.getKey()) != null ||
166-
configuration.get(ClientConfigProperties.SSL_KEY.getKey()) != null) {
167-
168-
try {
169-
sslContext = sslContextProvider.getSslContextFromCerts(
170-
(String) configuration.get(ClientConfigProperties.SSL_CERTIFICATE.getKey()),
171-
(String) configuration.get(ClientConfigProperties.SSL_KEY.getKey()),
172-
(String) configuration.get(ClientConfigProperties.CA_CERTIFICATE.getKey())
173-
);
174-
} catch (SSLException e) {
175-
throw new ClientMisconfigurationException("Failed to create SSL context from certificates", e);
176-
}
177-
}
178-
return sslContext;
179-
}
180-
181141
private static final long CONNECTION_INACTIVITY_CHECK = 5000L;
182142

183143
private ConnectionConfig createConnectionConfig(Map<String, Object> configuration) {
184144
ConnectionConfig.Builder connConfig = ConnectionConfig.custom();
185145

186-
ClientConfigProperties.CONNECTION_TTL.<Long>applyIfSet(configuration, (t) -> connConfig.setTimeToLive(t, TimeUnit.MILLISECONDS));
187-
ClientConfigProperties.CONNECTION_TIMEOUT.<Long>applyIfSet(configuration, (t) -> connConfig.setConnectTimeout(t, TimeUnit.MILLISECONDS));
146+
ClientConfigProperties.CONNECTION_TTL.<Long>applyIfSet(configuration, (t) -> connConfig.setTimeToLive(t, TimeUnit.MILLISECONDS));
147+
ClientConfigProperties.CONNECTION_TIMEOUT.<Long>applyIfSet(configuration, (t) -> connConfig.setConnectTimeout(t, TimeUnit.MILLISECONDS));
188148
connConfig.setValidateAfterInactivity(CONNECTION_INACTIVITY_CHECK, TimeUnit.MILLISECONDS); // non-configurable for now
189149

190150
return connConfig.build();
@@ -255,10 +215,10 @@ private HttpClientConnectionManager poolConnectionManager(LayeredConnectionSocke
255215
public CloseableHttpClient createHttpClient(boolean initSslContext, Map<String, Object> configuration) {
256216
// Top Level builders
257217
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
258-
SSLContext sslContext = initSslContext ? createSSLContext(configuration) : null;
218+
SSLContext sslContext = initSslContext ? new SslContextStrategyFactory(configuration).getSslContextStrategy().createSSLContext() : null;
259219
LayeredConnectionSocketFactory sslConnectionSocketFactory;
260220
if (sslContext != null) {
261-
String socketSNI = (String)configuration.get(ClientConfigProperties.SSL_SOCKET_SNI.getKey());
221+
String socketSNI = (String) configuration.get(ClientConfigProperties.SSL_SOCKET_SNI.getKey());
262222
if (socketSNI != null && !socketSNI.trim().isEmpty()) {
263223
sslConnectionSocketFactory = new CustomSSLConnectionFactory(socketSNI, sslContext, (hostname, session) -> true);
264224
} else {
@@ -305,7 +265,7 @@ public CloseableHttpClient createHttpClient(boolean initSslContext, Map<String,
305265
soCfgBuilder.setSocksProxyAddress(new InetSocketAddress(proxyHost, proxyPort));
306266
}
307267

308-
boolean disableCookies = !((Boolean)ClientConfigProperties.HTTP_SAVE_COOKIES.getOrDefault(configuration));
268+
boolean disableCookies = !((Boolean) ClientConfigProperties.HTTP_SAVE_COOKIES.getOrDefault(configuration));
309269
if (disableCookies) {
310270
clientBuilder.disableCookieManagement();
311271
}
@@ -325,7 +285,7 @@ public CloseableHttpClient createHttpClient(boolean initSslContext, Map<String,
325285
return clientBuilder.build();
326286
}
327287

328-
// private static final String ERROR_CODE_PREFIX_PATTERN = "Code: %d. DB::Exception:";
288+
// private static final String ERROR_CODE_PREFIX_PATTERN = "Code: %d. DB::Exception:";
329289
private static final String ERROR_CODE_PREFIX_PATTERN = "%d. DB::Exception:";
330290

331291
/**
@@ -438,10 +398,10 @@ public ClassicHttpResponse executeRequest(Endpoint server, Map<String, Object> r
438398

439399
HttpClientContext context = HttpClientContext.create();
440400
Number responseTimeout = ClientConfigProperties.SOCKET_OPERATION_TIMEOUT.getOrDefault(requestConfig);
441-
Number connectionReqTimeout = ClientConfigProperties.CONNECTION_REQUEST_TIMEOUT.getOrDefault(requestConfig);
401+
Number connectionReqTimeout = ClientConfigProperties.CONNECTION_REQUEST_TIMEOUT.getOrDefault(requestConfig);
442402
RequestConfig reqHttpConf = RequestConfig.custom()
443-
.setResponseTimeout(responseTimeout.longValue(), TimeUnit.MILLISECONDS)
444-
.setConnectionRequestTimeout(connectionReqTimeout.longValue(), TimeUnit.MILLISECONDS)
403+
.setResponseTimeout(responseTimeout.longValue(), TimeUnit.MILLISECONDS)
404+
.setConnectionRequestTimeout(connectionReqTimeout.longValue(), TimeUnit.MILLISECONDS)
445405
.build();
446406
context.setRequestConfig(reqHttpConf);
447407

@@ -492,52 +452,52 @@ private void addHeaders(HttpPost req, Map<String, Object> requestConfig) {
492452
addHeader(req, HttpHeaders.CONTENT_TYPE, CONTENT_TYPE.getMimeType());
493453
if (requestConfig.containsKey(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey())) {
494454
addHeader(
495-
req,
496-
ClickHouseHttpProto.HEADER_FORMAT,
455+
req,
456+
ClickHouseHttpProto.HEADER_FORMAT,
497457
((ClickHouseFormat) requestConfig.get(ClientConfigProperties.INPUT_OUTPUT_FORMAT.getKey())).name());
498458
}
499459
if (requestConfig.containsKey(ClientConfigProperties.QUERY_ID.getKey())) {
500460
addHeader(
501-
req,
502-
ClickHouseHttpProto.HEADER_QUERY_ID,
461+
req,
462+
ClickHouseHttpProto.HEADER_QUERY_ID,
503463
(String) requestConfig.get(ClientConfigProperties.QUERY_ID.getKey()));
504464
}
505465
addHeader(
506-
req,
507-
ClickHouseHttpProto.HEADER_DATABASE,
508-
ClientConfigProperties.DATABASE.getOrDefault(requestConfig));
466+
req,
467+
ClickHouseHttpProto.HEADER_DATABASE,
468+
ClientConfigProperties.DATABASE.getOrDefault(requestConfig));
509469

510470
if (ClientConfigProperties.SSL_AUTH.<Boolean>getOrDefault(requestConfig).booleanValue()) {
511471
addHeader(
512-
req,
513-
ClickHouseHttpProto.HEADER_DB_USER,
514-
ClientConfigProperties.USER.getOrDefault(requestConfig));
472+
req,
473+
ClickHouseHttpProto.HEADER_DB_USER,
474+
ClientConfigProperties.USER.getOrDefault(requestConfig));
515475
addHeader(
516-
req,
517-
ClickHouseHttpProto.HEADER_SSL_CERT_AUTH,
518-
"on");
476+
req,
477+
ClickHouseHttpProto.HEADER_SSL_CERT_AUTH,
478+
"on");
519479
} else if (ClientConfigProperties.HTTP_USE_BASIC_AUTH.<Boolean>getOrDefault(requestConfig).booleanValue()) {
520480
String user = ClientConfigProperties.USER.getOrDefault(requestConfig);
521481
String password = ClientConfigProperties.PASSWORD.getOrDefault(requestConfig);
522482
// Use as-is, no encoding allowed
523483
req.addHeader(
524-
HttpHeaders.AUTHORIZATION,
525-
"Basic " + Base64.getEncoder().encodeToString(
526-
(user + ":" + password).getBytes(StandardCharsets.UTF_8)));
484+
HttpHeaders.AUTHORIZATION,
485+
"Basic " + Base64.getEncoder().encodeToString(
486+
(user + ":" + password).getBytes(StandardCharsets.UTF_8)));
527487
} else {
528488
addHeader(
529-
req,
530-
ClickHouseHttpProto.HEADER_DB_USER,
531-
ClientConfigProperties.USER.getOrDefault(requestConfig));
489+
req,
490+
ClickHouseHttpProto.HEADER_DB_USER,
491+
ClientConfigProperties.USER.getOrDefault(requestConfig));
532492
addHeader(
533-
req,
534-
ClickHouseHttpProto.HEADER_DB_PASSWORD,
535-
ClientConfigProperties.PASSWORD.getOrDefault(requestConfig));
493+
req,
494+
ClickHouseHttpProto.HEADER_DB_PASSWORD,
495+
ClientConfigProperties.PASSWORD.getOrDefault(requestConfig));
536496
}
537497
if (proxyAuthHeaderValue != null) {
538498
req.addHeader(
539-
HttpHeaders.PROXY_AUTHORIZATION,
540-
proxyAuthHeaderValue);
499+
HttpHeaders.PROXY_AUTHORIZATION,
500+
proxyAuthHeaderValue);
541501
}
542502

543503
boolean clientCompression = ClientConfigProperties.COMPRESS_CLIENT_REQUEST.getOrDefault(requestConfig);
@@ -559,18 +519,17 @@ private void addHeaders(HttpPost req, Map<String, Object> requestConfig) {
559519
Object val = requestConfig.get(key);
560520
if (val != null) {
561521
addHeader(
562-
req,
563-
key.substring(ClientConfigProperties.HTTP_HEADER_PREFIX.length()),
564-
String.valueOf(val));
522+
req,
523+
key.substring(ClientConfigProperties.HTTP_HEADER_PREFIX.length()),
524+
String.valueOf(val));
565525
}
566526
}
567527
}
568528

569529
// Special cases
570530
if (req.containsHeader(HttpHeaders.AUTHORIZATION)
571-
&& (req.containsHeader(ClickHouseHttpProto.HEADER_DB_USER) ||
572-
req.containsHeader(ClickHouseHttpProto.HEADER_DB_PASSWORD)))
573-
{
531+
&& (req.containsHeader(ClickHouseHttpProto.HEADER_DB_USER) ||
532+
req.containsHeader(ClickHouseHttpProto.HEADER_DB_PASSWORD))) {
574533
// user has set auth header for purpose, lets remove ours
575534
req.removeHeaders(ClickHouseHttpProto.HEADER_DB_USER);
576535
req.removeHeaders(ClickHouseHttpProto.HEADER_DB_PASSWORD);
@@ -800,8 +759,7 @@ public void close() {
800759
}
801760

802761
private static <T> void addHeader(HttpRequest req, String headerName,
803-
String value)
804-
{
762+
String value) {
805763
if (value == null) {
806764
return;
807765
}
@@ -817,7 +775,7 @@ private static <T> void addHeader(HttpRequest req, String headerName,
817775
headerName + "*",
818776
"UTF-8''" + URLEncoder.encode(value, StandardCharsets.UTF_8.name()));
819777
} catch (UnsupportedEncodingException e) {
820-
throw new ClientException("Failed to convert string to UTF8" , e);
778+
throw new ClientException("Failed to convert string to UTF8", e);
821779
}
822780
}
823781
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.clickhouse.client.api.ssl.context;
2+
3+
import com.clickhouse.client.api.ClientConfigProperties;
4+
import com.clickhouse.client.api.ClientMisconfigurationException;
5+
import org.apache.hc.client5.http.ssl.TrustAllStrategy;
6+
import org.apache.hc.core5.ssl.SSLContextBuilder;
7+
8+
import javax.net.ssl.SSLContext;
9+
import java.security.KeyManagementException;
10+
import java.security.KeyStoreException;
11+
import java.security.NoSuchAlgorithmException;
12+
import java.util.Map;
13+
14+
public final class AllTrustSslContextStrategy implements SslContextStrategy {
15+
16+
private final Map<String, Object> config;
17+
18+
public AllTrustSslContextStrategy(Map<String, Object> config) {
19+
this.config = config;
20+
}
21+
22+
@Override
23+
public boolean support() {
24+
return this.config.get(ClientConfigProperties.SSL_TRUST_ALL_STRATEGY.getKey()) != null &&
25+
(boolean) this.config.get(ClientConfigProperties.SSL_TRUST_ALL_STRATEGY.getKey());
26+
}
27+
28+
@Override
29+
public SSLContext createSSLContext() {
30+
try {
31+
return SSLContextBuilder.create()
32+
.loadTrustMaterial(new TrustAllStrategy())
33+
.build();
34+
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
35+
throw new ClientMisconfigurationException("Failed to create SSL context with all trust strategy", e);
36+
}
37+
}
38+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.clickhouse.client.api.ssl.context;
2+
3+
import com.clickhouse.client.api.ClientMisconfigurationException;
4+
5+
import javax.net.ssl.SSLContext;
6+
import java.security.NoSuchAlgorithmException;
7+
8+
public final class DefaultSslContextStrategy implements SslContextStrategy {
9+
10+
@Override
11+
public boolean support() {
12+
return true;
13+
}
14+
15+
@Override
16+
public SSLContext createSSLContext() {
17+
try {
18+
return SSLContext.getDefault();
19+
} catch (NoSuchAlgorithmException e) {
20+
throw new ClientMisconfigurationException("Failed to create default SSL context", e);
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)