Skip to content

Commit 12e3b74

Browse files
committed
updated tests and docs
1 parent e6faeea commit 12e3b74

4 files changed

Lines changed: 26 additions & 5 deletions

File tree

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,13 @@ public SSLContext createSSLContext(Map<String, Object> configuration) {
173173
final String sslCertificate = (String) configuration.get(ClientConfigProperties.SSL_CERTIFICATE.getKey());
174174
final String sslKey = (String) configuration.get(ClientConfigProperties.SSL_KEY.getKey());
175175

176+
// This method is only reached when a secure (https) endpoint is configured, so SSLMode.Disabled
177+
// contradicts the endpoint scheme. The mode does not turn encryption off - the scheme decides it.
178+
if (sslMode == SSLMode.Disabled) {
179+
throw new ClientMisconfigurationException("SSL mode '" + SSLMode.Disabled
180+
+ "' cannot be used with a secure (https) endpoint. Use SSLMode.Trust to trust all certificates or use plain HTTP");
181+
}
182+
176183
if (sslMode == SSLMode.Trust) {
177184
// Server certificate is not validated. Trust material (trust store or CA certificate)
178185
// is not needed, but client certificate and key are still applied for mTLS.

client-v2/src/test/java/com/clickhouse/client/ClientTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ public void testDefaultSettings() {
332332
Assert.assertEquals(config.get(p.getKey()), p.getDefaultValue(), "Default value doesn't match");
333333
}
334334
}
335-
Assert.assertEquals(config.size(), 34); // to check everything is set. Increment when new added.
335+
Assert.assertEquals(config.size(), 35); // to check everything is set. Increment when new added.
336336
}
337337

338338
try (Client client = new Client.Builder()
@@ -365,7 +365,7 @@ public void testDefaultSettings() {
365365
.setSocketSndbuf(100000)
366366
.build()) {
367367
Map<String, String> config = client.getConfiguration();
368-
Assert.assertEquals(config.size(), 35); // to check everything is set. Increment when new added.
368+
Assert.assertEquals(config.size(), 36); // to check everything is set. Increment when new added.
369369
Assert.assertEquals(config.get(ClientConfigProperties.DATABASE.getKey()), "mydb");
370370
Assert.assertEquals(config.get(ClientConfigProperties.MAX_EXECUTION_TIME.getKey()), "10");
371371
Assert.assertEquals(config.get(ClientConfigProperties.COMPRESSION_LZ4_UNCOMPRESSED_BUF_SIZE.getKey()), "300000");
@@ -389,6 +389,7 @@ public void testDefaultSettings() {
389389
Assert.assertEquals(config.get(ClientConfigProperties.SOCKET_OPERATION_TIMEOUT.getKey()), "20000");
390390
Assert.assertEquals(config.get(ClientConfigProperties.SOCKET_RCVBUF_OPT.getKey()), "100000");
391391
Assert.assertEquals(config.get(ClientConfigProperties.SOCKET_SNDBUF_OPT.getKey()), "100000");
392+
Assert.assertEquals(config.get(ClientConfigProperties.SSL_MODE.getKey()), "Strict");
392393
}
393394
}
394395

@@ -432,7 +433,7 @@ public void testWithOldDefaults() {
432433
Assert.assertEquals(config.get(p.getKey()), p.getDefaultValue(), "Default value doesn't match");
433434
}
434435
}
435-
Assert.assertEquals(config.size(), 34); // to check everything is set. Increment when new added.
436+
Assert.assertEquals(config.size(), 35); // to check everything is set. Increment when new added.
436437
}
437438
}
438439

client-v2/src/test/java/com/clickhouse/client/HttpTransportTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,15 @@ public void testSSLModeDisabled() {
389389
} catch (Exception e) {
390390
Assert.fail("Disabled SSL mode should work with a plain HTTP endpoint", e);
391391
}
392+
393+
ClickHouseNode secureServer = getSecureServer(ClickHouseProtocol.HTTP);
394+
// Disabled mode contradicts a secure (https) endpoint - the scheme decides encryption, not the mode
395+
Assert.expectThrows(ClientMisconfigurationException.class, () -> new Client.Builder()
396+
.addEndpoint("https://localhost:" + secureServer.getPort())
397+
.setUsername("default")
398+
.setPassword(ClickHouseServerForTest.getPassword())
399+
.setSSLMode(SSLMode.Disabled)
400+
.build());
392401
}
393402

394403
@Test(groups = { "integration" })

docs/features.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ This document lists stable, user-visible behavior in `client-v2` and `jdbc-v2` t
55
## `client-v2`
66

