/*
* soapUI, copyright (C) 2004-2011 eviware.com
*
* soapUI is free software; you can redistribute it and/or modify it under the
* terms of version 2.1 of the GNU Lesser General Public License as published by
* the Free Software Foundation.
*
* soapUI 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 Lesser General Public License for more details at gnu.org.
*/
package com.eviware.soapui.security.scan;
import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.impl.schema.SchemaTypeImpl;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.config.InvalidSecurityScanConfig;
import com.eviware.soapui.config.SchemaTypeForSecurityScanConfig;
import com.eviware.soapui.config.SecurityScanConfig;
import com.eviware.soapui.config.StrategyTypeConfig;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.iface.MessageExchange;
import com.eviware.soapui.model.security.SecurityCheckedParameter;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
import com.eviware.soapui.model.testsuite.TestProperty;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.security.SecurityTestRunContext;
import com.eviware.soapui.security.SecurityTestRunner;
import com.eviware.soapui.security.boundary.BoundaryRestrictionUtill;
import com.eviware.soapui.security.ui.InvalidTypesTable;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.types.StringToStringMap;
import com.eviware.soapui.support.xml.XmlObjectTreeModel;
import com.eviware.soapui.support.xml.XmlObjectTreeModel.XmlTreeNode;
import com.eviware.soapui.support.xml.XmlUtils;
public class InvalidTypesSecurityScan extends AbstractSecurityScanWithProperties
{
public final static String TYPE = "InvalidTypesSecurityScan";
public final static String NAME = "Invalid Types";
private InvalidTypesForSOAP invalidTypes;
private TypeLabel typeLabel = new TypeLabel();
private InvalidSecurityScanConfig invalidTypeConfig;
private Map<SecurityCheckedParameter, ArrayList<String>> parameterMutations = new HashMap<SecurityCheckedParameter, ArrayList<String>>();
private boolean mutation;
public InvalidTypesSecurityScan( TestStep testStep, SecurityScanConfig config, ModelItem parent, String icon )
{
super( testStep, config, parent, icon );
if( config.getConfig() == null || !( config.getConfig() instanceof InvalidSecurityScanConfig ) )
initInvalidTypesConfig();
else
invalidTypeConfig = ( InvalidSecurityScanConfig )config.getConfig();
}
@Override
public void updateSecurityConfig( SecurityScanConfig config )
{
super.updateSecurityConfig( config );
if( invalidTypeConfig != null )
{
invalidTypeConfig = ( InvalidSecurityScanConfig )getConfig().getConfig();
}
}
public InvalidSecurityScanConfig getInvalidTypeConfig()
{
if( invalidTypeConfig == null || getConfig().getConfig() == null
|| !( getConfig().getConfig() instanceof InvalidSecurityScanConfig ) )
initInvalidTypesConfig();
return invalidTypeConfig;
}
private void initInvalidTypesConfig()
{
getConfig().setConfig( InvalidSecurityScanConfig.Factory.newInstance() );
invalidTypeConfig = ( InvalidSecurityScanConfig )getConfig().getConfig();
invalidTypes = new InvalidTypesForSOAP();
// add all types..
for( int key : invalidTypes.getDefaultTypeMap().keySet() )
{
SchemaTypeForSecurityScanConfig newType = invalidTypeConfig.addNewTypesList();
newType.setValue( invalidTypes.getDefaultTypeMap().get( key ) );
newType.setType( key );
}
}
@Override
public JComponent getAdvancedSettingsPanel()
{
return new InvalidTypesTable( getInvalidTypeConfig() );
}
/*
* There is no advanced settings/special for this security scan (non-Javadoc)
*
* @see com.eviware.soapui.security.scan.AbstractSecurityScan#getComponent()
*/
@Override
public JComponent getComponent()
{
JPanel panel = UISupport.createEmptyPanel( 5, 75, 0, 5 );
panel.add( typeLabel.getJLabel(), BorderLayout.CENTER );
return panel;
}
@Override
public String getType()
{
return TYPE;
}
@Override
public boolean isConfigurable()
{
return true;
}
@Override
protected void execute( SecurityTestRunner securityTestRunner, TestStep testStep, SecurityTestRunContext context )
{
try
{
StringToStringMap updatedParams = updateRequestContent( testStep, context );
MessageExchange message = ( MessageExchange )testStep.run( ( TestCaseRunner )securityTestRunner, context );
createMessageExchange( updatedParams, message, context );
}
catch( XmlException e )
{
SoapUI.logError( e, "[InvalidtypeSecurityScan]XPath seems to be invalid!" );
reportSecurityScanException( "Property value is not XML or XPath is wrong!" );
}
catch( Exception e )
{
SoapUI.logError( e, "[InvalidtypeSecurityScan]Property value is not valid xml!" );
reportSecurityScanException( "Property value is not XML or XPath is wrong!" );
}
}
/*
* Set new value for request
*/
private StringToStringMap updateRequestContent( TestStep testStep, SecurityTestRunContext context )
throws XmlException, Exception
{
StringToStringMap params = new StringToStringMap();
if( parameterMutations.size() == 0 )
mutateParameters( testStep, context );
if( getExecutionStrategy().getStrategy() == StrategyTypeConfig.ONE_BY_ONE )
{
/*
* Idea is to drain for each parameter mutations.
*/
for( SecurityCheckedParameter param : getParameterHolder().getParameterList() )
{
if( parameterMutations.containsKey( param ) )
if( parameterMutations.get( param ).size() > 0 )
{
TestProperty property = getTestStep().getProperties().get( param.getName() );
String value = context.expand( property.getValue() );
if( param.getXpath() == null || param.getXpath().trim().length() == 0 )
{
testStep.getProperties().get( param.getName() )
.setValue( parameterMutations.get( param ).get( 0 ) );
params.put( param.getLabel(), parameterMutations.get( param ).get( 0 ) );
parameterMutations.get( param ).remove( 0 );
}
else
{
// no value, do nothing.
if( value == null || value.trim().equals( "" ) )
continue;
if( XmlUtils.seemsToBeXml( value ) )
// try
{
// XmlObjectTreeModel model = new XmlObjectTreeModel(
// property.getSchemaType().getTypeSystem(),
// XmlObject.Factory.parse( value ) );
XmlObjectTreeModel model = new XmlObjectTreeModel( property.getSchemaType().getTypeSystem(),
XmlUtils.createXmlObject( value ) );
XmlTreeNode[] nodes = model.selectTreeNodes( context.expand( param.getXpath() ) );
for( XmlTreeNode node : nodes )
node.setValue( 1, parameterMutations.get( param ).get( 0 ) );
params.put( param.getLabel(), parameterMutations.get( param ).get( 0 ) );
parameterMutations.get( param ).remove( 0 );
testStep.getProperties().get( param.getName() ).setValue( model.getXmlObject().toString() );
}
}
break;
}
}
}
else
{
for( TestProperty property : testStep.getPropertyList() )
{
String value = context.expand( property.getValue() );
if( XmlUtils.seemsToBeXml( value ) )
{
XmlObjectTreeModel model = null;
// model = new XmlObjectTreeModel(
// property.getSchemaType().getTypeSystem(),
// XmlObject.Factory.parse( value ) );
model = new XmlObjectTreeModel( property.getSchemaType().getTypeSystem(),
XmlUtils.createXmlObject( value ) );
for( SecurityCheckedParameter param : getParameterHolder().getParameterList() )
{
if( param.getXpath() == null || param.getXpath().trim().length() == 0 )
{
testStep.getProperties().get( param.getName() )
.setValue( parameterMutations.get( param ).get( 0 ) );
params.put( param.getLabel(), parameterMutations.get( param ).get( 0 ) );
parameterMutations.get( param ).remove( 0 );
}
else
{
// no value, do nothing.
if( value == null || value.trim().equals( "" ) )
continue;
if( param.getName().equals( property.getName() ) )
{
XmlTreeNode[] nodes = model.selectTreeNodes( context.expand( param.getXpath() ) );
if( parameterMutations.containsKey( param ) )
if( parameterMutations.get( param ).size() > 0 )
{
for( XmlTreeNode node : nodes )
node.setValue( 1, parameterMutations.get( param ).get( 0 ) );
params.put( param.getLabel(), parameterMutations.get( param ).get( 0 ) );
parameterMutations.get( param ).remove( 0 );
}
}
}
}
if( model != null )
property.setValue( model.getXmlObject().toString() );
}
}
}
return params;
}
/**
* generate set of requests with all variations
*
* @param testStep
* @param context
* @throws Exception
* @throws XmlException
*
* @throws XmlException
*/
private void mutateParameters( TestStep testStep, SecurityTestRunContext context ) throws XmlException, Exception
{
mutation = true;
// for each parameter
for( SecurityCheckedParameter parameter : getParameterHolder().getParameterList() )
{
if( parameter.isChecked() )
{
TestProperty property = getTestStep().getProperties().get( parameter.getName() );
// no xpath, just put invalid type value in parameter value
if( parameter.getXpath() == null || parameter.getXpath().trim().length() == 0 )
{
for( SchemaTypeForSecurityScanConfig invalidType : invalidTypeConfig.getTypesListList() )
{
if( !parameterMutations.containsKey( parameter ) )
parameterMutations.put( parameter, new ArrayList<String>() );
parameterMutations.get( parameter ).add( invalidType.getValue() );
}
}
else
{
// we have xpath but do we have xml which need to mutate
// ignore if there is no value, since than we'll get exception
if( property.getValue() == null && property.getDefaultValue() == null )
continue;
// get value of that property
String value = context.expand( property.getValue() );
if( XmlUtils.seemsToBeXml( value ) )
{
// XmlObjectTreeModel model = new XmlObjectTreeModel(
// property.getSchemaType().getTypeSystem(),
// XmlObject.Factory.parse( value ) );
XmlObjectTreeModel model = new XmlObjectTreeModel( property.getSchemaType().getTypeSystem(),
XmlUtils.createXmlObject( value ) );
XmlTreeNode[] nodes = model.selectTreeNodes( context.expand( parameter.getXpath() ) );
// for each invalid type set all nodes
List<SchemaTypeForSecurityScanConfig> invalidTypes = invalidTypeConfig.getTypesListList();
for( SchemaTypeForSecurityScanConfig type : invalidTypes )
{
if( nodes.length > 0 )
{
if( nodes[0].getSchemaType().getBuiltinTypeCode() != type.getType() )
{
if( !parameterMutations.containsKey( parameter ) )
parameterMutations.put( parameter, new ArrayList<String>() );
parameterMutations.get( parameter ).add( type.getValue() );
}
}
}
}
}
}
}
}
@Override
protected boolean hasNext( TestStep testStep, SecurityTestRunContext context )
{
boolean hasNext = false;
if( ( parameterMutations == null || parameterMutations.size() == 0 ) && !mutation )
{
if( getParameterHolder().getParameterList().size() > 0 )
hasNext = true;
else
hasNext = false;
}
else
{
for( SecurityCheckedParameter param : parameterMutations.keySet() )
{
if( parameterMutations.get( param ).size() > 0 )
{
hasNext = true;
break;
}
}
}
if( !hasNext )
{
parameterMutations.clear();
mutation = false;
}
return hasNext;
}
/**
*
* This is support class that should keep track of all simple types. Also it
* should provide values for creating invalid requests.
*
* @author robert
*
*/
private class InvalidTypesForSOAP
{
private HashMap<Integer, String> typeMap = new HashMap<Integer, String>();
public InvalidTypesForSOAP()
{
generateInvalidTypes();
}
/*
* see http://www.w3.org/TR/xmlschema-0/#CreatDt
*/
private void generateInvalidTypes()
{
// strings
typeMap.put( SchemaType.BTC_STRING, "SoapUI is\t the\r best\n" );
// no cr/lf/tab
typeMap.put( SchemaType.BTC_NORMALIZED_STRING, "SoapUI is the best" );
// no cr/lf/tab
typeMap.put( SchemaType.BTC_TOKEN, "SoapUI is the best" );
// base64Binary
typeMap.put( SchemaType.BTC_BASE_64_BINARY, "GpM7" );
// hexBinary
typeMap.put( SchemaType.BTC_HEX_BINARY, "0FB7" );
// integer - no min or max
typeMap.put( SchemaType.BTC_INTEGER, "-1267896799" );
// positive integer
typeMap.put( SchemaType.BTC_POSITIVE_INTEGER, "1267896799" );
// negative integer
typeMap.put( SchemaType.BTC_NEGATIVE_INTEGER, "-1" );
// non negative integer
typeMap.put( SchemaType.BTC_NON_NEGATIVE_INTEGER, "1" );
// non positive integer
typeMap.put( SchemaType.BTC_NON_POSITIVE_INTEGER, "0" );
// long
typeMap.put( SchemaType.BTC_LONG, "-882223334991111111" );
// unsigned long
typeMap.put( SchemaType.BTC_UNSIGNED_LONG, "882223334991111111" );
// int
typeMap.put( SchemaType.BTC_INT, "-2147483647" );
// unsigned int
typeMap.put( SchemaType.BTC_UNSIGNED_INT, "294967295" );
// short
typeMap.put( SchemaType.BTC_SHORT, "-32768" );
// unsigned short
typeMap.put( SchemaType.BTC_UNSIGNED_SHORT, "65535" );
// byte
typeMap.put( SchemaType.BTC_BYTE, "127" );
// unsigned byte
typeMap.put( SchemaType.BTC_UNSIGNED_BYTE, "255" );
// decimal
typeMap.put( SchemaType.BTC_DECIMAL, "-1.23" );
// float
typeMap.put( SchemaType.BTC_FLOAT, "-1E4f" );
// double
typeMap.put( SchemaType.BTC_DOUBLE, "12.45E+12" );
// boolean
typeMap.put( SchemaType.BTC_BOOLEAN, "true" );
// duration
typeMap.put( SchemaType.BTC_DURATION, "P1Y2M3DT10H30M12.3S" );
// date time
typeMap.put( SchemaType.BTC_DATE_TIME, "1999-05-31T13:20:00.000-05:00" );
// date
typeMap.put( SchemaType.BTC_DATE, "1999-05-31" );
// need to add more...
}
public HashMap<Integer, String> getDefaultTypeMap()
{
return typeMap;
}
}
@Override
public String getConfigDescription()
{
return "Configures invalid type security scan";
}
@Override
public String getConfigName()
{
return "Invalid Types Security Scan";
}
@Override
public String getHelpURL()
{
return "http://soapui.org/Security/invalid-types.html";
}
@Override
protected void clear()
{
parameterMutations.clear();
mutation = false;
}
public class TypeLabel
{
private String text = "<html><pre> </pre></html>";
private JLabel jlabel = new JLabel();
{
setJlabel( text );
}
public void setJlabel( String text )
{
text = text.replace( "[", "" );
text = text.replace( "]", "" );
jlabel.setText( text );
}
public JLabel getJLabel()
{
return jlabel;
}
}
public TypeLabel getTypeLabel()
{
return typeLabel;
}
public void refreshRestrictionLabel( int row )
{
if( row == -1 )
{
typeLabel.setJlabel( "- no parameter selected -" );
return;
}
SecurityCheckedParameter parameter = getParameterAt( row );
if( parameter == null )
{
return;
}
String name = parameter.getName();
String xpath = parameter.getXpath();
TestProperty tp = getTestStep().getProperty( name );
XmlObjectTreeModel xmlObjectTreeModel = null;
if( tp.getSchemaType() != null && XmlUtils.seemsToBeXml( tp.getValue() ) )
{
try
{
// xmlObjectTreeModel = new XmlObjectTreeModel(
// tp.getSchemaType().getTypeSystem(),
// XmlObject.Factory.parse( tp.getValue() ) );
xmlObjectTreeModel = new XmlObjectTreeModel( tp.getSchemaType().getTypeSystem(),
XmlUtils.createXmlObject( tp.getValue() ) );
}
catch( XmlException e )
{
SoapUI.logError( e );
}
XmlTreeNode[] treeNodes = xmlObjectTreeModel.selectTreeNodes( xpath );
if( treeNodes.length == 0 )
{
typeLabel.setJlabel( "" );
return;
}
SchemaTypeImpl simpleType = ( SchemaTypeImpl )treeNodes[0].getSchemaType();
if( simpleType != null && !simpleType.isNoType() )
{
XmlObjectTreeModel model2 = new XmlObjectTreeModel( simpleType.getTypeSystem(), simpleType.getParseObject() );
List<String> list = BoundaryRestrictionUtill.getType( model2.getRootNode(), new ArrayList<String>() );
if( list.isEmpty() )
typeLabel.setJlabel( "parameter has type [" + simpleType.getName() + "]" );
else
typeLabel.setJlabel( "parameter has types [" + list.toString() + "]" );
}
else
{
typeLabel.setJlabel( "parameter is missing type in schema" );
}
}
else
{
typeLabel.setJlabel( "- no parameter selected ->" );
}
}
}