Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何以编程方式设置JAX-WS客户端的SSLContext?_Java_Ssl_Certificate_Jax Ws - Fatal编程技术网

Java 如何以编程方式设置JAX-WS客户端的SSLContext?

Java 如何以编程方式设置JAX-WS客户端的SSLContext?,java,ssl,certificate,jax-ws,Java,Ssl,Certificate,Jax Ws,我正在一个分布式应用程序中的服务器上工作,该应用程序具有浏览器客户端,并且还参与与第三方的服务器到服务器通信。 我的服务器有一个CA签名的证书,允许我的客户端使用HTTP/S和XMPP(安全)通过TLS(SSL)通信进行连接。一切都很好 现在,我需要通过HTTPS/SSL使用JAX-WS安全地连接到第三方服务器。在这种通信中,我的服务器充当JAX-WS交互中的客户机,我有一个由第三方签署的客户机证书 我尝试通过标准系统配置添加一个新的密钥库(-Djavax.net.ssl.keystore=xy

我正在一个分布式应用程序中的服务器上工作,该应用程序具有浏览器客户端,并且还参与与第三方的服务器到服务器通信。 我的服务器有一个CA签名的证书,允许我的客户端使用HTTP/S和XMPP(安全)通过TLS(SSL)通信进行连接。一切都很好

现在,我需要通过HTTPS/SSL使用JAX-WS安全地连接到第三方服务器。在这种通信中,我的服务器充当JAX-WS交互中的客户机,我有一个由第三方签署的客户机证书

我尝试通过标准系统配置添加一个新的密钥库(
-Djavax.net.ssl.keystore=xyz
),但我的其他组件显然受到了影响。尽管我的其他组件使用专用参数进行SSL配置(
my.xmpp.keystore=xxx,my.xmpp.truststore=xxy,
),但它们似乎最终使用了全局
SSLContext
。(配置名称空间
my.xmpp.
似乎表示分离,但事实并非如此)

我还尝试将客户机证书添加到原始密钥库中,但我的其他组件似乎也不喜欢它

我认为我剩下的唯一选择是以编程方式钩住JAX-WSHTTPS配置,为客户机JAX-WS交互设置密钥库和信任库

有关于如何做到这一点的想法/建议吗?我找到的所有信息要么使用
javax.net.ssl.keyStore
方法,要么正在设置全局
SSLContext
,我猜,这将在同一个confirc中结束。我得到的最有用的东西是这个旧的bug报告,它要求我需要的功能:


有什么需要的吗?

这是一个很难破解的难题,因此记录在案:

要解决此问题,需要一个自定义的
KeyManager
和一个使用此自定义
KeyManager
访问单独的
密钥库的
SSLSocketFactory
。 我在这篇优秀的博客文章中找到了这个
KeyStore
SSLFactory
的基本代码:

然后,需要将专用的
SSLSocketFactory
插入到WebService上下文中:

service = getWebServicePort(getWSDLLocation());
BindingProvider bindingProvider = (BindingProvider) service; 
bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getCustomSocketFactory()); 
其中
getCustomSocketFactory()
返回使用上述方法创建的
SSLSocketFactory
。考虑到表示
SSLSocketFactory
属性的字符串是此实现的专有属性,这只适用于JDK中内置的Sun Oracle impl中的JAX-WS RI

在这个阶段,JAX-WS服务通信是通过SSL进行安全保护的,但是如果您从同一个安全服务器()加载WSDL,那么您将遇到引导问题,因为收集WSDL的HTTPS请求将不会使用与Web服务相同的凭据。我通过使WSDL在本地可用来解决这个问题(file:///...)动态更改web服务端点:(可以找到关于为什么需要这样做的详细讨论)


现在,WebService已启动,并且能够使用命名(别名)客户端证书和相互身份验证通过SSL与服务器对等方通信。∎

这就是我通过一些小的调整解决它的方法。此解决方案不需要创建任何其他类

SSLContext sc = SSLContext.getInstance("SSLv3");

KeyManagerFactory kmf =
    KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm() );

KeyStore ks = KeyStore.getInstance( KeyStore.getDefaultType() );
ks.load(new FileInputStream( certPath ), certPasswd.toCharArray() );