77
- HTTP and HTTPS connectivity: Connects to ClickHouse over HTTP(S), supports endpoint paths, and exposes a basic `ping` health check.
8-
- TLS configuration: Supports trust stores, client certificates/keys, SSL certificate authentication, and SNI for HTTPS connections.
8+
- TLS configuration: Supports trust stores, client certificates/keys, SSL certificate authentication, and SNI for HTTPS connections. Trust material (root CA and client certificate/key) can be supplied either as a file path or directly as PEM content.
9+
- SSL verification modes: `Client.Builder.setSSLMode(SSLMode)` (or the `ssl_mode` property) controls how strictly the server identity is verified on secure connections: `Disabled` (SSL not used; plain protocols only), `Trust` (encrypt but accept any server certificate and skip hostname verification, while still applying a client certificate/key for mTLS if configured), `VerifyCa` (validate the certificate chain but skip hostname verification), and `Strict` (full chain and hostname verification, default).
910
- Authentication modes: Supports username/password credentials, ClickHouse auth headers, bearer tokens, and optional HTTP Basic authentication.
1011
- Runtime credential updates: Existing `Client` instances can update username/password or bearer-token credentials for subsequent requests without rebuilding the client.
1112
- Proxy support: Can send requests through configured HTTP proxies, including proxy credentials.
@@ -41,13 +42,15 @@ Compatibility-sensitive traits:
4142
- `Geometry` handling is shape-sensitive: supported values are 1D through 4D Java arrays representing the nested geometry variants, and unsupported shapes or non-array values are rejected during serialization.
4243
- `Geometry` write inference is dimension-based rather than fully type-specific: point, ring/line string, polygon/multi-line string, and multi-polygon are selected from array depth, so writing `Geometry` cannot currently distinguish `Ring` from `LineString` or `Polygon` from `MultiLineString`.
4344
- Session precedence is part of the contract: client session defaults apply to each request, operation settings may override them, and only the client `session_id` is mutable at runtime while other client session properties remain fixed for the lifetime of the client.
45+
- SSL mode behavior is compatibility-sensitive: the default is `Strict`. `ssl_mode` does not enable or disable encryption - the endpoint scheme decides that. `Disabled` is only valid with a plain `http://` endpoint; combining it with an `https://` endpoint throws `ClientMisconfigurationException`. A CA certificate and a trust store cannot be configured together (the CA certificate must be imported into the trust store), and that combination also throws `ClientMisconfigurationException`. When reading the `ssl_mode` value through the client configuration map, enum names are matched case-sensitively (`Disabled`, `Trust`, `VerifyCa`, `Strict`).
46+
- Certificate-as-content support is compatibility-sensitive: any certificate or key value containing a PEM begin marker (`-----BEGIN`) is treated as inline PEM content, otherwise it is treated as a file path (also searched in the home directory and on the classpath).
4447

4548

4649
## `jdbc-v2`
4750

4851
- JDBC driver registration: Registers through the standard JDBC service mechanism and is available through `DriverManager`.
4952
- JDBC URL parsing: Accepts `jdbc:clickhouse:` and `jdbc:ch:` URLs with host, port, optional HTTP path, optional database, and query parameters.
50-
- SSL URL support: Supports HTTPS connections through URL and property configuration, including default protocol and port handling.
53+
- SSL URL support: Supports HTTPS connections through URL and property configuration, including default protocol and port handling. The `ssl_mode` property selects the verification strictness (`disabled`, `trust`, `verifyca`, `strict`); values are case-insensitive and the traditional JDBC value `none` is accepted as an alias for `trust`. Root CA and client certificate/key may be supplied as a file path or as inline PEM content.
5154
- Driver and client properties: Separates JDBC-specific properties from passthrough client options used by the underlying `client-v2` transport.
5255
- DataSource support: Provides a JDBC `DataSource` implementation backed by the same driver configuration model.
5356
- Connection lifecycle: Supports connection close, validity checks, ping-based health checks, and network timeout management.
@@ -85,4 +88,5 @@ Compatibility-sensitive traits:
8588
- `getString()` formatting for temporal values is stable output: `Date` uses `yyyy-MM-dd`, `DateTime` uses `yyyy-MM-dd HH:mm:ss`, and `DateTime64` preserves fractional precision, all interpreted in server timezone context where applicable.
8689
- Date and timestamp setters with `Calendar` are timezone-sensitive by design. Preserving the current day-shift and instant-preserving behavior is important for compatibility.
8790
- `setObject()` temporal behavior is specific and should not drift: `LocalDateTime` and `Instant` are rendered through `fromUnixTimestamp64Nano(...)`, while `Timestamp` and `Date` use quoted textual forms.
91+
- JDBC `ssl_mode` handling is compatibility-sensitive: values are case-insensitive, `none` is aliased to `trust` (the no-verification mode), and an unrecognized value throws `SQLException` during connection configuration. The normalized canonical mode name is forwarded to the underlying `client-v2` transport.
8892
- INSERT result semantics depend on server-side `async_insert` and `wait_for_async_insert`. The driver does not override these settings, so it follows whatever the server profile or user configuration sets. When `async_insert=1` and `wait_for_async_insert=0`, `Statement.executeUpdate(...)` and `PreparedStatement.executeUpdate(...)` may return `0` (or an under-counted value), and parsing/data errors in the INSERT body may not be reported synchronously as a `SQLException`. Set `async_insert=0` (or `wait_for_async_insert=1`) per connection or statement to restore synchronous row counts and error reporting.

0 commit comments

Comments
 (0)