You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Open Liberty下MicroProfile REST Client证书认证握手失败问题

Fixing Truststore Switching Issue with MicroProfile REST Client (@Asynchronous) in Open Liberty

I’ve run into nearly identical SSL handshake headaches with MicroProfile REST Client in Open Liberty, especially when working with asynchronous calls. Given your scenario—where HttpsURLConnection works flawlessly but the async REST Client falls back to the JDK default cacerts (despite matching configs, with only the startup method differing: standalone vs mvn liberty:dev)—here’s how you can resolve this:

Core Problem Breakdown

The root issue is that asynchronous MicroProfile REST Client calls don’t automatically inherit Open Liberty’s global SSL truststore configuration, unlike HttpsURLConnection. When using liberty:dev, implicit system property overrides or context propagation gaps often cause the client to switch to the JDK’s default cacerts, leaving you without the required trusted certificate for authentication.

Solutions & Troubleshooting Steps

1. Explicitly Configure SSL Context for the REST Client

MicroProfile REST Client doesn’t always pick up the server’s global SSL config automatically, especially for async tasks. Define a custom SSL context and bind it to your client:

  • Create an SSL context producer class:
import javax.enterprise.context.ApplicationScoped;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.security.KeyStore;

@ApplicationScoped
public class RestClientSslConfig {

    public SSLContext getCustomSslContext() throws Exception {
        // Load your custom truststore (adjust path to match your project structure)
        KeyStore trustStore = KeyStore.getInstance("JKS");
        try (FileInputStream fis = new FileInputStream("./resources/security/key.jks")) {
            trustStore.load(fis, "changeit".toCharArray());
        }

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);
        return sslContext;
    }
}
  • Build your async REST Client with this SSL context using a CDI producer:
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import java.net.URI;

@ApplicationScoped
public class MyRestClientProducer {

    @Produces
    @RegisterRestClient
    public MyAsyncRestClient buildRestClient(RestClientSslConfig sslConfig) throws Exception {
        return RestClientBuilder.newBuilder()
                .baseUri(URI.create("https://your-external-endpoint.com"))
                .sslContext(sslConfig.getCustomSslContext())
                .build(MyAsyncRestClient.class);
    }
}
  • Your async client interface stays unchanged:
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.concurrent.CompletionStage;

@RegisterRestClient(baseUri = "https://your-external-endpoint.com")
@Asynchronous
public interface MyAsyncRestClient {
    @GET
    @Path("/api/data")
    CompletionStage<String> fetchData();
}

2. Force Truststore Properties in the liberty:dev Maven Config

The liberty-maven-plugin can sometimes override system properties during liberty:dev startup. Explicitly pass your truststore config in the plugin’s JVM options:

<plugin>
    <groupId>io.openliberty.tools</groupId>
    <artifactId>liberty-maven-plugin</artifactId>
    <version>3.9.1</version> <!-- Match your plugin version -->
    <configuration>
        <serverName>your-server-name</serverName>
        <jvmOptions>
            <option>-Djavax.net.ssl.trustStore=${project.basedir}/src/main/liberty/config/resources/security/key.jks</option>
            <option>-Djavax.net.ssl.trustStorePassword=changeit</option>
            <option>-Djavax.net.ssl.trustStoreType=JKS</option>
        </jvmOptions>
    </configuration>
</plugin>

This ensures the truststore path resolves correctly relative to your Maven project’s structure.

3. Bind REST Client to Open Liberty’s SSL Configuration

Update your server’s server.xml to explicitly link the MicroProfile REST Client to your custom SSL config:

<featureManager>
    <feature>ssl-1.0</feature>
    <feature>mpRestClient-2.0</feature> <!-- Use your MP Rest Client version -->
    <feature>contextPropagation-1.0</feature> <!-- Critical for async context inheritance -->
</featureManager>

<keyStore id="defaultKeyStore" location="key.jks" password="changeit" type="jks"/>
<ssl id="restClientSsl" trustStoreRef="defaultKeyStore"/>
<!-- Associate REST Client with your SSL config -->
<mpRestClient sslRef="restClientSsl"/>

The contextPropagation-1.0 feature is non-negotiable here—it ensures async threads inherit the main thread’s SSL context, preventing the unwanted switch to cacerts.

4. Debug Truststore Loading in liberty:dev

Add targeted debug flags to see exactly what’s happening during truststore loading:

mvn liberty:dev -Ddebug=false -DskipTests=true -Djavax.net.debug=ssl,trustmanager

Compare these logs with your standalone instance—look for lines where the truststore is loaded. You’ll likely find that liberty:dev is picking up a different truststore path due to Maven’s working directory.

内容的提问来源于stack exchange,提问作者Jacob Kjome

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 17:22:42