#2 Option to provide trusted CA certificate

This commit is contained in:
2016-11-04 21:58:19 +01:00
parent 4adefc2cda
commit d2b31122b6
12 changed files with 435 additions and 59 deletions

View File

@ -30,10 +30,8 @@ import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import javax.net.ssl.*;
import java.io.*;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.*;
@ -65,11 +63,12 @@ public class HTTPVaultConnector implements VaultConnector {
private final ObjectMapper jsonMapper;
private final String baseURL; /* Base URL of Vault */
private final String baseURL; /* Base URL of Vault */
private final SSLContext sslContext; /* Custom SSLSocketFactory */
private boolean authorized = false; /* authorization status */
private String token; /* current token */
private long tokenTTL = 0; /* expiration time for current token */
private boolean authorized = false; /* authorization status */
private String token; /* current token */
private long tokenTTL = 0; /* expiration time for current token */
/**
* Create connector using hostname and schema.
@ -93,12 +92,12 @@ public class HTTPVaultConnector implements VaultConnector {
}
/**
* Create connector using hostname, schame, port and path.
* Create connector using hostname, schema, port and path.
*
* @param hostname The hostname
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
* @param port The port
* @param prefix HTTP API prefix (default: /v1/"
* @param prefix HTTP API prefix (default: /v1/)
*/
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix) {
this(((useTLS) ? "https" : "http") +
@ -107,13 +106,40 @@ public class HTTPVaultConnector implements VaultConnector {
prefix);
}
/**
* Create connector using hostname, schema, port, path and trusted certificate.
*
* @param hostname The hostname
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
* @param port The port
* @param prefix HTTP API prefix (default: /v1/)
* @param sslContext Custom SSL Context
*/
public HTTPVaultConnector(String hostname, boolean useTLS, Integer port, String prefix, SSLContext sslContext) {
this(((useTLS) ? "https" : "http") +
"://" + hostname +
((port != null) ? ":" + port : "") +
prefix,
sslContext);
}
/**
* Create connector using full URL.
*
* @param baseURL The URL
*/
public HTTPVaultConnector(String baseURL) {
this(baseURL, null);
}
/**
* Create connector using full URL and trusted certificate.
*
* @param baseURL The URL
*/
public HTTPVaultConnector(String baseURL, SSLContext sslContext) {
this.baseURL = baseURL;
this.sslContext = sslContext;
this.jsonMapper = new ObjectMapper();
}
@ -669,7 +695,7 @@ public class HTTPVaultConnector implements VaultConnector {
base.addHeader("accept", "application/json");
HttpResponse response = null;
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
try (CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(sslContext).build()) {
response = httpClient.execute(base);
/* Check if response is valid */
if (response == null)

View File

@ -0,0 +1,51 @@
/*
* Copyright 2016 Stefan Kalscheuer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.stklcode.jvault.connector.exception;
/**
* Exception thrown on errors with TLS connection.
*
* @author Stefan Kalscheuer
* @since 0.4.0
*/
public class TlsException extends VaultConnectorException {
private Integer statusCode;
private String response;
public TlsException() {
}
public TlsException(String message) {
super(message);
}
public TlsException(Throwable cause) {
super(cause);
}
public TlsException(String message, Throwable cause) {
super(message, cause);
}
public Integer getStatusCode() {
return statusCode;
}
public String getResponse() {
return response;
}
}

View File

@ -17,12 +17,26 @@
package de.stklcode.jvault.connector.factory;
import de.stklcode.jvault.connector.HTTPVaultConnector;
import de.stklcode.jvault.connector.exception.TlsException;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* Vault Connector Factory implementation for HTTP Vault connectors.
*
* @author Stefan Kalscheuer
* @since 0.1
* @author Stefan Kalscheuer
* @since 0.1
*/
public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
public static final String DEFAULT_HOST = "127.0.0.1";
@ -34,6 +48,7 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
private Integer port;
private boolean tls;
private String prefix;
private SSLContext sslContext;
/**
* Default empty constructor.
@ -48,8 +63,9 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
/**
* Set hostname (default: 127.0.0.1)
* @param host Hostname or IP address
* @return self
*
* @param host Hostname or IP address
* @return self
*/
public HTTPVaultConnectorFactory withHost(String host) {
this.host = host;
@ -58,8 +74,9 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
/**
* Set port (default: 8200)
* @param port Vault TCP port
* @return self
*
* @param port Vault TCP port
* @return self
*/
public HTTPVaultConnectorFactory withPort(Integer port) {
this.port = port;
@ -68,8 +85,9 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
/**
* Set TLS usage (default: TRUE)
* @param useTLS use TLS or not
* @return self
*
* @param useTLS use TLS or not
* @return self
*/
public HTTPVaultConnectorFactory withTLS(boolean useTLS) {
this.tls = useTLS;
@ -78,7 +96,8 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
/**
* Convenience Method for TLS usage (enabled by default)
* @return self
*
* @return self
*/
public HTTPVaultConnectorFactory withTLS() {
return withTLS(true);
@ -86,7 +105,8 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
/**
* Convenience Method for NOT using TLS
* @return self
*
* @return self
*/
public HTTPVaultConnectorFactory withoutTLS() {
return withTLS(false);
@ -94,16 +114,98 @@ public class HTTPVaultConnectorFactory extends VaultConnectorFactory {
/**
* Set API prefix. Default is "/v1/" and changes should not be necessary for current state of development.
* @param prefix Vault API prefix (default: "/v1/"
* @return self
*
* @param prefix Vault API prefix (default: "/v1/"
* @return self
*/
public HTTPVaultConnectorFactory withPrefix(String prefix) {
this.prefix = prefix;
return this;
}
/**
* Add a trusted CA certifiate for HTTPS connections.
*
* @param cert path to certificate file
* @return self
* @since 0.4.0
*/
public HTTPVaultConnectorFactory withTrustedCA(Path cert) throws VaultConnectorException {
return withSslContext(createSslContext(cert));
}
/**
* Add a custom SSL context.
* Overwrites certificates set by {@link #withTrustedCA}.
*
* @param sslContext the SSL context
* @return self
* @since 0.4.0
*/
public HTTPVaultConnectorFactory withSslContext(SSLContext sslContext) {
this.sslContext = sslContext;
return this;
}
@Override
public HTTPVaultConnector build() {
return new HTTPVaultConnector(host, tls, port, prefix);
return new HTTPVaultConnector(host, tls, port, prefix, sslContext);
}
/**
* Create SSL Context trusting only provided certificate.
*
* @param trustedCert Path to trusted CA certificate
* @return SSL context
* @throws TlsException on errors
* @since 0.4.0
*/
private SSLContext createSslContext(Path trustedCert) throws TlsException {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, createTrustManager(trustedCert), new SecureRandom());
return context;
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new TlsException("Unable to intialize SSLContext", e);
}
}
/**
* Create a custom TrustManager for given CA certificate file.
*
* @param trustedCert Path to trusted CA certificate
* @return TrustManger
* @throws TlsException on error
* @since 0.4.0
*/
private TrustManager[] createTrustManager(Path trustedCert) throws TlsException {
try {
/* Create Keystore with trusted certificate */
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("trustedCert", certificateFromFile(trustedCert));
/* Initialize TrustManager */
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
return tmf.getTrustManagers();
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
throw new TlsException("Unable to initialize TrustManager", e);
}
}
/**
* Read given certificate file to X.509 certificate.
*
* @param certFile Path to certificate file
* @return X.509 Certificate object
* @throws TlsException on error
* @since 0.4.0
*/
private X509Certificate certificateFromFile(Path certFile) throws TlsException {
try (InputStream is = Files.newInputStream(certFile)) {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
} catch (IOException | CertificateException e) {
throw new TlsException("Unable to read certificate.", e);
}
}
}

View File

@ -17,6 +17,7 @@
package de.stklcode.jvault.connector.factory;
import de.stklcode.jvault.connector.VaultConnector;
import de.stklcode.jvault.connector.exception.VaultConnectorException;
/**
* Abstract Vault Connector Factory interface.