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

2019-05-31 22:29发布

我工作在具有浏览器客户端分布式应用程序在服务器上,还参加了与第三方服务器到服务器的通信。 我的服务器有一个CA签发的证书,让我的客户使用使用HTTP / S和XMPP(安全)TLS(SSL)通讯连接。 这是所有工作的罚款。

现在我需要安全地连接到使用JAX-WS通过HTTPS / SSL第三方服务器。 在此交流,我的服务器充当了JAX-WS互为作用的客户端和我已经通过第三方签署了客户端证书。

我试图通过标准的系统配置(添加一个新的密钥库-Djavax.net.ssl.keyStore=xyz ),但我的其他成分显然受此影响。 虽然我的其他部件都采用专用的参数,其SSL配置( my.xmpp.keystore=xxx, my.xmpp.truststore=xxy, ... ),似乎他们最终使用了全球SSLContext 。 (配置命名空间my.xmpp.似乎表明分离,但它并非如此)

我也尝试添加我的客户端证书到我原来的密钥库,但似乎-again-我的其他组件不要么喜欢它。

我认为我唯一的选择就是以编程方式挂接到JAX-WS HTTPS配置设置客户端JAX-WS互动的密钥库和信任。

任何想法/指针如何做到这一点? 我觉得无论是所有信息使用javax.net.ssl.keyStore法或正在制定全球SSLContext是-I guess-将在同一confilc结束。 我得到了一些有助于最接近的是,请求功能,我需要这个旧的错误报告: 添加传递一个SSLContext中的JAX-WS客户端运行时支持

任何需要?

Answer 1:

这一个是一个难啃的骨头,所以备案:

为了解决这个问题,它需要一个定制KeyManagerSSLSocketFactory使用该定制KeyManager访问分离的KeyStore 。 我发现这个基本代码KeyStoreSSLFactory在这个优秀的博客条目: 如何对动态选择-一个证书别名时,调用的Web服务

随后,专门SSLSocketFactory需要插入WebService的背景:

service = getWebServicePort(getWSDLLocation());
BindingProvider bindingProvider = (BindingProvider) service; 
bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getCustomSocketFactory()); 

其中getCustomSocketFactory()返回一个SSLSocketFactory使用上述的方法建立。 这将仅适用于JAX-WS RI从内置到JDK太阳甲骨文IMPL工作,因为指示字符串SSLSocketFactory属性是专有此实现。

在这个阶段中,JAX-WS服务的通信是通过SSL安全,但如果你是从同一个安全服务器加载WSDL(),那么你就会有一个引导的问题,作为HTTPS请求,以收集WSDL将不会被使用相同的凭据比Web服务。 我工作围绕这一问题通过使WSDL本地可用(文件:/// ...)和动态变化的网络服务端点(为什么这是需要能够找到一个很好的讨论, 在这个论坛 )

bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, webServiceLocation); 

现在,WebService的被Bootstrap过,能够通过使用一个名为(化名)的服务器对应SSL通信的客户端证书和相互认证。 ∎



Answer 2:

这是我如何解决它基于这个职位有一些小的调整。 该解决方案不需要任何额外的类创作。

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() );


Answer 3:

我尝试以下,并没有在我的环境中工作:

bindingProvider.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", getCustomSocketFactory());

但是,不同的物业工作就像一个魅力:

bindingProvider.getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, getCustomSocketFactory());

代码的其余部分是从第一个回复拍摄。



Answer 4:

通过结合拉狄克和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


Answer 5:

以上是精(正如我在评论说的),除非你的WSDL与https访问://太。

这里是我的这种解决方法:

设置你的SSLSocketFactory为默认:

HttpsURLConnection.setDefaultSSLSocketFactory(...);

对于Apache CXF我用你也需要添加这些行到您的配置:

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


Answer 6:

对于那些尝试,仍然没有得到它的工作,这为我做与Wildfly 8,使用动态Dispatcher

bindingProvider.getRequestContext().put("com.sun.xml.ws.transport.https.client.SSLSocketFactory", yourSslSocketFactory);

需要注意的是, internal部分从属性关键是在这里了。



Answer 7:

我不得不建立信任管理器时,信任自签名证书问题。 我使用了Apache的HttpClient的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);

并传入new TrustSelfSignedStrategy()作为一个参数loadTrustMaterial方法。



Answer 8:

我尝试此处的步骤:

http://jyotirbhandari.blogspot.com/2011/09/java-error-invalidalgorithmparameterexc.html

而且,这解决了该问题。 我做了一些小改动 - 我设置使用System.getProperty两个参数...



Answer 9:

您可以将您的代理认证和SSL人员SOAP处理程序

  port = new SomeService().getServicePort();
  Binding binding = ((BindingProvider) port).getBinding();
  binding.setHandlerChain(Collections.<Handler>singletonList(new ProxyHandler()));

这是我的榜样,做所有的网络OPS

  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();
    }
  }

它使用的URLConnection,你可以使用你在处理程序所需的任何库。 玩得开心!



文章来源: How to programmatically set the SSLContext of a JAX-WS client?