Install with Maven
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart</artifactId>
<version>7.0.3</version>
</dependency>
implementation 'io.github.hakky54:sslcontext-kickstart:7.0.3'
implementation("io.github.hakky54:sslcontext-kickstart:7.0.3")
libraryDependencies += "io.github.hakky54" % "sslcontext-kickstart" % "7.0.3"
<dependency org="io.github.hakky54" name="sslcontext-kickstart" rev="7.0.3" />
- Introduction
- Usage
- Example configuration
- Other possible configurations
- Loading keystore from the classpath
- Loading keystore from the file system
- Loading keystore from InputStream
- Loading trust material with OCSP options
- Skip certificate validation
- Skip hostname validation
- Loading JDK and OS trusted certificates
- Using specific protocols and ciphers with custom secure-random and hostname-verifier
- Using multiple identity materials and trust materials
- Using custom KeyManager and TrustManager
- Hot swap KeyManager and TrustManager at runtime
- Using KeyStore with multiple keys having different passwords
- Using custom PrivateKey and Certificates
- Routing client identity to specific host
- Updating client identity routes at runtime
- Managing ssl session
- Extracting server certificates
- Using P7B or PKCS#7 files
- Using DER files
- Using PFX or P12 or PKCS#12 Files
- Using PEM Files
- Migrating from classic configuration
- Returnable values from the SSLFactory
- Additional mappers for specific libraries
- Tested HTTP Clients
- Contributing
- Contributors
- License
Hey, hello there 👋 Welcome, you are I hope you will like this library ❤️
SSLContext Kickstart is a library which provides a High-Level SSLFactory class for configuring a http client to communicate over SSL/TLS for one way authentication or two-way authentication. It is designed to be as lightweight as possible by having minimized the external dependencies. The core library only depends on the SLF4J logging API.
As a Java developer I worked for different kinds of clients. Most of the time the application required to call other microservices within the organization or some other http servers. These requests needed to be secured and therefore it was required to load the ssl materials into the http client. Each client may require different input value to enable https requests and therefore I couldn't just copy-paste my earlier configuration into the new project. The resulting configuration was in my opinion always verbose, not reusable, hard to test and hard to maintain.
As a developer you also need to know how to properly load your file into your application and consume it as a KeyStore instance. Therefore, you also need to understand how to properly create for example a KeyManager and a TrustManager for you SSLContext. An alternative for the traditional creation of SSLContext can be simplified if you use a Http Client which relies on libraries of Jetty, Netty or Apache. If you use other clients than you are out of luck. The sslcontext-kickstart library is taking the responsibility of creating an instance of SSLContext from the provided arguments, and it will provide you all the ssl materials which are required to configure 40+ different Http Client for Java, Scala and Kotlin. I wanted the library to be as easy as possible to use for all developers to give them a kickstart when configuring their Http Client. So feel free to provide feedback or feature requests. The library also provides other utilities such as:
- CertificateUtils
- HostnameVerifierUtils
- KeyStoreUtils
- KeyManagerUtils
- TrustManagerUtils
- PemUtils
- SSLContextUtils
- SSLSessionUtils
- SSLSocketUtils
See the javadoc for all the options.
I would like to thank Cody A. Ray for his contribution to the community regarding loading multiple Keystores into the SSLContext. The limitation of the JDK is to only support one keystore for the KeyManagerFactory and only one keystore for the TrustManagerFactory. The code snippets which Cody has shared are now available within this library and can be found here: CompositeX509KeyManager and CompositeX509TrustManager
The original content can be found here:
- No need for low-level SSLContext configuration anymore
- No knowledge needed about SSLContext, TrustManager, TrustManagerFactory, KeyManager, KeyManagerFactory and how to create it.
- Above classes will all be created with just providing an identity and a trustStore
- Load multiple identities/trustStores/keyManagers/trustManagers
- Identity: A KeyStore which holds the key pair also known as private and public key
- TrustStore: A KeyStore containing one or more certificates also known as public key. This KeyStore contains a list of trusted certificates
- One way authentication (also known as one way tls, one way ssl): Https connection where the client validates the certificate of the counter party
- Two way authentication (also known as two way tls, two way ssl, mutual authentication): Https connection where the client as well as the counter party validates the certificate, also known as mutual authentication
Example configuration with apache http client, or click here to view the other client configurations
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import nl.altindag.ssl.SSLFactory;
public class App {
public static void main(String[] args) throws IOException, JSONException {
SSLFactory sslFactory = SSLFactory.builder()
.withDefaultTrustMaterial()
.build();
HttpClient httpClient = HttpClients.custom()
.setSSLContext(sslFactory.getSslContext())
.setSSLHostnameVerifier(sslFactory.getHostnameVerifier())
.build();
HttpGet request = new HttpGet("https://api.chucknorris.io/jokes/random");
HttpResponse response = httpClient.execute(request);
String chuckNorrisJoke = new JSONObject(EntityUtils.toString(response.getEntity())).getString("value");
System.out.println(String.format("Received the following status code: %d", response.getStatusLine().getStatusCode()));
System.out.println(String.format("Received the following joke: %s", chuckNorrisJoke));
}
}
Response:
Received the following status code: 200
Received the following joke: If a black cat crosses your path, you have bad luck. If Chuck Norris crosses your path, it was nice knowing you.
SSLFactory.builder()
.withIdentityMaterial("identity.jks", "password".toCharArray())
.withTrustMaterial("truststore.jks", "password".toCharArray())
.build();
SSLFactory.builder()
.withIdentityMaterial(Paths.get("/path/to/your/identity.jks"), "password".toCharArray())
.withTrustMaterial(Paths.get("/path/to/your/truststore.jks"), "password".toCharArray())
.build();
InputStream keyStoreStream = ...
InputStream trustStoreStream = ...
SSLFactory.builder()
.withIdentityMaterial(keyStoreStream, "password".toCharArray())
.withTrustMaterial(trustStoreStream, "password".toCharArray())
.build();
CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
revocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.NO_FALLBACK));
SSLFactory sslFactory = SSLFactory.builder()
.withTrustMaterial("truststore.jks", "password".toCharArray(), trustStore -> {
PKIXBuilderParameters pkixBuilderParameters = new PKIXBuilderParameters(trustStore, new X509CertSelector());
pkixBuilderParameters.addCertPathChecker(revocationChecker);
return new CertPathTrustManagerParameters(pkixBuilderParameters);
})
.build();
X509ExtendedTrustManager trustManager = ...
CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
revocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.NO_FALLBACK));
SSLFactory sslFactory = SSLFactory.builder()
.withTrustMaterial(trustManager, trustStore -> {
PKIXBuilderParameters pkixBuilderParameters = new PKIXBuilderParameters(trustStore, new X509CertSelector());
pkixBuilderParameters.addCertPathChecker(revocationChecker);
return new CertPathTrustManagerParameters(pkixBuilderParameters);
})
.build();
List<Certificate> certificates = ...
CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
revocationChecker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.NO_FALLBACK));
SSLFactory sslFactory = SSLFactory.builder()
.withTrustMaterial(certificates, trustStore -> {
PKIXBuilderParameters pkixBuilderParameters = new PKIXBuilderParameters(trustStore, new X509CertSelector());
pkixBuilderParameters.addCertPathChecker(revocationChecker);
return new CertPathTrustManagerParameters(pkixBuilderParameters);
})
.build();
SSLFactory.builder()
.withUnsafeTrustMaterial()
.build();
SSLFactory.builder()
.withDefaultTrustMaterial()
.withUnsafeHostnameVerifier()
.build();
SSLFactory.builder()
.withDefaultTrustMaterial()
.withSystemTrustMaterial()
.build();
If you are using java 11 or newer, than you are also able to use TLSv1.3 as encryption protocol by default.
SSLFactory.builder()
.withDefaultTrustMaterial()
.withProtocols("TLSv1.3", "TLSv1.2")
.withCiphers("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384")
.withHostnameVerifier(hostnameVerifier)
.withSecureRandom(secureRandom)
.build();
SSLFactory.builder()
.withIdentityMaterial("identity-1.jks", password)
.withIdentityMaterial("identity-2.jks", password)
.withIdentityMaterial("identity-3.jks", password)
.withIdentityMaterial("identity-4.jks", password)
.withTrustMaterial("truststore-1.jks", password)
.withTrustMaterial("truststore-2.jks", password)
.withTrustMaterial("truststore-3.jks", password)
.withTrustMaterial("truststore-4.jks", password)
.build();
In some use cases multiple identities can fail to work. If that happens please try to add the additional SSLFactory option of client identity route. See here for more: Routing client identity to specific host
X509ExtendedKeyManager keyManager = ...
X509ExtendedTrustManager trustManager = ...
SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withTrustMaterial(trustManager)
.build();
It is possible to swap a KeyManager and TrustManager from a SSLContext, SSLSocketFactory and SSLServerSocketFactory while already using it within your client or server at runtime. This option will enable to refresh the identity and trust material of a server or client without the need of restarting your application or recreating it with SSLFactory. The identity and trust material may expire at some point in time and needs to be replaced to be still functional. Restart of the application with a traditional setup is unavoidable and can result into a downtime for x amount of time. A restart is not needed when using the setup below.
SSLFactory sslFactory = SSLFactory.builder()
.withSwappableIdentityMaterial()
.withIdentityMaterial("identity.jks", "password".toCharArray())
.withSwappableTrustMaterial()
.withTrustMaterial("truststore.jks", "password".toCharArray())
.build();
HttpClient httpClient = HttpClient.newBuilder()
.sslParameters(sslFactory.getSslParameters())
.sslContext(sslFactory.getSslContext())
.build()
// execute https request
HttpResponse<String> response = httpClient.send(aRequest, HttpResponse.BodyHandlers.ofString());
// swap identity and trust materials and reuse existing http client
KeyManagerUtils.swapKeyManager(sslFactory.getKeyManager().get(), anotherKeyManager);
TrustManagerUtils.swapTrustManager(sslFactory.getTrustManager().get(), anotherTrustManager);
// Cleanup old ssl sessions by invalidating them all. Forces to use new ssl sessions which will be created by the swapped KeyManager/TrustManager
SSLSessionUtils.invalidateCaches(sslFactory.getSslContext());
HttpResponse<String> response = httpClient.send(aRequest, HttpResponse.BodyHandlers.ofString());
See here for a basic reference implementation for a server: GitHub - Instant SSL Reloading
KeyStore keyStore = ...
X509ExtendedKeyManager keyManager = KeyManagerUtils.createKeyManager(keyStore, Map.of(
"foo","foo-password".toCharArray(),
"bar","bar-password".toCharArray(),
"lorum-ipsum","lorum-ipsum-password".toCharArray()
));
SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withDefaultTrustMaterial()
.build();
PrivateKey privateKey = ...
char[] privateKeyPassword = ...
Certificate[] certificateChain = ...
Certificate trustedCertificate = ...
SSLFactory.builder()
.withIdentityMaterial(privateKey, privateKeyPassword, certificateChain)
.withTrustMaterial(trustedCertificate)
.build();
It may occur that the client is sending the wrong certificate to the server when using multiple identities. This will happen when the client certificate has insufficient information for the underlying ssl engine (the KeyManager) and therefore it cannot select the right certificate. Recreating the certificates can resolve this issue. However, if that is not possible you can provide an option to the engine to use a specific certificate for a given server. Below is an example setup for correctly routing the client identity based on the alias which can be found within the KeyStore file.
SSLFactory.builder()
.withIdentityMaterial("identity-1.jks", password)
.withIdentityMaterial("identity-2.jks", password)
.withTrustMaterial("truststore.jks", password)
.withClientIdentityRoute("client-alias-one", "https://localhost:8443/", "https://localhost:8453/")
.withClientIdentityRoute("client-alias-two", "https://localhost:8463/", "https://localhost:8473/")
.build();
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial("identity-1.jks", password)
.withIdentityMaterial("identity-2.jks", password)
.withTrustMaterial("truststore.jks", password)
.withClientIdentityRoute("client-alias-one", "https://localhost:8443/", "https://localhost:8453/")
.withClientIdentityRoute("client-alias-two", "https://localhost:8463/", "https://localhost:8473/")
.build();
X509ExtendedKeyManager keyManager = sslFactory.getKeyManager().get()
// Add additional routes next to the existing ones
KeyManagerUtils.addClientIdentityRoute(keyManager, "client-alias-one", "https://localhost:8463/", "https://localhost:8473/")
// Override existing routes
KeyManagerUtils.overrideClientIdentityRoute(keyManager, "client-alias-two", "https://localhost:9463/", "https://localhost:9473/")
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial("identity.jks", "password".toCharArray())
.withTrustMaterial("truststore.jks", "password".toCharArray())
.withSessionTimeout(3600) // Amount of seconds until it will be invalidated
.withSessionCacheSize(1024) // Amount of bytes until it will be invalidated
.build();
SSLContext sslContext = sslFactory.getSslContext();
// Caches can be invalidated with the snippet below
SSLSessionUtils.invalidateCaches(sslContext);
// or any other option:
SSLSessionUtils.invalidateCachesBefore(
sslContext,
ZonedDateTime.of(LocalDateTime.of(2021, JANUARY, 1, 15, 55), ZoneOffset.UTC)
);
SSLSessionUtils.invalidateCachesAfter(
sslContext,
ZonedDateTime.of(LocalDateTime.of(2021, FEBRUARY, 10, 8, 14), ZoneOffset.UTC)
);
SSLSessionUtils.invalidateCachesBetween(
sslContext,
ZonedDateTime.now().minusHours(2), // from
ZonedDateTime.now() // up till
);
Map<String, List<Certificate>> certificates = CertificateUtils.getCertificate(
"https://github.com/",
"https://stackoverflow.com/",
"https://www.reddit.com/",
"https://www.youtube.com/");
// or get the server certificates as pem format
Map<String, List<String>> certificatesAsPem = CertificateUtils.getCertificateAsPem(
"https://github.com/",
"https://stackoverflow.com/",
"https://www.reddit.com/",
"https://www.youtube.com/");
See here for a demo application: GitHub - Certificate Ripper
Support for using p7b formatted certificates and certificate-chain from classpath, any directory or as an InputStream.
P7b file is a text file containing a -----BEGIN PKCS7-----
as header, -----END PKCS7-----
as footer and has a Base64 encoded data between it.
List<Certificate> certificates = CertificateUtils.loadCertificate("certificate.p7b");
SSLFactory.builder()
.withTrustMaterial(certificates)
.build();
Support for using der formatted certificates and certificate-chain from classpath, any directory or as an InputStream.
Der file is a binary form of a certificate. Commonly used extensions are .cer
and crt
.
List<Certificate> certificates = CertificateUtils.loadCertificate("certificate.cer");
SSLFactory.builder()
.withTrustMaterial(certificates)
.build();
PFX and p12 are both PKCS#12 type keystores which are supported.
SSLFactory.builder()
.withIdentityMaterial("identity.p12", "password".toCharArray())
.withTrustMaterial("truststore.p12", "password".toCharArray())
.build();
Support for using pem formatted private key and certificates from classpath, any directory or as an InputStream. See PemUtilsShould for detailed usages. Add the dependency below to use this feature, it also includes the core features from the library such as SSLFactory.
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-pem</artifactId>
<version>7.0.3</version>
</dependency>
X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial("certificate.pem", "private-key.pem");
X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial("some-trusted-certificate.pem");
SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withTrustMaterial(trustManager)
.build();
X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial(Paths.get("/path/to/your/certificate.pem"), Paths.get("/path/to/your/"private-key.pem"));
X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(Paths.get("/path/to/your/"some-trusted-certificate.pem"));
InputStream privateKey = ...
InputStream certificate = ...
InputStream trustedCertificates = ...
X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial(certificate, privateKey);
X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial(trustedCertificates);
String privateKey =
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n" +
"MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIy3Fposf+2ccCAggA\n" +
"-----END ENCRYPTED PRIVATE KEY-----\n";
String certificate =
"-----BEGIN CERTIFICATE-----\n" +
"g0Y2YBH5v0xmi8sYU7weOcwynkjZARpUltBUQ0pWCF5uJsEB8uE8PPDD3c4=\n" +
"-----END CERTIFICATE-----\n";
String trustedCertificates =
"-----BEGIN CERTIFICATE-----\n" +
"CC01zojqS10nGowxzOiqyB4m6wytmzf0QwjpMw==\n" +
"-----END CERTIFICATE-----\n";
X509ExtendedKeyManager keyManager = PemUtils.parseIdentityMaterial(certificate, privateKey, "secret".toCharArray());
X509ExtendedTrustManager trustManager = PemUtils.parseTrustMaterial(trustedCertificates);
X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial("certificate.pem", "private-key.pem", "secret".toCharArray());
Below is an example of the classic configuration for enabling ssl for your application.
-Djavax.net.ssl.trustStore=/path/to/truststore.jks
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.trustStorePassword=changeit
-Djavax.net.ssl.keyStore=/path/to/keystore.jks
-Djavax.net.ssl.keyStoreType=jks
-Djavax.net.ssl.keyStorePassword=changeit
-Djdk.tls.client.protocols=TLSv1.3
-Dhttps.protocols=TLSv1.3
SSLFactory can be used with these properties together with the existing properties with the following snippet:
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial(Paths.get(System.getProperty("javax.net.ssl.keyStore")), System.getProperty("javax.net.ssl.keyStorePassword").toCharArray(), System.getProperty("javax.net.ssl.keyStoreType"))
.withTrustMaterial(Paths.get(System.getProperty("javax.net.ssl.trustStore")), System.getProperty("javax.net.ssl.trustStorePassword").toCharArray(), System.getProperty("javax.net.ssl.trustStoreType"))
.withProtocols(System.getProperty("jdk.tls.client.protocols"))
.build();
SSLContext.setDefault(sslFactory.getSslContext());
Or it can be refactored to the configuration below:
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial(Paths.get("/path/to/keystore.jks"), "changeit".toCharArray(), "jks")
.withTrustMaterial(Paths.get("/path/to/truststore.jks"), "changeit".toCharArray(), "jks")
.withProtocols("TLSv1.3")
.build();
The SSLFactory returnable values can be supplied to the http client as shown here
The SSLFactory provides different kinds of returnable values, see below for all the options:
import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.model.KeyStoreHolder;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509ExtendedTrustManager;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Optional;
public class App {
public static void main(String[] args) {
SSLFactory sslFactory = SSLFactory.builder()
.withIdentityMaterial("keystore.p12", "secret".toCharArray(), "PKCS12")
.withTrustMaterial("truststore.p12", "secret".toCharArray(), "PKCS12")
.build();
SSLContext sslContext = sslFactory.getSslContext();
HostnameVerifier hostnameVerifier = sslFactory.getHostnameVerifier();
Optional<X509ExtendedKeyManager> keyManager = sslFactory.getKeyManager();
Optional<X509ExtendedTrustManager> trustManager = sslFactory.getTrustManager();
Optional<KeyManagerFactory> keyManagerFactory = sslFactory.getKeyManagerFactory();
Optional<TrustManagerFactory> trustManagerFactory = sslFactory.getTrustManagerFactory();
List<X509Certificate> trustedCertificates = sslFactory.getTrustedCertificates();
SSLSocketFactory sslSocketFactory = sslFactory.getSslSocketFactory();
SSLServerSocketFactory sslServerSocketFactory = sslFactory.getSslServerSocketFactory();
SSLEngine sslEngine = sslFactory.getSslEngine(host, port);
SSLParameters sslParameters = sslFactory.getSslParameters();
List<String> ciphers = sslFactory.getCiphers();
List<String> protocols = sslFactory.getProtocols();
}
}
Some http clients relay on different ssl classes from third parties and require mapping from SSLFactory to those libraries. Below you will find the maven dependency which will provide the mapping and also the SSLFactory library. When using one of the below libraries, it is not required to also explicitly include sslcontext-kickstart into your project. The additional mappers for specific libraries below won't provide transitive dependencies on Netty, Jetty or Apache. This has been decided to prevent dependency hell on your side.
Some know http clients which relay on netty libraries are: Spring WebFlux WebClient Netty, Async Http Client and Dispatch Reboot Http Client.
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-netty</artifactId>
<version>7.0.3</version>
</dependency>
Example setup for Spring WebClient with Netty:
import io.netty.handler.ssl.SslContext;
import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.util.NettySslUtils;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import javax.net.ssl.SSLException;
public class App {
public static void main(String[] args) throws SSLException {
SSLFactory sslFactory = SSLFactory.builder()
.withDefaultTrustMaterial()
.build();
SslContext sslContext = NettySslUtils.forClient(sslFactory).build();
HttpClient httpClient = HttpClient.create()
.secure(sslSpec -> sslSpec.sslContext(sslContext));
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
}
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-jetty</artifactId>
<version>7.0.3</version>
</dependency>
Example setup for Spring WebFlux WebClient Jetty:
import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.util.JettySslUtils;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.springframework.http.client.reactive.JettyClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
public class App {
public static void main(String[] args) {
SSLFactory sslFactory = SSLFactory.builder()
.withDefaultTrustMaterial()
.build();
SslContextFactory.Client sslContextFactory = JettySslUtils.forClient(sslFactory);
HttpClient httpClient = new HttpClient(sslContextFactory);
WebClient webClient = WebClient.builder()
.clientConnector(new JettyClientHttpConnector(httpClient))
.build();
}
}
Apache Http Client works with javax.net.ssl.SSLContext, so an additional mapping to their library is not required, see here. However it is still possible to configure the http client with their custom configuration class. you can find below an example configuration for that use case:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-apache4</artifactId>
<version>7.0.3</version>
</dependency>
import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.util.Apache4SslUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.impl.client.HttpClients;
public class App {
public static void main(String[] args) {
SSLFactory sslFactory = SSLFactory.builder()
.withDefaultTrustMaterial()
.build();
LayeredConnectionSocketFactory socketFactory = Apache4SslUtils.toSocketFactory(sslFactory);
HttpClient httpClient = HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
}
}
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-apache5</artifactId>
<version>7.0.3</version>
</dependency>
import nl.altindag.ssl.SSLFactory;
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
import nl.altindag.ssl.util.Apache5SslUtils;
class App {
public static void main(String[] args) {
SSLFactory sslFactory = SSLFactory.builder()
.withDefaultTrustMaterial()
.build();
LayeredConnectionSocketFactory socketFactory = Apache5SslUtils.toSocketFactory(sslFactory);
PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(socketFactory)
.build();
HttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
PoolingAsyncClientConnectionManager asyncConnectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
.setTlsStrategy(Apache5SslUtils.toTlsStrategy(sslFactory))
.build();
CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.custom()
.setConnectionManager(asyncConnectionManager)
.build();
}
}
Below is a list of clients which have already been tested with examples, see in the ClientConfig class and the service directory for detailed configuration
Java
- Apache HttpClient -> Client configuration | Example request
- Apache HttpAsyncClient -> Client configuration | Example request
- Apache 5 HttpClient -> Client configuration | Example request
- Apache 5 HttpAsyncClient -> Client configuration | Example request
- JDK HttpClient -> Client Configuration | Example request
- Old JDK HttpClient -> Client Configuration & Example request
- Netty Reactor -> Client Configuration | Example request
- Jetty Reactive HttpClient -> Client Configuration | Example request
- Spring RestTemplate -> Client Configuration | Example request
- Spring WebFlux WebClient Netty -> Client Configuration | Example request
- Spring WebFlux WebClient Jetty -> Client Configuration | Example request
- OkHttp -> Client Configuration | Example request
- Jersey Client -> Client Configuration | Example request
- Old Jersey Client -> Client Configuration | Example request
- Apache CXF JAX-RS -> Client Configuration | Example request
- Apache CXF using ConduitConfigurer -> Client Configuration | Example request
- Google HttpClient -> Client Configuration | Example request
- Unirest -> Client Configuration | Example request
- Retrofit -> Client Configuration | Example request
- Async Http Client -> Client Configuration | Example request
- Feign -> Client Configuration | Example request
- Methanol -> Client Configuration | Example request
- Vertx Webclient -> Client Configuration | Example request
- gRPC -> Client/Server Configuration & Example request
- ElasticSearch -> RestHighLevelClient Configuration & example request
- Jetty WebSocket -> Client configuration & example request
Kotlin
- Fuel -> Client Configuration & Example request
- Http4k with Apache 4 -> Client Configuration | Example request
- Http4k with Async Apache 4 -> Client Configuration | Example request
- Http4k with Apache 5 -> Client Configuration | Example request
- Http4k with Async Apache 5 -> Client Configuration | Example request
- Http4k with Java Net -> Client Configuration | Example request
- Http4k with Jetty -> Client Configuration | Example request
- Http4k with OkHttp -> Client Configuration | Example request
- Kohttp -> Client Configuration & Example request
- Ktor with Android engine -> Client Configuration | Example request
- Ktor with Apache engine -> Client Configuration | Example request
- Ktor with CIO (Coroutine-based I/O) engine -> Client Configuration | Example request
- Ktor with Okhttp engine -> Client Configuration | Example request
Scala
- Twitter Finagle -> Client Configuration | Example request
- Twitter Finagle Featherbed -> Client Configuration & Example request
- Akka Http Client -> Client Configuration | Example request
- Dispatch Reboot -> Client Configuration & Example request
- ScalaJ / Simplified Http Client -> Client Configuration & Example request
- Sttp -> Client Configuration & Example request
- Requests-Scala -> Client Configuration & Example request
- Http4s Blaze Client -> Client Configuration | Example request
- Http4s Java Net Client -> Client Configuration | Example request
There is a github project available named Mutual-tls-ssl which provides a tutorial containing steps for setting up these four scenarios:
- No security
- One way authentication
- Two way authentication
- Two way authentication with trusting the Certificate Authority
It will also explain how to create KeyStores, Certificates, Certificate Signing Requests and how to implement it.
There are plenty of ways to contribute to this project:
- Give it a star
- Share it with a
- Join the Gitter room and leave a feedback or help with answering users questions
- Submit a PR
Thanks goes to these wonderful people (emoji key):
Laurynas 💻 🚧 |
Philippe Charles 🤔 |
Tadhg Pearson 🐛 |
winster 🤔 |
Pablo Lalloni 🤔 |
Luis Miguel Ospina 🐛 |
Jérémie Panzer 🤔 |
patpatpat123 🤔 🐛 |
Cody A. Ray 💻 |
This project follows the all-contributors specification. Contributions of any kind welcome!