Skip to content
Draft
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## 8.1.0 [unreleased]

### Features

- [#948](https://github.com/influxdata/influxdb-client-java/pull/948): Support TLS and mTls configurations.

### Dependencies

Update dependencies:
Expand Down
38 changes: 19 additions & 19 deletions client-core/src/test/java/com/influxdb/internal/RestClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,25 @@
import java.util.concurrent.CountDownLatch;
import javax.annotation.Nonnull;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okhttp3.mockwebserver.MockResponse;
import okio.Buffer;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.Path;

import com.influxdb.LogLevel;
import com.influxdb.exceptions.BadGatewayException;
import com.influxdb.exceptions.BadRequestException;
Expand All @@ -46,25 +65,6 @@
import com.influxdb.exceptions.UnprocessableEntityException;
import com.influxdb.test.AbstractMockServerTest;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okhttp3.mockwebserver.MockResponse;
import okio.Buffer;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.Path;

/**
* @author Jakub Bednar (bednar@github) (04/10/2018 07:57)
*/
Expand Down
178 changes: 178 additions & 0 deletions client-utils/src/main/java/com/influxdb/utils/TlsUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* 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.utils;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public final class TlsUtils {
private static final String TLS = "TLS";
private static final char[] DEFAULT_PASSWORD_CHAR_ARRAY = "".toCharArray();
private static final String X509 = "X.509";
private static final String PKCS12 = "PKCS12";

private TlsUtils() {
}

@Nullable
public static SSLContext buildSslContext(@Nullable final KeyManagerFactory kmf,
@Nullable final TrustManagerFactory tmf) throws Exception {
if (kmf == null && tmf == null) {
return null;
}

SSLContext sslContext = SSLContext.getInstance(TLS);
var trustManagers = tmf != null ? tmf.getTrustManagers() : null;
var keyManagers = kmf != null ? kmf.getKeyManagers() : null;
sslContext.init(keyManagers, trustManagers, null);
return sslContext;
}

@Nonnull
public static X509TrustManager getX509TrustManager(@Nullable final TrustManagerFactory tmf) throws Exception {
TrustManagerFactory factory = tmf;
if (factory == null) {
factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init((KeyStore) null);
}
return (X509TrustManager) factory.getTrustManagers()[0];
}

public static X509Certificate loadCertificate(@Nonnull final String path) throws Exception {
byte[] encoded = Files.readAllBytes(Paths.get(path));
return (X509Certificate) CertificateFactory.getInstance(X509)
.generateCertificate(new ByteArrayInputStream(encoded));
}

public static PrivateKey loadPrivateKey(@Nonnull final String path) throws Exception {
String keyPem = Files.readString(Paths.get(path));
if (keyPem.contains("-----BEGIN ENCRYPTED PRIVATE KEY-----")) {
throw new IllegalArgumentException("Encrypted PKCS#8 private keys are not supported. Use an unencrypted "
+ "PKCS#8 key or a PKCS#12 file.");
}

String privateKeyPEM = keyPem
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");

byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
for (String algorithm : new String[]{"RSA", "EC", "DSA"}) {
try {
return KeyFactory.getInstance(algorithm).generatePrivate(keySpec);
} catch (java.security.spec.InvalidKeySpecException ignored) {
}
}

throw new GeneralSecurityException("Unsupported private key algorithm");
}

public static KeyManagerFactory createKmfP12(@Nonnull final String path,
@Nullable final char[] password) throws Exception {
char[] pass = password != null && password.length > 0 ? password : DEFAULT_PASSWORD_CHAR_ARRAY;

KeyStore keyStore = KeyStore.getInstance(PKCS12);
try (FileInputStream fis = new FileInputStream(path)) {
keyStore.load(fis, pass);
}

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, pass);
return kmf;
}

public static KeyManagerFactory createKmf(@Nonnull final String certPath,
@Nonnull final String keyPath) throws Exception {
X509Certificate certificate = TlsUtils.loadCertificate(certPath);
PrivateKey privateKey = TlsUtils.loadPrivateKey(keyPath);
Comment thread
NguyenHoangSon96 marked this conversation as resolved.

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);

keyStore.setKeyEntry("alias", privateKey, null, new Certificate[]{certificate});
Comment on lines +124 to +130

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, null);

return kmf;
}

// For .p12 only
public static TrustManagerFactory createTmfP12(@Nonnull final String path,
@Nullable final char[] password) throws Exception {
char[] pass = password != null && password.length > 0 ? password : DEFAULT_PASSWORD_CHAR_ARRAY;

KeyStore trustStore = KeyStore.getInstance("PKCS12");
try (FileInputStream fis = new FileInputStream(path)) {
trustStore.load(fis, pass);
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);

return tmf;
}

public static TrustManagerFactory createTmf(@Nonnull final String path,
@Nullable final char[] password) throws Exception {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

String extension = path.toLowerCase(Locale.ROOT);

if (extension.endsWith(".p12") || extension.endsWith(".pfx")) {
char[] pass = password != null && password.length > 0 ? password : DEFAULT_PASSWORD_CHAR_ARRAY;
tmf = createTmfP12(path, pass);
} else if (extension.endsWith(".crt") || extension.endsWith(".cert") || extension.endsWith(".pem")) {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);

CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
try (FileInputStream fis = new FileInputStream(path)) {
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(fis);
trustStore.setCertificateEntry("alias", cert);
}
Comment on lines +166 to +170
tmf.init(trustStore);
} else {
throw new IllegalArgumentException("Unsupported certificate format");
}

return tmf;
}
}
Loading
Loading