Notes on configuring Liberty to use specific SSL/TLS configurations for outbound connections.

Dynamic Outbound SSL Configuration

I honestly expected configuring the required server.xml elements to “just work” with all TLS connections, but it did not. Thus, the StackOverflow question I posted. It turns out that for JAX-WS and JAX-RS, this is intended to be sufficient. But not for the lower-level java.net.http.HttpClient that I’m using.

(Note in the examples below that our use case for this is presenting the Apple Pay merchant identity certificate in the mTLS required for Apple Pay merchant validation.)

server.xml

Of course this assumes a feature that enables SSL/TLS, the current being transportSecurity-1.0 (which is pulled in by higher-level features as well).

Then add elements to define the keystore and the configuration that uses it for specific host(s):

    <keyStore id="applePayKeyStore" location="/keys/MerchID.p12" password="${APPLE_KEYSTORE_PASSWORD}" readOnly="true"/>
    <ssl id="applePaySSL" keyStoreRef="applePayKeyStore" clientAuthentication="true" sslProtocol="TLSv1.2" trustDefaultCerts="true">
        <outboundConnection host="${APPLE_VALIDATION_HOST}"/>
    </ssl>

Java code

Excerpt:

        HttpRequest request = HttpRequest.newBuilder().uri(validationEndpoint)
            .header("Content-Type", "application/json")
            .POST(BodyPublishers.ofString(jsonRequest))
            .build();

        HttpClient client = HttpClient.newBuilder()
            .sslContext(sslContext).build();

        String responseData = client.send(request, BodyHandlers.ofString()).body();

Where:

  • validationEndpoint is the injected URL on server ${APPLE_VALIDATION_HOST}:
  • sslContext is also injected, as I’ll show below

Alternatively, the first cut at this for the SSLContext was explicitly using the Liberty-specific JSSEHelper class:

        SSLContext sslContext =
            JSSEHelper.getInstance().getSSLContext("applePaySSL", null, null);

Injecting the SSLContext

We use Spring DI with mostly XML bean configuration, so here are my relevant beans that allow the Java code to not depend on the Liberty classes:

    <bean id="libertyJSSEHelper" class="com.ibm.websphere.ssl.JSSEHelper" factory-method="getInstance"/>

    <bean id="appleSSLContext" factory-bean="libertyJSSEHelper" factory-method="getSSLContext">
        <constructor-arg index="0" value="applePaySSL"/>
        <constructor-arg index="1"><null/></constructor-arg>
        <constructor-arg index="2"><null/></constructor-arg>
    </bean>

References