2012-09-18 165 views
13

如何使用javax.xml.ws.Service禁用JAX-WS客戶端中的證書驗證?如何在JAX-WS客戶端中禁用證書驗證?

我試圖在SSLSocketFactory的創建全信任的TrustManager,並試圖與BindingProvider

SSLContext sc = SSLContext.getInstance("SSL"); 
sc.init(null, trustAllCerts, new java.security.SecureRandom()); 

Map<String, Object> ctxt = ((BindingProvider) wsport).getRequestContext(); 
ctxt.put(JAXWSProperties.SSL_SOCKET_FACTORY, sc.getSocketFactory()); 

綁定,但我仍然得到Exception: unable to find valid certification path to requested target

但它的作品時,我只是用

HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); 

或者有沒有辦法讓javax.xml.ws.Service使用我創建的HttpsURLConnection

+4

上下文是重要的。你爲什麼要故意引入重大的不安全感?如果你不想保護它,爲什麼要使用HTTPS/SSL呢? – EJP

+3

您最好將不受信任的證書添加到Java密鑰庫 – artbristol

回答

7

真相可以從這裏找到Erik Wramner的博客http://erikwramner.wordpress.com/2013/03/27/trust-self-signed-ssl-certificates-and-skip-host-name-verification-with-jax-ws

請注意尼古拉斯米爾諾夫的評論也是如此。我使用jdk 7和glassfish 3.1.2。在這種環境下,如果服務器處理自簽名證書,建議的解決方案將很完美。

我包括用於以後參考還包括溶液的完整解決方案時的Apache CXF使用:

// import com.sun.xml.ws.developer.JAXWSProperties; 
import java.security.GeneralSecurityException; 
import java.security.SecureRandom; 
import java.util.Map; 
import javax.net.ssl.HostnameVerifier; 
import javax.net.ssl.KeyManager; 
import javax.net.ssl.SSLContext; 
import javax.net.ssl.SSLSession; 
import javax.net.ssl.SSLSocketFactory; 
import javax.net.ssl.TrustManager; 
import javax.net.ssl.X509TrustManager; 
import javax.xml.ws.BindingProvider; 
import org.apache.cxf.configuration.jsse.TLSClientParameters; 
import org.apache.cxf.endpoint.Client; 
import org.apache.cxf.frontend.ClientProxy; 
import org.apache.cxf.transport.http.HTTPConduit; 

/** 
* 
* Usage examples (BindingProvider port): 
* NaiveSSLHelper.makeWebServiceClientTrustEveryone(port); // GlassFish 
* NaiveSSLHelper.makeCxfWebServiceClientTrustEveryone(port); // TomEE 
* 
* Based on Erik Wramner's example frome here: 
* http://erikwramner.wordpress.com/2013/03/27/trust-self-signed-ssl-certificates-and-skip-host-name-verification-with-jax-ws/ 
* 
* I have extended the functionality when Apache CXF is used. 
*/ 
public class NaiveSSLHelper { 

    private static final String JAXWS_HOSTNAME_VERIFIER = "com.sun.xml.ws.transport.https.client.hostname.verifier"; // JAXWSProperties.HOSTNAME_VERIFIER; 
    private static final String JAXWS_SSL_SOCKET_FACTORY = "com.sun.xml.ws.transport.https.client.SSLSocketFactory"; // JAXWSProperties.SSL_SOCKET_FACTORY; 

    // In Glassfish (Metro) environment you can use this function (Erik Wramner's solution) 
    public static void makeWebServiceClientTrustEveryone(Object webServicePort) { 
     if (webServicePort instanceof BindingProvider) { 
      BindingProvider bp = (BindingProvider) webServicePort; 
      Map requestContext = bp.getRequestContext(); 
      requestContext.put(JAXWS_SSL_SOCKET_FACTORY, getTrustingSSLSocketFactory()); 
      requestContext.put(JAXWS_HOSTNAME_VERIFIER, new NaiveHostnameVerifier()); 
     } else { 
      throw new IllegalArgumentException(
        "Web service port " 
        + webServicePort.getClass().getName() 
        + " does not implement " 
        + BindingProvider.class.getName()); 
     } 
    } 

    // In TomEE (Apache CXF) environment you can use this function (my solution) 
    public static void makeCxfWebServiceClientTrustEveryone(Object port) { 
     TrustManager[] trustManagers = new TrustManager[]{ 
      new NaiveTrustManager() 
     }; 
     Client c = ClientProxy.getClient(port); 
     HTTPConduit httpConduit = (HTTPConduit) c.getConduit(); 
     TLSClientParameters tlsParams = new TLSClientParameters(); 
     tlsParams.setSecureSocketProtocol("SSL"); 
     tlsParams.setKeyManagers(new KeyManager[0]); 
     tlsParams.setTrustManagers(trustManagers); 
     tlsParams.setDisableCNCheck(true); 
     httpConduit.setTlsClientParameters(tlsParams); 
    } 

    public static SSLSocketFactory getTrustingSSLSocketFactory() { 
     return SSLSocketFactoryHolder.INSTANCE; 
    } 

    private static SSLSocketFactory createSSLSocketFactory() { 
     TrustManager[] trustManagers = new TrustManager[]{ 
      new NaiveTrustManager() 
     }; 
     SSLContext sslContext; 
     try { 
      sslContext = SSLContext.getInstance("SSL"); 
      sslContext.init(new KeyManager[0], trustManagers, new SecureRandom()); 
      return sslContext.getSocketFactory(); 
     } catch (GeneralSecurityException e) { 
      return null; 
     } 
    } 

    private static interface SSLSocketFactoryHolder { 

     public static final SSLSocketFactory INSTANCE = createSSLSocketFactory(); 
    } 

    private static class NaiveHostnameVerifier implements 
      HostnameVerifier { 

     @Override 
     public boolean verify(String hostName, 
       SSLSession session) { 
      return true; 
     } 
    } 

    private static class NaiveTrustManager implements 
      X509TrustManager { 

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

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

     @Override 
     public java.security.cert.X509Certificate[] getAcceptedIssuers() { 
      return new java.security.cert.X509Certificate[0]; 
     } 
    } 
} 
+1

比Jose Renato的答案要好得多。從鏈接的解決方案來說,並非所有情況下都可以使用,但至少對我來說(使用OpenJdk 1.8,以及使用NetBeans 8.2的JAX-WS實現)它工作的很好,你會在這裏複製它,以防止鏈接頁面潛在的將來消失嗎? – pvgoran

+1

我已經根據@pvgoran的建議添加了解決方案本身,還包括使用ApacheCXF的情況。 –