HTTP/2 and TLS in Helidon

Santiago Pericas-Geertsen
Helidon
Published in
3 min readOct 21, 2019

In an earlier story, I talked about how to enable HTTP/2 in Helidon. In today’s story we shall focus on how to do so together with Transport Layer Security (TLS) and its Application-Layer Protocol Negotiation (ALPN) extension. TLS is the successor of the Secure Socket Layer (SSL) protocol and, consequently, the two acronyms are at times used interchangeably.

Unfortunately, some older JDKs do not have the built-in support required to use TLS with ALPN: namely, JDK 8 requires an external (bootclasspath) library for ALPN and JDK 9 has support but only for TLS 1.2. The more desirable (and secure) version 1.3 of TLS is available in JDK 11 only. Thus, without additional libraries are installed, enabling HTTP/2 with TLS in Helidon requires at least JDK 9.

Configuration

The first step in setting up HTTP/2 with TLS is in your application’s configuration. In addition to enabling experimental support HTTP/2, a private key needs to be specified for TLS to secure connections:

server:
port: 8080
host: 0.0.0.0
ssl:
private-key:
keystore-resource-path: "certificate.p12"
keystore-passphrase: "helidon"
experimental:
http2:
enable: true
max-content-length: 16384

In this example, certificate.p12 is defined as a resource path and will normally be located alongside your application.yaml file. The passphrase is a requirement for the server to access the certificate.

The YAML file shown above is part of the bookstore-se application in the Helidon’s workspace under tests/apps/booskstore/bookstore-se. The reader is referred to that location for additional information.

Testing the Application

Testing your application requires a TLS and ALPN compatible client. Most modern Web browsers support these protocols and, in fact, do not support HTTP/2 without TLS. In what follows, we shall use the OkHttp client library version 3.14.1.

The creation of a new OkHttp client instance requires some initial setup as follows:

private static X509TrustManager TRUST_MANAGER = 
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) { }
public void checkServerTrusted(X509Certificate[] certs,
String authType) { }
};
OkHttpClient newOkHttpClient() throws Exception {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.addNetworkInterceptor(new LoggingInterceptor())
.protocols(Arrays.asList(Protocol.HTTP_2,
Protocol.HTTP_1_1));
SSLContext sslContext = setupSSLTrust();
clientBuilder.sslSocketFactory(
sslContext.getSocketFactory(), TRUST_MANAGER);
clientBuilder.hostnameVerifier((host, session) ->
host.equals("localhost"));
return clientBuilder.build();
}
static SSLContext setupSSLTrust() throws Exception {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { TRUST_MANAGER },
new SecureRandom());
return sslContext;
}

In a nutshell, the code above creates a client instance using a builder and sets up an SSLContext for all connections created with it. Note that for flexibility both HTTP 1.1 and HTTP/2 are listed as protocols while creating the client.

Finally, we create an HTTP request and use the OkHttp client to access the server:

Request getBooks = new Request.Builder().url(
new URL("https://localhost:8080/books").build();
Response getBooksRes = client.newCall(getBooks).execute());

This story has shown how to enable HTTP/2 with TLS in Helidon. Stay tuned for future stories about Helidon by following this publication.

References

--

--