Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## 1.12.0 [unreleased]

### Features

1. [#470](https://github.com/InfluxCommunity/influxdb3-java/pull/470):
- Add support for mTLS.
- Support separated .crt and .key files or bundled certificate and key in one .p12 file.

### CI

1. [#446](https://github.com/InfluxCommunity/influxdb3-java/pull/446): Sets up automated releasing to Maven Central
Expand Down
111 changes: 111 additions & 0 deletions examples/src/main/java/com/influxdb/v3/TlsConfigExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.influxdb.v3;

import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import com.influxdb.v3.client.InfluxDBClient;
import com.influxdb.v3.client.PointValues;
import com.influxdb.v3.client.config.ClientConfig;

public final class TlsConfigExample {

public static String resolveProperty(final String property, final String fallback) {
return System.getProperty(property, System.getenv(property)) == null
? fallback : System.getProperty(property, System.getenv(property));
}

private TlsConfigExample() { }

public static void main(final String[] args) {
String host = resolveProperty("INFLUX_HOST", "https://localhost:8181");
String token = resolveProperty("INFLUX_TOKEN", "my-token");
String database = resolveProperty("INFLUX_DATABASE", "my-database");

String measurement = "tls_example";

// ClientConfig config = configTls(host, token, database);

// ClientConfig config = configMutualTls(host, token, database);

try (InfluxDBClient client = InfluxDBClient.getInstance(config)) {
client.writeRecord(String.format("%s,id=0001 temp=30.14,ticks=42i", measurement));

TimeUnit.SECONDS.sleep(1);
String sql = String.format("SELECT * FROM %s ORDER BY time DESC", measurement);
try (Stream<PointValues> values = client.queryPoints(sql)) {
values.forEach(pv -> {
String sv = measurement + ","
+ " id: " + pv.getTag("id") + ","
+ " fVal: " + pv.getFloatField("temp") + ","
+ " iVal: " + pv.getIntegerField("ticks") + ","
+ " " + pv.getTimestamp();
System.out.println(sv);
});
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public ClientConfig configTls(
@Nonnull final String host,
@Nonnull final String token,
@Nonnull final String database) {
ClientConfig.Builder configBuilder = new ClientConfig.Builder()
.host(host)
.token(token.toCharArray())
.database(database)
.sslRootsFilePath("path/to/server.crt");

// Optional, set this if client certificate is password protected.
configBuilder.sslRootFilePassword("password".toCharArray());
return configBuilder.build();
}

public ClientConfig configMutualTls(
@Nonnull final String host,
@Nonnull final String token,
@Nonnull final String database) {
ClientConfig.Builder configBuilder = new ClientConfig.Builder()
.host(host)
.token(token.toCharArray())
.database(database)
.sslRootsFilePath("path/to/server.crt");

// Optional, set this if server certificate is password-protected.
configBuilder.sslRootFilePassword("password".toCharArray());

// Config client certificate send to the server by using a bundled certificate and key in one .p12 file
// or separated .crt and .key files format, but NOT both.

// Using separated .crt and .key files format.
configBuilder.certificateFilePath("path/to/client.crt", "path/to/client.key");

// Using .p12 file format.
// configBuilder.certificateP12FilePath("path/to/client.p12", "password".toCharArray());


return configBuilder.build();
}
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@
**/target/**, **/*.jar, **/.git/**, **/.*, **/*.png, **/*.iml, **/*.bolt, .idea/**,
**/*nightly*/**, **/.m2/**, LICENSE, **/*.md, **/.github/**, license_header.txt,
release.properties/, **/pom.xml.releaseBackup, **/pom.xml.tag, **/semantic.yml,
.circleci/config.yml, **/*.pem
.circleci/config.yml, **/*.pem, **/*.p12, **/*.crt, **/*.key
</excludes>
</licenseSet>
</licenseSets>
Expand Down
149 changes: 148 additions & 1 deletion src/main/java/com/influxdb/v3/client/config/ClientConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@
* <li><code>authenticator</code> - HTTP proxy authenticator</li>
* <li><code>headers</code> - headers to be added to requests</li>
* <li><code>sslRootsFilePath</code> - path to the stored certificates file in PEM format</li>
* <li><code>sslRootFilePassword</code> - password for a stored certificates file in PEM format</li>
* <li><code>certificatePath</code> - path to the client certificate file in PEM format. Cannot be used together
* with <code>certificateP12FilePath</code></li>
* <li><code>certificateKeyPath</code> - path to the client certificate key file in PEM format</li>
* <li><code>certificateP12FilePath</code> - path to the client certificate file in P12 format. Cannot be used
* together with <code>certificatePath</code></li>
* <li><code>keyPassword</code> - password for a client certificate file in P12 format</li>
* <li><code>disableGRPCCompression</code> - disables the default gRPC compression header</li>
* <li><code>interceptors</code> - list of client interceptors to be used in the query API</li>
* </ul>
Expand Down Expand Up @@ -129,7 +136,12 @@ public final class ClientConfig {
private final String proxyUrl;
private final Authenticator authenticator;
private final Map<String, String> headers;
private final String certificatePath;
private final String certificateKeyPath;
private final String certificateP12FilePath;
private final char[] keyPassword;
private final String sslRootsFilePath;
private final char[] sslRootFilePassword;
private final boolean disableGRPCCompression;
private final List<ClientInterceptor> interceptors;

Expand Down Expand Up @@ -337,6 +349,59 @@ public String sslRootsFilePath() {
return sslRootsFilePath;
}

/**
* Gets certificate file password.
*
* @return the certificate file password may be null
*/
@Nullable
public char[] getSslRootFilePassword() {
return sslRootFilePassword;
}


/**
* Get a client certificate file path.
* Cannot be used together with certificateP12FilePath.
*
* @return the client certificate file path may be null.
*/
@Nullable
public String getCertificatePath() {
return certificatePath;
}

/**
* Get a client certificate key file path.
*
* @return the client certificate key file path may be null.
*/
@Nullable
public String getCertificateKeyPath() {
return certificateKeyPath;
}

/**
* Get a client certificate file path in .p12 file format.
* Cannot be used together with certificatePath.
*
* @return the client certificate file path may be null.
*/
@Nullable
public String getCertificateP12FilePath() {
return certificateP12FilePath;
}

/**
* Gets certificate file password.
*
* @return the certificate file password may be null
*/
@Nullable
public char[] getKeyPassword() {
return keyPassword;
}

/**
* Gets the (proxy) authenticator.
*
Expand Down Expand Up @@ -389,6 +454,18 @@ public void validate() {
if (uri.getHost() == null) {
throw new URISyntaxException(host, "Invalid URL.");
}

if ("https".equals(uri.getScheme())) {
if (certificatePath != null && certificateP12FilePath != null) {
throw new IllegalArgumentException("Cannot set both certificateFilePath "
+ "and certificateP12FilePath");
}

if (certificatePath != null && certificateKeyPath == null) {
throw new IllegalArgumentException("Cannot set certificatePath without certificateKeyPath");
}
}

} catch (URISyntaxException e) {
throw new IllegalArgumentException("Invalid URL.");
}
Expand Down Expand Up @@ -424,6 +501,11 @@ public boolean equals(final Object o) {
&& Objects.equals(authenticator, that.authenticator)
&& Objects.equals(headers, that.headers)
&& Objects.equals(sslRootsFilePath, that.sslRootsFilePath)
&& Arrays.equals(sslRootFilePassword, that.sslRootFilePassword)
&& Objects.equals(certificatePath, that.certificatePath)
&& Objects.equals(certificateKeyPath, that.certificateKeyPath)
&& Objects.equals(certificateP12FilePath, that.certificateP12FilePath)
&& Arrays.equals(keyPassword, that.keyPassword)
&& disableGRPCCompression == that.disableGRPCCompression
&& Objects.equals(interceptors, that.interceptors);
}
Expand All @@ -434,7 +516,9 @@ public int hashCode() {
database, writePrecision, gzipThreshold, writeNoSync, writeAcceptPartial, writeUseV2Api,
timeout, writeTimeout, queryTimeout, allowHttpRedirects, disableServerCertificateValidation,
proxy, proxyUrl, authenticator, headers,
defaultTags, sslRootsFilePath, disableGRPCCompression, interceptors);
defaultTags, sslRootsFilePath, Arrays.hashCode(sslRootFilePassword), certificatePath,
certificateKeyPath, certificateP12FilePath, Arrays.hashCode(keyPassword),
disableGRPCCompression, interceptors);
}

@Override
Expand All @@ -459,6 +543,11 @@ public String toString() {
.add("headers=" + headers)
.add("defaultTags=" + defaultTags)
.add("sslRootsFilePath=" + sslRootsFilePath)
.add("sslRootFilePassword=" + Arrays.toString(sslRootFilePassword))
.add("certificatePath=" + certificatePath)
.add("certificateKeyPath=" + certificateKeyPath)
.add("certificateP12FilePath=" + certificateP12FilePath)
.add("keyPassword=" + Arrays.toString(keyPassword))
.add("disableGRPCCompression=" + disableGRPCCompression)
.toString();
}
Expand Down Expand Up @@ -490,7 +579,15 @@ public static final class Builder {
private String proxyUrl;
private Authenticator authenticator;
private Map<String, String> headers;

private String certificatePath;
private String certificateKeyPath;
private String certificateP12FilePath;
private char[] keyPassword;

private String sslRootsFilePath;
private char[] sslRootFilePassword;

private boolean disableGRPCCompression;
private List<ClientInterceptor> interceptors;

Expand Down Expand Up @@ -805,6 +902,51 @@ public Builder sslRootsFilePath(@Nullable final String sslRootsFilePath) {
return this;
}

/**
* Sets certificate file password. Default is 'null'.
*
* @param sslRootFilePassword The certificate file password
* @return this
*/
@Nonnull
public Builder sslRootFilePassword(@Nullable final char[] sslRootFilePassword) {

this.sslRootFilePassword = sslRootFilePassword;
return this;
}

/**
* Sets the file paths for the certificate and its corresponding private key for secure connections.
*
* @param certificatePath the file path to the certificate file in PEM format, must not be null.
* @param certificateKeyPath the file path to the certificate's private key in PEM format, must not be null.
* @return this.
*/
@Nonnull
public Builder certificateFilePath(@Nonnull final String certificatePath,
@Nonnull final String certificateKeyPath) {
this.certificatePath = certificatePath;
this.certificateKeyPath = certificateKeyPath;

return this;
}

/**
* Sets the file paths for the certificate and in .p12 file format.
*
* @param certificateP12FilePath the file path to the certificate file in .p12 format, must not be null.
* @param password The certificate file password.
* @return this.
*/
@Nonnull
public Builder certificateP12FilePath(@Nonnull final String certificateP12FilePath,
@Nullable final char[] password) {
this.certificateP12FilePath = certificateP12FilePath;
this.keyPassword = password;

return this;
}

/**
* Sets whether to disable gRPC compression. Default is 'false'.
*
Expand Down Expand Up @@ -1023,6 +1165,11 @@ private ClientConfig(@Nonnull final Builder builder) {
authenticator = builder.authenticator;
headers = builder.headers;
sslRootsFilePath = builder.sslRootsFilePath;
sslRootFilePassword = builder.sslRootFilePassword;
certificatePath = builder.certificatePath;
certificateKeyPath = builder.certificateKeyPath;
certificateP12FilePath = builder.certificateP12FilePath;
keyPassword = builder.keyPassword;
disableGRPCCompression = builder.disableGRPCCompression;
interceptors = builder.interceptors;
}
Expand Down
Loading
Loading