【发布时间】:2015-10-30 10:42:02
【问题描述】:
我正在尝试从tomee 1.6 server 调用WS 而不是SSL,但我得到了SSLHandshakeError。问题是证书是自签名的,我的JVM 无法识别。由于它仅用于测试目的,而不是生产,我被要求绕过证书控制。
我阅读了很多关于如何进行的资料,并且我已经编写了该代码:
一个类NaiveSSLContext:
package fr.csf.ssl;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
/**
* A factory class which creates an {@link SSLContext} that
* naively accepts all certificates without verification.
*/
public class NaiveSSLContext
{
private NaiveSSLContext()
{}
/**
* Get an SSLContext that implements the specified secure
* socket protocol and naively accepts all certificates
* without verification.
*/
public static SSLContext getInstance( String protocol) throws NoSuchAlgorithmException
{
SSLContext sslCtx = SSLContext.getInstance( protocol);
init( sslCtx);
return sslCtx;
}
/**
* Get an SSLContext that implements the specified secure
* socket protocol and naively accepts all certificates
* without verification.
*/
public static SSLContext getInstance( String protocol, Provider provider) throws NoSuchAlgorithmException
{
SSLContext sslCtx = SSLContext.getInstance( protocol, provider);
init( sslCtx);
return sslCtx;
}
/**
* Get an SSLContext that implements the specified secure
* socket protocol and naively accepts all certificates
* without verification.
*/
public static SSLContext getInstance( String protocol, String provider) throws NoSuchAlgorithmException, NoSuchProviderException
{
SSLContext sslCtx = SSLContext.getInstance( protocol, provider);
init( sslCtx);
return sslCtx;
}
/**
* Set NaiveTrustManager to the given context.
*/
private static void init( SSLContext context)
{
try
{
// Set NaiveTrustManager.
context.init( null, new TrustManager[] { new NaiveTrustManager() }, new java.security.SecureRandom());
System.out.println( "------------- Initialisation du NaiveSSLContext ---------------------");
}
catch( java.security.KeyManagementException e)
{
throw new RuntimeException( "Failed to initialize an SSLContext.", e);
}
}
/**
* A {@link TrustManager} which trusts all certificates naively.
*/
private static class NaiveTrustManager implements X509TrustManager
{
@Override
public X509Certificate[] getAcceptedIssuers()
{
System.out.println( "------------- NaiveTrustManager.getAcceptedIssuers() ---------------------");
return null;
}
@Override
public void checkClientTrusted( X509Certificate[] certs, String authType)
{
System.out.println( "------------- NaiveTrustManager.checkClientTrusted( " + certs.toString() + ", " + authType
+ ") ---------------------");
}
@Override
public void checkServerTrusted( X509Certificate[] certs, String authType)
{
System.out.println( "------------- NaiveTrustManager.checkServerTrusted( " + certs.toString() + ", " + authType
+ ") ---------------------");
}
}
}
还有另一个类NaiveSSLSocketFactory:
package fr.csf.ssl;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
public class NaiveSSLSocketFactory extends javax.net.ssl.SSLSocketFactory
{
private javax.net.ssl.SSLSocketFactory factory;
public NaiveSSLSocketFactory() throws NoSuchAlgorithmException
{
javax.net.ssl.SSLContext sslCtx = NaiveSSLContext.getInstance( "SSL");
factory = sslCtx.getSocketFactory();
}
private final String[] enabledProtocols = new String[]
{ "SSLv3", "TLSv1" };
@Override
public Socket createSocket( Socket s, String host, int port, boolean autoClose) throws IOException
{
Socket socket = factory.createSocket( s, host, port, autoClose);
((javax.net.ssl.SSLSocket) socket).setEnabledProtocols( enabledProtocols);
return socket;
}
@Override
public Socket createSocket( String host, int port) throws IOException, UnknownHostException
{
Socket socket = factory.createSocket( host, port);
((javax.net.ssl.SSLSocket) socket).setEnabledProtocols( enabledProtocols);
return socket;
}
@Override
public Socket createSocket( InetAddress host, int port) throws IOException
{
Socket socket = factory.createSocket( host, port);
((javax.net.ssl.SSLSocket) socket).setEnabledProtocols( enabledProtocols);
return socket;
}
@Override
public Socket createSocket( String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException
{
Socket socket = factory.createSocket( host, port, localHost, localPort);
((javax.net.ssl.SSLSocket) socket).setEnabledProtocols( enabledProtocols);
return socket;
}
@Override
public Socket createSocket( InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException
{
Socket socket = factory.createSocket( address, port, localAddress, localPort);
((javax.net.ssl.SSLSocket) socket).setEnabledProtocols( enabledProtocols);
return socket;
}
@Override
public String[] getDefaultCipherSuites()
{
String[] cipherSuites = factory.getDefaultCipherSuites();
return cipherSuites;
}
@Override
public String[] getSupportedCipherSuites()
{
String[] cipherSuites = factory.getSupportedCipherSuites();
return cipherSuites;
}
}
问题是我不知道如何让 JVM 使用我的 Naive* 类而不是默认类。我尝试了不同的方法,但它们都不起作用:
第一次尝试:
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory( new NaiveSSLSocketFactory());
我在 checkClientTruted 方法中的日志跟踪从不显示。似乎我的 NaiveSSLSocketFactory 从未被调用过。
第二次尝试:
java.security.Security.setProperty( "ssl.SocketFactory.provider", new NaiveSSLSocketFactory().getClass().getName());
由于 ClassLoader 问题,我遇到了 ClassNotFoundException,但在解决此问题后,同样的问题仍然存在。
我最终找到了一个博客,上面说 CXF 客户端必须做更多的配置工作:
<http-conf:conduit name="*.http-conduit" >
<http-conf:tlsClientParameters
useHttpsURLConnectionDefaultSslSocketFactory="true"
/>
</http-conf:conduit>
由于我使用的是 Tomee1.6 服务器,所以我的程序是一个 CXF 客户端。所以这一定是解决方案。但是我必须在哪里写这个配置属性?我在 Tomee 中找不到任何与 CXF 相关的 xml 文件。只有一个 cxf.properties 文件,几乎是空的。
【问题讨论】:
-
不是重复的。我不问如何编写绕过证书控制的类。我已经写了它们,并在我的帖子中提供了它们。我认为它们是正确的,因为它们看起来就像我在专业网站上找到的一样。我问我如何告诉我的服务器(Tomeeplus v1.6)使用它们。由于它使用 CXF,我相信有一个配置属性需要更改,但我不知道是哪个,也不知道它在哪里。
标签: java web-services ssl cxf apache-tomee