如何让 JAX-WS 在 TLS 握手中不发送客户端证书
结论
客户端可以在 TLS 握手中不提供客户端证书,具体配置方式取决于 JAX-WS 使用的传输实现。JAX-WS 没有可移植的标准属性来控制客户端证书选择。如果客户端使用 Metro,可以为代理设置一个使用空客户端密钥库的 SSLSocketFactory,避免选中 GlassFish 默认密钥库中的自签名证书。
SAP 发出的 CertificateRequest 表示服务器请求客户端证书,但客户端不一定要发送可用证书。没有匹配的证书时,TLS 客户端可以发送空的 Certificate 消息。java.net.http.HttpClient 的提示表明该客户端没有找到用于客户端认证的证书,但无法据此判断 JAX-WS 代理是否使用了相同的 TLS 配置。
Metro 客户端配置示例
下面的示例创建一个不含私钥条目的客户端密钥管理器,再将对应的 SSL socket factory 设置到 Metro 客户端代理上。请将 MyService 和服务端点地址替换为项目中的实际值:
import jakarta.xml.ws.BindingProvider;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
MyService service = new MyService();
MyPort port = service.getMyPort();
KeyStore emptyKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
emptyKeyStore.load(null, null);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmf.init(emptyKeyStore, new char[0]);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);
BindingProvider bindingProvider = (BindingProvider) port;
bindingProvider.getRequestContext().put(
"com.sun.xml.ws.transport.https.client.SSLSocketFactory",
sslContext.getSocketFactory());
将 null 作为 TrustManager[] 传入时,客户端会使用默认的服务器证书信任配置。这段代码只改变客户端证书的可用性,不会关闭对 SAP 服务端证书的验证。com.sun.xml.ws.transport.https.client.SSLSocketFactory 是 Metro 使用的属性名,不属于 JAX-WS 标准 API。请确认 GlassFish 中的客户端实际使用 Metro,且当前传输路径支持此属性。
配置后仍发送证书时
检查代理是否使用了配置后的 SSLContext,以及 GlassFish 域级别的 TLS 配置或其他客户端配置是否覆盖了它。如果使用的 JAX-WS 实现不是 Metro,请查明该实现的客户端 TLS 配置方式;上述属性不一定适用于其他实现。
请保留服务端证书校验。如果 SAP 要求客户端证书,或者其网关策略与问题描述不同,空客户端证书也可能无法建立连接。应以 SAP 端的 TLS 策略和握手日志为准。
备注:内容仅供参考。