kmf.init( ks, certPasswd.toCharArray() );

sc.init( kmf.getKeyManagers(), null, null );

((BindingProvider) webservicePort).getRequestContext()
    .put(
        "com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory",
        sc.getSocketFactory() );

我尝试了以下方法,但在我的环境中无效:

bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getCustomSocketFactory());
但是,不同的财产发挥了巨大的作用:

bindingProvider.getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, getCustomSocketFactory());
其余的代码取自第一个回复。

以上内容很好(正如我在评论中所说),除非您的WSDL也可以通过https://访问

以下是我的解决方法:

将SSLSocketFactory设置为默认值:

HttpsURLConnection.setDefaultSSLSocketFactory(...);
对于我使用的Apache CXF,您还需要在配置中添加以下行:

<http-conf:conduit name="*.http-conduit">
  <http-conf:tlsClientParameters useHttpsURLConnectionDefaultSslSocketFactory="true" />
<http-conf:conduit>

对于那些试图让它工作但仍然无法正常工作的人,我使用了Wildfly 8,使用了动态
调度程序

bindingProvider.getRequestContext().put(“com.sun.xml.ws.transport.https.client.SSLSocketFactory”,yoursssocketfactory)


请注意,属性键的
内部部分已在此处消失。

通过结合Radek和l0co的答案,您可以访问https背后的WSDL:

SSLContext sc = SSLContext.getInstance("TLS");

KeyManagerFactory kmf = KeyManagerFactory
        .getInstance(KeyManagerFactory.getDefaultAlgorithm());

KeyStore ks = KeyStore.getInstance("JKS");
ks.load(getClass().getResourceAsStream(keystore),
        password.toCharArray());

kmf.init(ks, password.toCharArray());

sc.init(kmf.getKeyManagers(), null, null);

HttpsURLConnection
        .setDefaultSSLSocketFactory(sc.getSocketFactory());

yourService = new YourService(url); //Handshake should succeed

设置信任管理器时,我无法信任自签名证书。我使用ApacheHttpClient的SSLContexts构建器创建了一个定制的
SSLSocketFactory

SSLContext sslcontext = SSLContexts.custom()
        .loadKeyMaterial(keyStoreFile, "keystorePassword.toCharArray(), keyPassword.toCharArray())
        .loadTrustMaterial(trustStoreFile, "password".toCharArray(), new TrustSelfSignedStrategy())
        .build();
SSLSocketFactory customSslFactory = sslcontext.getSocketFactory()
bindingProvider.getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, customSslFactory);

并将
新TrustSelfSignedStrategy()
作为
loadTrustMaterial
方法中的参数传递。

我尝试了以下步骤:


这就解决了问题。我做了一些小的调整-我使用System.getProperty设置了两个参数…

您可以将代理身份验证和ssl人员移动到soap处理程序

  port = new SomeService().getServicePort();
  Binding binding = ((BindingProvider) port).getBinding();
  binding.setHandlerChain(Collections.<Handler>singletonList(new ProxyHandler()));
