为什么Liferay 6.2 ee sp14加载JKS密钥库文件存在不一致问题?
问题根因
Java默认的SSLContext是懒加载单例,仅在首次使用SSL/TLS连接时读取javax.net.ssl.*系统属性完成初始化,后续修改系统属性不会重新初始化默认上下文。Liferay启动过程中大量内置模块、第三方插件会发起网络请求,只要某一个模块在你的代码执行前发起了HTTPS请求,就会触发默认SSLContext初始化,你的属性设置就完全失效,这正好匹配你遇到的启动后立刻调用有概率成功、延后调用必失败的现象。
干扰源定位方法
- 加JVM启动参数
-Djavax.net.debug=ssl,trustmanager,重启服务器复现问题,查看日志输出,SSL初始化阶段会打印加载的信任库路径、初始化调用栈,可直接定位到先触发SSLContext初始化的模块 - 也可以在你的代码设置系统属性前,打印当前的
javax.net.ssl.*系统属性的初始值,确认是否被其他模块提前修改过
可行解决方案
方案1:为第三方WebService客户端单独配置自定义SSLContext(最推荐,无全局影响)
无需修改全局配置,直接给你调用WS的客户端绑定自定义加载的JKS对应的SSLContext,完全不受全局初始化状态影响:
// 加载自定义JKS生成SSLContext KeyStore keyStore = KeyStore.getInstance("JKS"); try (FileInputStream fis = new FileInputStream(jksPath)) { keyStore.load(fis, jksPass.toCharArray()); } // 初始化密钥管理器 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(keyStore, jksPass.toCharArray()); // 初始化信任管理器 TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(keyStore); // 生成自定义SSLContext SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); // 绑定到JAX-WS客户端 YourWebServicePort port = service.getYourWebServicePort(); BindingProvider bindingProvider = (BindingProvider) port; bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", sslContext.getSocketFactory()); // 如果用CXF客户端,对应配置项为"org.apache.cxf.configuration.jsse.TLSClientParameters"
该方案完全不影响Liferay其他模块的SSL配置,也不会被其他模块干扰,可用性最高。
方案2:强制重置全局默认SSLContext(适配无法修改WS客户端代码的场景)
如果第三方库写死使用默认SSLContext、无法修改客户端配置,可以直接覆盖已经初始化的全局默认SSLContext:
// 按方案1的代码构造好自定义sslContext后执行 SSLContext.setDefault(sslContext);
执行后所有使用默认SSLContext的请求都会用你配置的JKS,不管之前是否有其他模块加载过密钥库。
方案3:JVM启动参数预配置(兜底方案)
如果上述两个方案都无法实施,直接把JKS配置加到Liferay启动参数中,JVM启动时就会加载该配置,优先级最高,不会被任何模块的运行时属性修改覆盖:
在Liferay的setenv.sh(Linux)或setenv.bat(Windows)的CATALINA_OPTS参数中添加:
-Djavax.net.ssl.keyStore=/path/to/your.jks -Djavax.net.ssl.keyStorePassword=yourpassword -Djavax.net.ssl.keyStoreType=JKS -Djavax.net.ssl.trustStore=/path/to/your.jks -Djavax.net.ssl.trustStorePassword=yourpassword -Djavax.net.ssl.trustStoreType=JKS
注意该方案全局生效,会影响Liferay所有模块的SSL请求,若其他模块需要使用不同密钥库不建议使用。
内容的提问来源于stack exchange,提问作者SolS
相关产品推荐
相关产品推荐

