【问题标题】:Websphere - Spring Integration SSL issueWebsphere - Spring 集成 SSL 问题
【发布时间】:2019-07-11 23:58:15
【问题描述】:

我们的 Spring Integration 应用程序在 Websphere 上运行。它是 SSL 外部服务的客户端。

我已经使用 Retrive 从端口 [进入默认信任库] 导入了一个证书,提供主机和 443 端口。在 WebSphere 上启用了跟踪,它似乎正在查看 cacert 文件而不是 trust.p12。

[18-2-19 13:44:59:154 CET] 00000063 SystemOut     O 2019-02-18 13:44:59.153  INFO 30426 --- [ver.startup : 0] pertySourcedRequestMappingHandlerMapping : Mapped URL path [/v2/api-docs] onto method [public org.springframework.http.ResponseEntity<springfox.documentation.spring.web.json.Json> springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(java.lang.String,javax.servlet.http.HttpServletRequest)]
[18-2-19 13:44:59:826 CET] 00000063 SystemOut     O keyStore is: /srv/opt/IBM/WebSphere/AppServer/java/8.0/jre/lib/security/cacerts

代码:

public class PreemptiveMessageSender extends HttpComponentsMessageSender {

    @Autowired
    private Environment env; 

    private String host;
    private String userId;
    private String password;

    public PreemptiveMessageSender() {
        super();
    }

    public PreemptiveMessageSender(HttpClient httpClient) {
        super(httpClient);
    }

    @Override
    protected HttpContext createContext(URI uri) {

        HttpHost targetHost = new HttpHost(host, 443, "https");

        String decryptedPassword = getDecryptedPassword();

         CredentialsProvider credsProvider = new BasicCredentialsProvider();
         credsProvider.setCredentials(AuthScope.ANY, 
                    new UsernamePasswordCredentials(userId, decryptedPassword));

         AuthCache authCache = new BasicAuthCache();
         authCache.put(targetHost, new BasicScheme());

         // Add AuthCache to the execution context
         final HttpClientContext context = HttpClientContext.create();
         context.setCredentialsProvider(credsProvider);
         context.setAuthCache(authCache);

         return context;        
    }

    private String getDecryptedPassword() {
        BasicTextEncryptor textEncrypt = new BasicTextEncryptor();

        textEncrypt.setPassword(env.getProperty("KEY_PASSWORD"));
        return textEncrypt.decrypt(password);       
    }

    @Override
    public WebServiceConnection createConnection(URI uri) throws IOException {

        HttpPost httpPost = new HttpPost(uri);
        if (isAcceptGzipEncoding()) {
            httpPost.addHeader(HttpTransportConstants.HEADER_ACCEPT_ENCODING,
                    HttpTransportConstants.CONTENT_ENCODING_GZIP);
        }
        HttpContext httpContext = createContext(uri);
        return new CustomHttpComponentsConnection(getHttpClient(), httpPost, httpContext);
    }

    ... 
}

错误

“异常”:“org.springframework.ws.client.WebServiceIOException”, “消息”:“I/O 错误:com.ibm.jsse2.util.h:PKIX 路径构建失败:java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl 无法构建有效的 CertPath。;内部的 原因是:\n\tjava.security.cert.CertPathValidatorException: CN=ODC Test Root CA - G1, O=ODC Test, C=TU颁发的证书 不信任;内因是: \n\tjava.security.cert.CertPathValidatorException:证书 链接错误;嵌套异常是 javax.net.ssl.SSLHandshakeException:com.ibm.jsse2.util.h:PKIX 路径 构建失败:java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl 无法构建有效的 CertPath。;内部的 原因是:\n\tjava.security.cert.CertPathValidatorException: CN=ODC Test Root CA - G1, O=ODC Test, C=TU颁发的证书 不信任;内因是: \n\tjava.security.cert.CertPathValidatorException:证书 链接错误”,

问题: 使用 java cacert 的 Spring Integration 是否存在此问题?如何让它使用 WebSphere 的信任库?

【问题讨论】:

    标签: spring websphere spring-integration truststore


    【解决方案1】:

    首先我对 Spring 一无所知。但是考虑到您谈论的行为,它必须创建自己的 SSLContext 实例。这将导致它绕过 WebSphere SSL 设置。它必须执行类似 SSLContext.getInstance() 的操作来创建自己的实例,或者它可能执行类似 SSLContext.getDefault() 的操作,返回 JDK 的默认 SSLContext。两者都不会为您提供 WebSphere SSLContext。

    【讨论】:

    • 我能理解,但是getDefault虽然还没试过,应该弄到WAS环境吧?希望我能得到一个有效的答案
    • 没有 SSLContext.getDefault() 会为您提供 JSSE 的默认 SSLContext。 WebSphere 不做任何事情来重置 JSSE 的默认 SSLContext.setDefault()。 WebSphere 使用自定义 SSLSocketFactory,您可以通过调用 SSLSocketFactory.getDefault() 来获取它。有了它,您将可以访问 WebSphere 的 ssl 配置。
    • 感谢您的指点。使用 HttpClients、HttpClientBuilder、blah blah 并得到错误 Content-length 标头始终存在等。但最终找到了一个修复的链接。对不起,但作为另一个答案添加
    • Aww,在这种情况下,您还有其他事情要做。 HttpClientBuilder 有一个名为 useSystemProperties() 的选项。这将允许 Apache 代码获取 WebSphere 配置。
    【解决方案2】:

    https://developer.ibm.com/answers/questions/394270/im-using-an-apache-httpclient-to-make-an-outbound/

    HttpClient theClient = HttpClientBuilder.create().useSystemProperties().addInterceptorFirst(new RemoveSoapHeadersInterceptor()).build();

    private static class RemoveSoapHeadersInterceptor implements HttpRequestInterceptor {
            @Override
            public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
                if (request instanceof HttpEntityEnclosingRequest) {
                    if (request.containsHeader(HTTP.TRANSFER_ENCODING)) {
                        request.removeHeaders(HTTP.TRANSFER_ENCODING);
                    }
                    if (request.containsHeader(HTTP.CONTENT_LEN)) {
                        request.removeHeaders(HTTP.CONTENT_LEN);
                    }
                }
            }   
        }
    

    【讨论】: