/*
* Copyright 2004-2014 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.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 ->");
}
}
}