使用 https WSDL 针对生成的 Web 客户端创建服务

Creating a Service against a generated web client with a https WSDL

所以我必须针对托管在 HTTPS url 上的 WSDL 创建服务,但在创建服务时遇到了问题。出于实际原因,我不允许将证书添加到我的信任库中,因此当我使用自定义 SSLSocketFactory 执行以下步骤时(因此我们可以动态更改密钥库):

QName name = new QName(qName, QNAME);
Service service = new Client(httpsUrl, name);
port = service.getPort(ClientSoap.class);

我们得到了熟悉的错误

unable to find valid certification path to requested target

解决此问题的方法是在我们创建服务之前添加自定义套接字工厂,这样我们的 SSL 上下文是正确的(详见此处 1

HttpsURLConnection.setDefaultSSLSocketFactory(socketFactory);

然而,这会将应用程序的默认 SSLContext 污染为我们特定的自定义上下文,并导致应用程序内的其他 https 调用失败,因为它们使用的是我们刚刚使用的自定义上下文,而不是 cacerts 上下文。

有什么方法可以在我们最初创建服务时使用我们的自定义上下文吗?

好的,我通过做一些有点丑陋的事情(IMO)自己解决了这个问题,但我想我会把它放在这里以防其他人遇到这个问题。基本上将原始 SSLContext 拉入 class 级别变量,然后使用新上下文设置默认值。完成所有处理后,将默认上下文重置为原始上下文。

private SSLSocketFactory originalSocketFactory;
private SSLSocketFactory customSocketFactory;

public void doSomeStuff(){

    try {
        setSocketFactories();
    } catch (CertificateException | IOException | GeneralSecurityException e) {
        e.printStackTrace();
    }

    //do your stuff here

    resetOriginalSocketFactory();
}

private void setSocketFactories() throws CertificateException, IOException, GeneralSecurityException {

    String jksFile = "C:\My.jks";
    String type = "JKS";
    String password="password";

    if(null == originalSocketFactory){
        originalSocketFactory= HttpsURLConnection.getDefaultSSLSocketFactory();         
    }
    if(null == customSocketFactory){
        customSocketFactory = getCustomSocketFactory(jksFile, type, password);
        HttpsURLConnection.setDefaultSSLSocketFactory(customSocketFactory);
    }
}

private void resetOriginalSocketFactory(){
    HttpsURLConnection.setDefaultSSLSocketFactory(originalSocketFactory);
}

private SSLSocketFactory getCustomSocketFactory(String keyStoreLocation, String keystoreType,String password) 
        throws CertificateException, IOException, GeneralSecurityException {
    SSLSocketFactory socketFactory = new SSLSocketFactoryGenerator(keyStoreLocation,keystoreType).getSSLSocketFactory(password);
    return socketFactory;
}