/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wsdl.support.http; import com.eviware.soapui.SoapUI; import com.eviware.soapui.support.StringUtils; import org.apache.commons.ssl.KeyMaterial; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.apache.log4j.Logger; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.X509Certificate; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class SoapUISSLSocketFactory extends SSLSocketFactory { // a cache of factories for custom certificates/Keystores at the project level - never cleared private static final Map<String, SSLSocketFactory> factoryMap = new ConcurrentHashMap<String, SSLSocketFactory>(); private final String sslContextAlgorithm = System.getProperty("soapui.sslcontext.algorithm", "TLS"); private final SSLContext sslContext = SSLContext.getInstance(sslContextAlgorithm); private final static Logger log = Logger.getLogger(SoapUISSLSocketFactory.class); @SuppressWarnings("deprecation") public SoapUISSLSocketFactory(KeyStore keyStore, String keystorePassword) throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException { super(keyStore); // trust everyone! X509TrustManager tm = new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { } }; if (keyStore != null) { KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmfactory.init(keyStore, keystorePassword != null ? keystorePassword.toCharArray() : null); KeyManager[] keymanagers = kmfactory.getKeyManagers(); sslContext.init(keymanagers, new TrustManager[]{tm}, null); } else { sslContext.init(null, new TrustManager[]{tm}, null); } setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); } private static SSLSocket enableSocket(SSLSocket socket) { String invalidateSession = System.getProperty("soapui.https.session.invalidate"); String protocols = System.getProperty("soapui.https.protocols"); String ciphers = System.getProperty("soapui.https.ciphers"); if (StringUtils.hasContent(invalidateSession)) { socket.getSession().invalidate(); } if (StringUtils.hasContent(protocols)) { socket.setEnabledProtocols(protocols.split(",")); } // else if( socket.getSupportedProtocols() != null ) // { // socket.setEnabledProtocols( socket.getSupportedProtocols() ); // } if (StringUtils.hasContent(ciphers)) { socket.setEnabledCipherSuites(ciphers.split(",")); } // else if( socket.getSupportedCipherSuites() != null ) // { // socket.setEnabledCipherSuites( socket.getSupportedCipherSuites() ); // } return socket; } @Override public Socket createSocket(HttpParams params) throws IOException { String sslConfig = (String) params.getParameter(SoapUIHttpRoute.SOAPUI_SSL_CONFIG); if (StringUtils.isNullOrEmpty(sslConfig)) { return enableSocket((SSLSocket) sslContext.getSocketFactory().createSocket()); } SSLSocketFactory factory = factoryMap.get(sslConfig); if (factory != null) { if (factory == this) { return enableSocket((SSLSocket) sslContext.getSocketFactory().createSocket()); } else { return enableSocket((SSLSocket) factory.createSocket(params)); } } try { // try to create new factory for specified config int ix = sslConfig.lastIndexOf(' '); String keyStore = sslConfig.substring(0, ix); String pwd = sslConfig.substring(ix + 1); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); if (keyStore.trim().length() > 0) { File f = new File(keyStore); if (f.exists()) { log.info("Initializing Keystore from [" + keyStore + "]"); try { KeyMaterial km = new KeyMaterial(f, pwd.toCharArray()); ks = km.getKeyStore(); } catch (Exception e) { SoapUI.logError(e); pwd = null; } } } factory = new SoapUISSLSocketFactory(ks, pwd); factoryMap.put(sslConfig, factory); return enableSocket((SSLSocket) factory.createSocket(params)); } catch (Exception gse) { SoapUI.logError(gse); return enableSocket((SSLSocket) super.createSocket(params)); } } /** * @since 4.1 */ @Override public Socket connectSocket(final Socket socket, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException { if (remoteAddress == null) { throw new IllegalArgumentException("Remote address may not be null"); } if (params == null) { throw new IllegalArgumentException("HTTP parameters may not be null"); } Socket sock = socket != null ? socket : new Socket(); if (localAddress != null) { sock.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params)); sock.bind(localAddress); } int connTimeout = HttpConnectionParams.getConnectionTimeout(params); int soTimeout = HttpConnectionParams.getSoTimeout(params); try { sock.setSoTimeout(soTimeout); sock.connect(remoteAddress, connTimeout); } catch (SocketTimeoutException ex) { throw new ConnectTimeoutException("Connect to " + remoteAddress.getHostName() + "/" + remoteAddress.getAddress() + " timed out"); } SSLSocket sslsock; // Setup SSL layering if necessary if (sock instanceof SSLSocket) { sslsock = (SSLSocket) sock; } else { sslsock = (SSLSocket)sslContext.getSocketFactory().createSocket(sock, remoteAddress.getHostName(), remoteAddress.getPort(), true); sslsock = enableSocket(sslsock); } // do we need it? trust all hosts // if( getHostnameVerifier() != null ) // { // try // { // getHostnameVerifier().verify( remoteAddress.getHostName(), sslsock ); // // verifyHostName() didn't blowup - good! // } // catch( IOException iox ) // { // // close the socket before re-throwing the exception // try // { // sslsock.close(); // } // catch( Exception x ) // { /* ignore */ // } // throw iox; // } // } return sslsock; } /** * @since 4.1 */ @Override public Socket createLayeredSocket(final Socket socket, final String host, final int port, final boolean autoClose) throws IOException, UnknownHostException { SSLSocket sslSocket = (SSLSocket)sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); sslSocket = enableSocket(sslSocket); // if( getHostnameVerifier() != null ) // { // getHostnameVerifier().verify( host, sslSocket ); // } // verifyHostName() didn't blowup - good! return sslSocket; } }