/** * WS-Attacker - A Modular Web Services Penetration Testing Framework Copyright * (C) 2014 Christian Mainka * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package wsattacker.http.transport; import com.eviware.soapui.impl.wsdl.WsdlRequest; import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse; import com.eviware.soapui.support.types.StringToStringsMap; import java.io.*; import java.util.*; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; /** * @author Juraj Somorovsky - juraj.somorovsky@rub.de * @version 0.1 */ public class SoapHttpClient { /** * if the connection is closed, the client tries to send the soap message again, max MAX_RETRY_NUMBER times */ private static int MAX_RETRY_NUMBER = 3; /** * holds the current instance of the object */ private static SoapHttpClient currentInstance = null; /** * http client */ private HttpClient client; /** * http post */ private HttpPost post; private static Logger LOG = Logger.getLogger( SoapHttpClient.class ); SoapHttpClient( WsdlRequest request ) { this( request.getEndpoint() ); setSoapUiHeaders( request ); } SoapHttpClient( String destinationUrl ) { this.client = TlsWrapperClient.wrapClient( new DefaultHttpClient() ); this.post = new HttpPost( destinationUrl ); setConfigProxy(); } private void setConfigProxy() { final String protocol = post.getURI().getScheme(); if ( "http".equals( protocol ) || "https".equals( protocol ) ) { final String httpProxyHost = System.getProperty( protocol + ".proxyHost" ); final String proxyPortAsString = System.getProperty( protocol + ".proxyPort" ); if ( httpProxyHost != null && !httpProxyHost.isEmpty() && proxyPortAsString != null && !proxyPortAsString.isEmpty() ) { try { final int httpProxyPort = Integer.parseInt( proxyPortAsString ); if ( httpProxyHost != null && !httpProxyHost.isEmpty() ) { final HttpHost proxy = new HttpHost( httpProxyHost, httpProxyPort, protocol ); client.getParams().setParameter( ConnRoutePNames.DEFAULT_PROXY, proxy ); } } catch ( NumberFormatException e ) { Logger.getLogger( SoapHttpClient.class ).warn( String.format( "Could not set Proxy for %s with value with value '%s'", protocol, proxyPortAsString ), e ); } } } } public static boolean isContentLengthHeader( String name ) { return "Content-Length".equals( name ); } private void setSoapUiHeaders( WsdlRequest request ) { final WsdlResponse response = request.getResponse(); if ( response != null ) { final StringToStringsMap requestBasicHeaders = response.getRequestHeaders(); setHeaders( requestBasicHeaders ); } final StringToStringsMap additionalHeaders = request.getRequestHeaders(); setHeaders( additionalHeaders ); } private void setHeaders( final StringToStringsMap headers ) { for ( Map.Entry<String, List<String>> header : headers.entrySet() ) { String name = header.getKey(); if ( isContentLengthHeader( name ) ) { LOG.debug( "HTTP-Header 'Content-Length' will be recalculated." ); continue; } for ( String value : header.getValue() ) { post.setHeader( name, value ); } } } /** * Get the current soap http client initialized with the URL and wsdl request * * @return */ public static SoapHttpClient getSoapHttpClient() { return currentInstance; } /** * Sends the SOAP message to the initialized endpoint destination * * @param soap * @return * @throws IOException */ public SoapResponse sendSoap( String soap ) throws IOException { final StringEntity httpBody = new StringEntity( soap ); post.setEntity( httpBody ); int maxTries = MAX_RETRY_NUMBER; HttpResponse httpResponse = null; while ( httpResponse == null ) { try { httpResponse = client.execute( post ); } catch ( IOException ex ) { if ( maxTries == 0 ) { throw ex; } else { maxTries--; LOG.warn( ex.getLocalizedMessage() ); LOG.warn( "Trying to send the message once more" ); LOG.debug( ex ); } } } SoapResponse soapResponse = new SoapResponse(); if ( LOG.isDebugEnabled() ) { LOG.debug( httpResponse.getStatusLine() ); } soapResponse.setStatusLine( httpResponse.getStatusLine().toString() ); for ( Header h : httpResponse.getAllHeaders() ) { final String name = h.getName(); final String value = h.getValue(); if ( LOG.isDebugEnabled() ) { final String headerDebug = name + ": " + value; LOG.debug( headerDebug ); } HttpHeader newHeader = new HttpHeader( name, value ); soapResponse.getHeaders().add( newHeader ); } LOG.debug( "waiting for response: " ); final HttpEntity entity = httpResponse.getEntity(); final String charset = EntityUtils.getContentCharSet( entity ); final String responseString = EntityUtils.toString( entity, charset ); soapResponse.setBody( responseString ); return soapResponse; } /** * Shuts down the connection manager and releases all the allocated resources */ public void shutDownConnectionManager() { client.getConnectionManager().shutdown(); } }