/*
* 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.List;
import java.util.Stack;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.apache.xmlbeans.XmlAnySimpleType;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.impl.schema.SchemaTypeImpl;
import com.eviware.soapui.SoapUI;
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.AbstractBoundary;
import com.eviware.soapui.security.boundary.BoundaryRestrictionUtill;
import com.eviware.soapui.security.boundary.enumeration.EnumerationValues;
import com.eviware.soapui.support.SecurityScanUtil;
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 BoundarySecurityScan extends AbstractSecurityScanWithProperties
{
public static final String TYPE = "BoundaryScan";
public static final String NAME = "Boundary Scan";
private static final String REQUEST_MUTATIONS_STACK = "RequestMutationsStack";
private RestrictionLabel restrictionLabel = new RestrictionLabel();
StrategyTypeConfig.Enum strategy = StrategyTypeConfig.ONE_BY_ONE;
public BoundarySecurityScan( TestStep testStep, SecurityScanConfig config, ModelItem parent, String icon )
{
super( testStep, config, parent, icon );
}
@Override
public JComponent getComponent()
{
JPanel panel = UISupport.createEmptyPanel( 5, 75, 0, 5 );
panel.add( restrictionLabel.getJLabel(), BorderLayout.CENTER );
return panel;
}
@Override
public String getType()
{
return TYPE;
}
@Override
protected void execute( SecurityTestRunner securityTestRunner, TestStep testStep, SecurityTestRunContext context )
{
PropertyMutation mutation = popMutation( context );
if( mutation != null )
{
updateRequestProperty( testStep, mutation );
MessageExchange message = ( MessageExchange )testStep.run( ( TestCaseRunner )securityTestRunner, context );
createMessageExchange( mutation.getMutatedParameters(), message, context );
}
}
@SuppressWarnings( "unchecked" )
private PropertyMutation popMutation( SecurityTestRunContext context )
{
Stack<PropertyMutation> requestMutationsStack = ( Stack<PropertyMutation> )context.get( REQUEST_MUTATIONS_STACK );
return requestMutationsStack.empty() ? null : requestMutationsStack.pop();
}
private void extractMutations( TestStep testStep, SecurityTestRunContext context ) throws XmlException, Exception
{
strategy = getExecutionStrategy().getStrategy();
XmlObjectTreeModel model = null;// getXmlObjectTreeModel( testStep );
List<SecurityCheckedParameter> scpList = getParameterHolder().getParameterList();
StringToStringMap stsmap = new StringToStringMap();
for( SecurityCheckedParameter scp : scpList )
{
if( scp.isChecked() && scp.getXpath().trim().length() > 0 )
{
XmlTreeNode[] treeNodes = null;
if( strategy.equals( StrategyTypeConfig.ONE_BY_ONE ) )
{
stsmap = new StringToStringMap();
model = SecurityScanUtil.getXmlObjectTreeModel( testStep, scp );
}
else
{
if( model == null )
{
model = SecurityScanUtil.getXmlObjectTreeModel( testStep, scp );
}
}
treeNodes = model.selectTreeNodes( context.expand( scp.getXpath() ) );
if( treeNodes.length > 0 )
{
XmlTreeNode mynode = treeNodes[0];
if( mynode.isLeaf() )
{
if( mynode.getSchemaType() != null && mynode.getSchemaType().getEnumerationValues() != null
&& mynode.getSchemaType().getEnumerationValues().length > 0 )
{
EnumerationValues nodeInfo = new EnumerationValues( mynode.getSchemaType().getBaseType()
.getShortJavaName() );
for( XmlAnySimpleType s : mynode.getSchemaType().getEnumerationValues() )
{
nodeInfo.addValue( s.getStringValue() );
}
updateEnumNodeValue( mynode, nodeInfo );
stsmap.put( scp.getLabel(), mynode.getNodeText() );
// addToUpdated( context, scp.getLabel(),
// mynode.getNodeText() );
if( strategy.equals( StrategyTypeConfig.ONE_BY_ONE ) )
{
PropertyMutation pm = new PropertyMutation();
pm.setPropertyName( scp.getName() );
pm.setPropertyValue( model.getXmlObject().toString() );
stsmap = new StringToStringMap();
stsmap.put( scp.getLabel(), mynode.getNodeText() );
pm.setMutatedParameters( stsmap );
addMutation( context, pm );
}
}
else
{
SchemaTypeImpl simpleType = ( SchemaTypeImpl )mynode.getSchemaType();
XmlObjectTreeModel model2 = new XmlObjectTreeModel( simpleType.getTypeSystem(),
simpleType.getParseObject() );
extractRestrictions( model2, context, mynode, model, scp, stsmap );
}
}
}
}
}
if( model != null && strategy.equals( StrategyTypeConfig.ALL_AT_ONCE ) )
{
PropertyMutation pm = new PropertyMutation();
pm.setPropertyName( "Request" );
pm.setPropertyValue( model.getXmlObject().toString() );
pm.setMutatedParameters( stsmap );
addMutation( context, pm );
}
}
@SuppressWarnings( "unchecked" )
private void addMutation( SecurityTestRunContext context, PropertyMutation mutation )
{
Stack<PropertyMutation> stack = ( Stack<PropertyMutation> )context.get( REQUEST_MUTATIONS_STACK );
stack.push( mutation );
}
private void updateRequestProperty( TestStep testStep, PropertyMutation mutation )
{
testStep.getProperty( mutation.getPropertyName() ).setValue( mutation.getPropertyValue() );
}
public String extractRestrictions( XmlObjectTreeModel model2, SecurityTestRunContext context,
XmlTreeNode nodeToUpdate, XmlObjectTreeModel model, SecurityCheckedParameter scp, StringToStringMap stsmap )
throws XmlException, Exception
{
getNextChild( model2.getRootNode(), context, nodeToUpdate, model, scp, stsmap );
return nodeToUpdate.getXmlObject().toString();
}
private void getNextChild( XmlTreeNode node, SecurityTestRunContext context, XmlTreeNode nodeToUpdate,
XmlObjectTreeModel model, SecurityCheckedParameter scp, StringToStringMap stsmap )
{
String baseType = null;
for( int i = 0; i < node.getChildCount(); i++ )
{
XmlTreeNode mynode = node.getChild( i );
if( "xsd:restriction".equals( mynode.getParent().getNodeName() ) )
{
if( mynode.getNodeName().equals( "@base" ) )
{
baseType = mynode.getNodeText();
}
else
{
createMutation( baseType, mynode, context, nodeToUpdate, model, scp, stsmap );
}
}
getNextChild( mynode, context, nodeToUpdate, model, scp, stsmap );
}
}
private void createMutation( String baseType, XmlTreeNode mynode, SecurityTestRunContext context,
XmlTreeNode nodeToUpdate, XmlObjectTreeModel model, SecurityCheckedParameter scp, StringToStringMap stsmap )
{
String value = null;
String nodeName = mynode.getNodeName();
String nodeValue = mynode.getChild( 0 ).getNodeText();
value = AbstractBoundary.outOfBoundaryValue( baseType, nodeName, nodeValue );
if( value != null )
{
nodeToUpdate.setValue( 1, value );
PropertyMutation pm = new PropertyMutation();
pm.setPropertyName( scp.getName() );
pm.setPropertyValue( model.getXmlObject().toString() );
if( strategy.equals( StrategyTypeConfig.ONE_BY_ONE ) )
{
stsmap = new StringToStringMap();
stsmap.put( scp.getLabel() + " (" + nodeName + "='" + nodeValue + "') ", value );
pm.setMutatedParameters( stsmap );
addMutation( context, pm );
}
else
{
stsmap.put( scp.getLabel() + " (" + nodeName + "='" + nodeValue + "') ", value );
}
}
else
{
SoapUI.log.warn( "No out of boundary value is created for restriction " + nodeName + " of baseType:"
+ baseType );
}
}
public void updateEnumNodeValue( XmlTreeNode mynode, EnumerationValues enumerationValues )
{
int size = EnumerationValues.maxLengthStringSize( enumerationValues.getValuesList() );
String value = EnumerationValues.createOutOfBoundaryValue( enumerationValues, size );
if( value != null )
{
mynode.setValue( 1, value );
}
}
/**
* this method uses context to handle list of mutated request
*
*/
@SuppressWarnings( "unchecked" )
protected boolean hasNext( TestStep testStep, SecurityTestRunContext context )
{
if( !context.hasProperty( REQUEST_MUTATIONS_STACK ) )
{
Stack<PropertyMutation> requestMutationsList = new Stack<PropertyMutation>();
context.put( REQUEST_MUTATIONS_STACK, requestMutationsList );
try
{
extractMutations( testStep, context );
}
catch( Exception e )
{
SoapUI.logError( e );
}
return checkIfStackHasContent( context );
}
Stack<PropertyMutation> stack = ( Stack<PropertyMutation> )context.get( REQUEST_MUTATIONS_STACK );
if( stack.empty() )
{
context.remove( REQUEST_MUTATIONS_STACK );
return false;
}
else
{
return true;
}
}
@SuppressWarnings( "unchecked" )
private boolean checkIfStackHasContent( SecurityTestRunContext context )
{
Stack<PropertyMutation> stack = ( Stack<PropertyMutation> )context.get( REQUEST_MUTATIONS_STACK );
if( stack.empty() )
{
context.remove( REQUEST_MUTATIONS_STACK );
return false;
}
else
return true;
}
@Override
public boolean isConfigurable()
{
return true;
}
@Override
public String getConfigDescription()
{
return "Configuration for Boundary Security Scan";
}
@Override
public String getConfigName()
{
return "Configuration for Boundary Security Scan";
}
@Override
public String getHelpURL()
{
return "http://www.soapui.org/Security/boundary-scan.html";
}
public class RestrictionLabel
{
private String text = "";
private JLabel jlabel = new JLabel();
private int limit = 70;
{
setJlabel( text );
}
public void setJlabel( String text )
{
text = text.replace( "[", "" );
text = text.replace( "]", "" );
if( text.length() > limit )
{
jlabel.setToolTipText( text.length() < 250 ? text : text.substring( 0, 249 ) + " ... " );
jlabel.setText( text.substring( 0, limit - 5 ) + " ... " );
}
else
{
jlabel.setText( text );
}
}
public JLabel getJLabel()
{
return jlabel;
}
}
public void refreshRestrictionLabel( int row )
{
if( row == -1 )
{
restrictionLabel.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 )
{
restrictionLabel.setJlabel( "<html><pre> </pre></html>" );
return;
}
List<String> list = null;
if( treeNodes[0].getSchemaType() != null && treeNodes[0].getSchemaType().getEnumerationValues() != null )
{
list = BoundaryRestrictionUtill.extractEnums( treeNodes[0] );
restrictionLabel.setJlabel( list.toString().replaceFirst( ",", "" ) );
}
else
{
SchemaTypeImpl simpleType = ( SchemaTypeImpl )treeNodes[0].getSchemaType();
if( simpleType != null && !simpleType.isNoType() )
{
XmlObjectTreeModel model2 = new XmlObjectTreeModel( simpleType.getTypeSystem(),
simpleType.getParseObject() );
list = BoundaryRestrictionUtill.getRestrictions( model2.getRootNode(), new ArrayList<String>() );
if( list.isEmpty() )
{
list.add( "No restrictions in schema are specified for this parameter!" );
}
restrictionLabel.setJlabel( list.toString() );
}
else
{
restrictionLabel.setJlabel( "parameter is missing type in schema" );
}
}
}
else
{
restrictionLabel.setJlabel( "- no parameter selected -" );
}
}
}