port=newsomeservice().getServicePort();
Binding Binding=((BindingProvider)端口).getBinding();
binding.setHandlerChain(Collections.singletonList(新的ProxyHandler());
这是我的例子,做所有的网络操作

  class ProxyHandler implements SOAPHandler<SOAPMessageContext> {
    static class TrustAllHost implements HostnameVerifier {
      public boolean verify(String urlHostName, SSLSession session) {
        return true;
      }
    }

    static class TrustAllCert implements X509TrustManager {
      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
      }

      public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
      }

      public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
      }
    }

    private SSLSocketFactory socketFactory;

    public SSLSocketFactory getSocketFactory() throws Exception {
      // just an example
      if (socketFactory == null) {
        SSLContext sc = SSLContext.getInstance("SSL");
        TrustManager[] trustAllCerts = new TrustManager[] { new TrustAllCert() };
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        socketFactory = sc.getSocketFactory();
      }

      return socketFactory;
    }

    @Override public boolean handleMessage(SOAPMessageContext msgCtx) {
      if (!Boolean.TRUE.equals(msgCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)))
        return true;

      HttpURLConnection http = null;

      try {
        SOAPMessage outMessage = msgCtx.getMessage();
        outMessage.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");
        // outMessage.setProperty(SOAPMessage.WRITE_XML_DECLARATION, true); // Not working. WTF?

        ByteArrayOutputStream message = new ByteArrayOutputStream(2048);
        message.write("<?xml version='1.0' encoding='UTF-8'?>".getBytes("UTF-8"));
        outMessage.writeTo(message);

        String endpoint = (String) msgCtx.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
        URL service = new URL(endpoint);

        Proxy proxy = Proxy.NO_PROXY;
        //Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("{proxy.url}", {proxy.port}));

        http = (HttpURLConnection) service.openConnection(proxy);
        http.setReadTimeout(60000); // set your timeout
        http.setConnectTimeout(5000);
        http.setUseCaches(false);
        http.setDoInput(true);
        http.setDoOutput(true);
        http.setRequestMethod("POST");
        http.setInstanceFollowRedirects(false);

        if (http instanceof HttpsURLConnection) {
          HttpsURLConnection https = (HttpsURLConnection) http;
          https.setHostnameVerifier(new TrustAllHost());
          https.setSSLSocketFactory(getSocketFactory());
        }

        http.setRequestProperty("Content-Type", "application/soap+xml; charset=utf-8");
        http.setRequestProperty("Content-Length", Integer.toString(message.size()));
        http.setRequestProperty("SOAPAction", "");
        http.setRequestProperty("Host", service.getHost());
        //http.setRequestProperty("Proxy-Authorization", "Basic {proxy_auth}");

        InputStream in = null;
        OutputStream out = null;

        try {
          out = http.getOutputStream();
          message.writeTo(out);
        } finally {
          if (out != null) {
            out.flush();
            out.close();
          }
        }

        int responseCode = http.getResponseCode();
        MimeHeaders responseHeaders = new MimeHeaders();
        message.reset();

        try {
          in = http.getInputStream();
          IOUtils.copy(in, message);
        } catch (final IOException e) {
          try {
            in = http.getErrorStream();
            IOUtils.copy(in, message);
          } catch (IOException e1) {
            throw new RuntimeException("Unable to read error body", e);
          }
        } finally {
          if (in != null)
            in.close();
        }

        for (Map.Entry<String, List<String>> header : http.getHeaderFields().entrySet()) {
          String name = header.getKey();

          if (name != null)
            for (String value : header.getValue())
              responseHeaders.addHeader(name, value);
        }

        SOAPMessage inMessage = MessageFactory.newInstance()
          .createMessage(responseHeaders, new ByteArrayInputStream(message.toByteArray()));

        if (inMessage == null)
          throw new RuntimeException("Unable to read server response code " + responseCode);

        msgCtx.setMessage(inMessage);
        return false;
      } catch (Exception e) {
        throw new RuntimeException("Proxy error", e);
      } finally {
        if (http != null)
          http.disconnect();
      }
    }

    @Override public boolean handleFault(SOAPMessageContext context) {
      return false;
    }

    @Override public void close(MessageContext context) {
    }

    @Override public Set<QName> getHeaders() {
      return Collections.emptySet();
    }
  }
