当 Axis 传输是默认的 HTTPSender 时,上述解决方案运行良好。此外,知道新的套接字工厂不仅可以用 AxisProperties 替换,还可以用系统属性替换,这很有用,它可以像这样在命令行上传递:
-Dorg.apache.axis.components.net.SecureSocketFactory=your.package.TLSv12JSSESocketFactory
这是我的 TLSv12JSSESocketFactory 的代码:
package your.package;
import java.util.Hashtable;
import java.io.IOException;
import java.net.Socket;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import org.apache.axis.components.net.JSSESocketFactory;
import org.apache.axis.components.net.BooleanHolder;
public class TLSv12JSSESocketFactory extends JSSESocketFactory {
private final String TLS_VERSION_1_2 = "TLSv1.2";
public TLSv12JSSESocketFactory( @SuppressWarnings("rawtypes") Hashtable attributes ) {
super(attributes);
}
@Override
protected void initFactory() throws IOException {
SSLContext context;
try {
context = SSLContext.getInstance( TLS_VERSION_1_2 );
context.init( null, null, null );
sslFactory = context.getSocketFactory();
} catch ( Exception e ) {
throw new IOException( "Could not init SSL factory with TLS context: " + TLS_VERSION_1_2, e );
}
}
@Override
public Socket create( String host, int port, StringBuffer otherHeaders, BooleanHolder useFullURL ) throws Exception {
Socket s = super.create( host, port, otherHeaders, useFullURL );
((SSLSocket) s).setEnabledProtocols( new String[] { TLS_VERSION_1_2 } );
return s;
}
}
在我的情况下,我必须使用 Apache Commons HttpClient 作为传输来更改 Axis 1.4。这涉及创建一个实现接口 SecureProtocolSocketFactory 的类。这是我的代码:
package your.package;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import javax.net.ssl.SSLSocket;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
public class TLSv12HttpsSocketFactory implements SecureProtocolSocketFactory
{
private static final String TLS_VERSION_1_2 = "TLSv1.2";
private final SecureProtocolSocketFactory base;
public TLSv12HttpsSocketFactory( ProtocolSocketFactory base )
{
if ( base == null || !(base instanceof SecureProtocolSocketFactory) ) throw new IllegalArgumentException();
this.base = (SecureProtocolSocketFactory) base;
}
private Socket acceptOnlyTLS12( Socket socket )
{
if ( socket != null && (socket instanceof SSLSocket) ) {
((SSLSocket) socket).setEnabledProtocols( new String[] { TLS_VERSION_1_2 } );
}
return socket;
}
@Override
public Socket createSocket( String host, int port ) throws IOException
{
return acceptOnlyTLS12( base.createSocket(host, port) );
}
@Override
public Socket createSocket( String host, int port, InetAddress localAddress, int localPort ) throws IOException
{
return acceptOnlyTLS12( base.createSocket(host, port, localAddress, localPort) );
}
@Override
public Socket createSocket( String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params ) throws IOException
{
return acceptOnlyTLS12( base.createSocket(host, port, localAddress, localPort, params) );
}
@Override
public Socket createSocket( Socket socket, String host, int port, boolean autoClose ) throws IOException
{
return acceptOnlyTLS12( base.createSocket(socket, host, port, autoClose) );
}
}
但我还必须像这样修改 org.apache.axis.transport.http.CommonsHTTPSender 类(编译时生成一些类文件):
// import the new socket factory
import your.package.TLSv12HttpsSocketFactory;
...
// add this at the end of the initialize() method
// setup to our custom TLSv1.2 socket factory
String scheme = "https";
Protocol baseHttps = Protocol.getProtocol( scheme );
int defaultPort = baseHttps.getDefaultPort();
ProtocolSocketFactory baseFactory = baseHttps.getSocketFactory();
ProtocolSocketFactory customFactory = new TLSv12HttpsSocketFactory( baseFactory );
Protocol customHttps = new Protocol( scheme, customFactory, defaultPort );
Protocol.registerProtocol( scheme, customHttps );