/*
* 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.security.scan;
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;
import org.apache.xmlbeans.XmlAnySimpleType;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.impl.schema.SchemaTypeImpl;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
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 -");
}
}
}