/*
* 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.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.config.MaliciousAttachmentConfig;
import com.eviware.soapui.config.MaliciousAttachmentElementConfig;
import com.eviware.soapui.config.MaliciousAttachmentSecurityScanConfig;
import com.eviware.soapui.config.SecurityScanConfig;
import com.eviware.soapui.config.StrategyTypeConfig;
import com.eviware.soapui.impl.support.AbstractHttpRequest;
import com.eviware.soapui.impl.wsdl.AttachmentContainer;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.iface.Attachment;
import com.eviware.soapui.model.iface.MessageExchange;
import com.eviware.soapui.model.testsuite.TestCaseRunner;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.security.SecurityTestRunContext;
import com.eviware.soapui.security.SecurityTestRunner;
import com.eviware.soapui.security.tools.RandomFile;
import com.eviware.soapui.security.ui.MaliciousAttachmentAdvancedSettingsPanel;
import com.eviware.soapui.security.ui.MaliciousAttachmentMutationsPanel;
import com.eviware.soapui.support.UISupport;
public class MaliciousAttachmentSecurityScan extends AbstractSecurityScan implements PropertyChangeListener {
public static final String TYPE = "MaliciousAttachmentSecurityScan";
public static final String NAME = "Malicious Attachment";
private MaliciousAttachmentSecurityScanConfig config;
private MaliciousAttachmentAdvancedSettingsPanel advancedSettingsPanel;
private MaliciousAttachmentMutationsPanel mutationsPanel;
private int elementIndex = -1;
private int valueIndex = -1;
private AbstractHttpRequest<?> request;
public MaliciousAttachmentSecurityScan(TestStep testStep, SecurityScanConfig newConfig, ModelItem parent,
String icon) {
super(testStep, newConfig, parent, icon);
if (newConfig.getConfig() == null || !(newConfig.getConfig() instanceof MaliciousAttachmentSecurityScanConfig)) {
initConfig();
} else {
config = ((MaliciousAttachmentSecurityScanConfig) newConfig.getConfig());
}
request = ((AbstractHttpRequest<?>) getRequest(testStep));
request.addAttachmentsChangeListener(this);
}
/**
* Default malicious attachment configuration
*/
protected void initConfig() {
getConfig().setConfig(MaliciousAttachmentSecurityScanConfig.Factory.newInstance());
config = (MaliciousAttachmentSecurityScanConfig) getConfig().getConfig();
}
private void generateFiles() {
if (config != null) {
for (MaliciousAttachmentElementConfig element : config.getElementList()) {
for (MaliciousAttachmentConfig value : element.getGenerateAttachmentList()) {
File file = new File(value.getFilename());
try {
if (!file.exists() || file.length() == 0) {
file = new RandomFile(value.getSize(), value.getFilename(), value.getContentType()).next();
}
} catch (IOException e) {
SoapUI.logError(e);
}
}
}
}
}
@Override
public void updateSecurityConfig(SecurityScanConfig config) {
super.updateSecurityConfig(config);
if (this.config != null) {
this.config = (MaliciousAttachmentSecurityScanConfig) getConfig().getConfig();
}
if (advancedSettingsPanel != null) {
advancedSettingsPanel.setConfig((MaliciousAttachmentSecurityScanConfig) getConfig().getConfig());
}
if (mutationsPanel != null) {
mutationsPanel.updateConfig((MaliciousAttachmentSecurityScanConfig) getConfig().getConfig());
}
}
public MaliciousAttachmentSecurityScanConfig getMaliciousAttachmentSecurityScanConfig() {
return config;
}
/*
* Set attachments. Strategy determines the number of existing attachments
* used (one/all)
*/
private void updateRequestContent(TestStep testStep, SecurityTestRunContext context) {
if (config.getRequestTimeout() > 0) {
setRequestTimeout(testStep, config.getRequestTimeout());
}
if (getExecutionStrategy().getStrategy() == StrategyTypeConfig.ONE_BY_ONE) {
if (elementIndex == -1) {
elementIndex++;
}
if (elementIndex < config.getElementList().size()) {
MaliciousAttachmentElementConfig element = config.getElementList().get(elementIndex);
removeAttachments(testStep, element.getKey(), false);
if (element.getRemove()) {
removeAttachments(testStep, element.getKey(), true);
}
if (valueIndex < element.getGenerateAttachmentList().size() + element.getReplaceAttachmentList().size() - 1) {
valueIndex++;
addAttachments(testStep, element, valueIndex);
}
if (valueIndex == element.getGenerateAttachmentList().size() + element.getReplaceAttachmentList().size()
- 1) {
valueIndex = -1;
elementIndex++;
}
}
} else if (getExecutionStrategy().getStrategy() == StrategyTypeConfig.ALL_AT_ONCE) {
if (elementIndex == -1) {
elementIndex++;
}
executeAllAtOnce(testStep);
valueIndex++;
}
}
private void executeAllAtOnce(TestStep testStep) {
for (MaliciousAttachmentElementConfig element : config.getElementList()) {
if (element.getRemove()) {
removeAttachments(testStep, element.getKey(), true);
}
int valIndex = valueIndex;
if (valIndex < element.getGenerateAttachmentList().size() + element.getReplaceAttachmentList().size() - 1) {
valIndex++;
addAttachments(testStep, element, valIndex);
}
if (valIndex + 1 > element.getGenerateAttachmentList().size() + element.getReplaceAttachmentList().size() - 1) {
elementIndex++;
}
}
}
private void addAttachments(TestStep testStep, MaliciousAttachmentElementConfig element, int counter) {
if (counter == -1) {
return;
}
boolean generated = false;
List<MaliciousAttachmentConfig> list = null;
if (counter < element.getGenerateAttachmentList().size()) {
generated = true;
list = element.getGenerateAttachmentList();
} else {
list = element.getReplaceAttachmentList();
counter = counter - element.getGenerateAttachmentList().size();
}
MaliciousAttachmentConfig value = list.get(counter);
File file = new File(value.getFilename());
if (value.getEnabled()) {
try {
if (!file.exists()) {
UISupport.showErrorMessage("Missing file: " + file.getName());
return;
}
addAttachment(testStep, file, value.getContentType(), generated, value.getCached());
} catch (IOException e) {
SoapUI.logError(e);
}
}
}
@Override
protected void execute(SecurityTestRunner securityTestRunner, TestStep testStep, SecurityTestRunContext context) {
try {
request.removeAttachmentsChangeListener(this);
generateFiles();
updateRequestContent(testStep, context);
MessageExchange message = (MessageExchange) testStep.run((TestCaseRunner) securityTestRunner, context);
getSecurityScanRequestResult().setMessageExchange(message);
request.addAttachmentsChangeListener(this);
} catch (Exception e) {
SoapUI.logError(e, "[MaliciousAttachmentSecurityScan]Property value is not valid xml!");
reportSecurityScanException("Property value is not XML or XPath is wrong!");
}
}
@Override
public String getType() {
return TYPE;
}
private Attachment addAttachment(TestStep testStep, File file, String contentType, boolean generated, boolean cache)
throws IOException {
AbstractHttpRequest<?> request = (AbstractHttpRequest<?>) getRequest(testStep);
Attachment attach = request.attachFile(file, cache);
attach.setContentType(contentType);
return attach;
}
private void removeAttachments(TestStep testStep, String key, boolean equals) {
List<Attachment> toRemove = new ArrayList<Attachment>();
AbstractHttpRequest<?> request = (AbstractHttpRequest<?>) getRequest(testStep);
for (Attachment attachment : request.getAttachments()) {
if (equals) {
if (attachment.getId().equals(key)) {
toRemove.add(attachment);
}
} else {
if (!attachment.getId().equals(key)) {
toRemove.add(attachment);
}
}
}
for (Attachment remove : toRemove) {
request.removeAttachment(remove);
}
}
private void setRequestTimeout(TestStep testStep, int timeout) {
AbstractHttpRequest<?> request = (AbstractHttpRequest<?>) getRequest(testStep);
request.setTimeout(String.valueOf(timeout));
}
@Override
public JComponent getComponent() {
if (mutationsPanel == null) {
mutationsPanel = new MaliciousAttachmentMutationsPanel(config,
(AbstractHttpRequest<?>) getRequest(getTestStep()));
}
return mutationsPanel.getPanel();
}
@Override
protected boolean hasNext(TestStep testStep, SecurityTestRunContext context) {
AbstractHttpRequest<?> request = (AbstractHttpRequest<?>) getRequest(testStep);
boolean hasNext = request.getAttachmentCount() == 0 ? false : elementIndex < config.getElementList().size();
if (!hasNext) {
elementIndex = -1;
valueIndex = -1;
}
return hasNext;
}
@Override
public String getConfigDescription() {
return "Configures malicious attachment security scan";
}
@Override
public String getConfigName() {
return "Malicious Attachment Security Scan";
}
@Override
public String getHelpURL() {
return "http://soapui.org/Security/malicious-attachment.html";
}
@Override
public JComponent getAdvancedSettingsPanel() {
if (advancedSettingsPanel == null) {
advancedSettingsPanel = new MaliciousAttachmentAdvancedSettingsPanel(config);
}
return advancedSettingsPanel.getPanel();
}
@Override
public void copyConfig(SecurityScanConfig config) {
super.copyConfig(config);
if (advancedSettingsPanel != null) {
advancedSettingsPanel.setConfig((MaliciousAttachmentSecurityScanConfig) getConfig().getConfig());
}
if (mutationsPanel != null) {
mutationsPanel.updateConfig((MaliciousAttachmentSecurityScanConfig) getConfig().getConfig());
}
}
@Override
public void release() {
if (advancedSettingsPanel != null) {
advancedSettingsPanel.release();
}
if (mutationsPanel != null) {
mutationsPanel.release();
}
if (request != null) {
request.removeAttachmentsChangeListener(this);
}
super.release();
}
private void addedAttachment(Attachment attachment) {
if (config != null) {
MaliciousAttachmentElementConfig element = config.addNewElement();
element.setKey(attachment.getId());
}
}
private void removedAttachment(Attachment attachment) {
if (config != null) {
int idx = -1;
for (int i = 0; i < config.getElementList().size(); i++) {
MaliciousAttachmentElementConfig element = config.getElementList().get(i);
if (attachment.getId().equals(element.getKey())) {
idx = i;
break;
}
}
if (idx != -1) {
config.removeElement(idx);
}
}
if (mutationsPanel != null) {
mutationsPanel.getHolder().removeAttachment(attachment.getId());
}
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (AttachmentContainer.ATTACHMENTS_PROPERTY.equals(evt.getPropertyName())) {
if (evt.getOldValue() == null && evt.getNewValue() != null) {
if (evt.getNewValue() instanceof Attachment) {
Attachment attachment = (Attachment) evt.getNewValue();
addedAttachment(attachment);
}
} else if (evt.getOldValue() != null && evt.getNewValue() == null) {
if (evt.getOldValue() instanceof Attachment) {
Attachment attachment = (Attachment) evt.getOldValue();
removedAttachment(attachment);
}
}
}
}
}