类ProxyHandler实现SOAPHandler{
静态类TrustAllHost实现HostnameVerifier{
公共布尔验证(字符串urlHostName,SSLSession会话){
返回true;
}
}
静态类TrustAllCert实现X509TrustManager{
public java.security.cert.X509Certificate[]getAcceptedIssuers(){
返回null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[]证书,字符串authType){
}
public void checkServerTrusted(java.security.cert.X509Certificate[]证书,字符串authType){
}
}
私营SSLSocketFactory袜子厂;
公共SSLSocketFactory getSocketFactory()引发异常{
//只是一个例子
if(socketFactory==null){
SSLContext sc=SSLContext.getInstance(“SSL”);
TrustManager[]trustAllCerts=new TrustManager[]{new TrustAllCert()};
sc.init(null,trustAllCerts,新java.security)。
  class ProxyHandler implements SOAPHandler<SOAPMessageContext> {
    static class TrustAllHost implements HostnameVerifier {
      public boolean verify(String urlHostName, SSLSession session) {
        return true;
      }
    }

    static class TrustAllCert implements X509TrustManager {
      public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
      }

      public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
      }

      public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
      }
    }

    private SSLSocketFactory socketFactory;

    public SSLSocketFactory getSocketFactory() throws Exception {
      // just an example
      if (socketFactory == null) {
        SSLContext sc = SSLContext.getInstance("SSL");
        TrustManager[] trustAllCerts = new TrustManager[] { new TrustAllCert() };
        sc.init(null, trustAllCerts, new java.security.SecureRandom());
        socketFactory = sc.getSocketFactory();
      }

      return socketFactory;
    }

    @Override public boolean handleMessage(SOAPMessageContext msgCtx) {
      if (!Boolean.TRUE.equals(msgCtx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)))
        return true;

      HttpURLConnection http = null;

      try {
        SOAPMessage outMessage = msgCtx.getMessage();
        outMessage.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-8");
        // outMessage.setProperty(SOAPMessage.WRITE_XML_DECLARATION, true); // Not working. WTF?

        ByteArrayOutputStream message = new ByteArrayOutputStream(2048);
        message.write("<?xml version='1.0' encoding='UTF-8'?>".getBytes("UTF-8"));
        outMessage.writeTo(message);

        String endpoint = (String) msgCtx.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
        URL service = new URL(endpoint);

        Proxy proxy = Proxy.NO_PROXY;
        //Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("{proxy.url}", {proxy.port}));

        http = (HttpURLConnection) service.openConnection(proxy);
        http.setReadTimeout(60000); // set your timeout
        http.setConnectTimeout(5000);
        http.setUseCaches(false);
        http.setDoInput(true);
        http.setDoOutput(true);
        http.setRequestMethod("POST");
        http.setInstanceFollowRedirects(false);

        if (http instanceof HttpsURLConnection) {
          HttpsURLConnection https = (HttpsURLConnection) http;
          https.setHostnameVerifier(new TrustAllHost());
          https.setSSLSocketFactory(getSocketFactory());
        }

        http.setRequestProperty("Content-Type", "application/soap+xml; charset=utf-8");
        http.setRequestProperty("Content-Length", Integer.toString(message.size()));
        http.setRequestProperty("SOAPAction", "");
        http.setRequestProperty("Host", service.getHost());
        //http.setRequestProperty("Proxy-Authorization", "Basic {proxy_auth}");

        InputStream in = null;
        OutputStream out = null;

        try {
          out = http.getOutputStream();
          message.writeTo(out);
        } finally {
          if (out != null) {
            out.flush();
            out.close();
          }
        }

        int responseCode = http.getResponseCode();
        MimeHeaders responseHeaders = new MimeHeaders();
        message.reset();

        try {
          in = http.getInputStream();
          IOUtils.copy(in, message);
        } catch (final IOException e) {
          try {
            in = http.getErrorStream();
            IOUtils.copy(in, message);
          } catch (IOException e1) {
            throw new RuntimeException("Unable to read error body", e);
          }
        } finally {
          if (in != null)
            in.close();
        }

        for (Map.Entry<String, List<String>> header : http.getHeaderFields().entrySet()) {
          String name = header.getKey();

          if (name != null)
            for (String value : header.getValue())
              responseHeaders.addHeader(name, value);
        }

        SOAPMessage inMessage = MessageFactory.newInstance()
          .createMessage(responseHeaders, new ByteArrayInputStream(message.toByteArray()));

        if (inMessage == null)
          throw new RuntimeException("Unable to read server response code " + responseCode);

        msgCtx.setMessage(inMessage);
        return false;
      } catch (Exception e) {
        throw new RuntimeException("Proxy error", e);
      } finally {
        if (http != null)
          http.disconnect();
      }
    }

    @Override public boolean handleFault(SOAPMessageContext context) {
      return false;
    }

    @Override public void close(MessageContext context) {
    }

    @Override public Set<QName> getHeaders() {
      return Collections.emptySet();
    }
  }