/*
* 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.ui;
import com.eviware.soapui.config.MaliciousAttachmentConfig;
import com.eviware.soapui.config.MaliciousAttachmentElementConfig;
import com.eviware.soapui.config.MaliciousAttachmentSecurityScanConfig;
import com.eviware.soapui.impl.support.AbstractHttpRequest;
import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.model.iface.Attachment;
import com.eviware.soapui.security.support.MaliciousAttachmentFilesListForm;
import com.eviware.soapui.security.support.MaliciousAttachmentGenerateTableModel;
import com.eviware.soapui.security.support.MaliciousAttachmentListToTableHolder;
import com.eviware.soapui.security.support.MaliciousAttachmentReplaceTableModel;
import com.eviware.soapui.security.support.MaliciousAttachmentTableModel;
import com.eviware.soapui.security.tools.AttachmentElement;
import com.eviware.soapui.settings.ProjectSettings;
import com.eviware.soapui.support.HelpActionMarker;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.Tools;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.components.JXToolBar;
import com.eviware.soapui.support.editor.inspectors.attachments.ContentTypeHandler;
import com.eviware.soapui.support.swing.JTableFactory;
import com.eviware.x.form.XFormDialog;
import com.eviware.x.form.XFormField;
import com.eviware.x.form.XFormFieldListener;
import com.eviware.x.form.support.ADialogBuilder;
import com.eviware.x.form.support.AField;
import com.eviware.x.form.support.AField.AFieldType;
import com.eviware.x.form.support.AForm;
import com.eviware.x.impl.swing.JCheckBoxFormField;
import com.eviware.x.impl.swing.JFormDialog;
import com.eviware.x.impl.swing.JTextFieldFormField;
import org.jdesktop.swingx.JXTable;
import javax.activation.MimetypesFileTypeMap;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableCellEditor;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.io.File;
public class MaliciousAttachmentMutationsPanel {
private JFormDialog dialog;
private MaliciousAttachmentSecurityScanConfig config;
private JButton addGeneratedButton;
private JButton removeGeneratedButton;
private JButton addReplacementButton;
private JButton removeReplacementButton;
private AbstractHttpRequest<?> request;
private MaliciousAttachmentListToTableHolder holder = new MaliciousAttachmentListToTableHolder();
private JFormDialog tablesDialog;
public MaliciousAttachmentMutationsPanel(MaliciousAttachmentSecurityScanConfig config,
AbstractHttpRequest<?> request) {
this.config = config;
this.request = request;
dialog = (JFormDialog) ADialogBuilder.buildDialog(MutationSettings.class);
dialog.getFormField(MutationSettings.MUTATIONS_PANEL).setProperty("component", createMutationsPanel());
dialog.getFormField(MutationSettings.MUTATIONS_PANEL).setProperty("dimension", new Dimension(720, 320));
}
private JComponent buildFilesList() {
MaliciousAttachmentFilesListForm filesList = new MaliciousAttachmentFilesListForm(config, holder);
holder.setFilesList(filesList);
JScrollPane scrollPane = new JScrollPane(filesList);
return scrollPane;
}
private JComponent buildTables() {
tablesDialog = (JFormDialog) ADialogBuilder.buildDialog(MutationTables.class);
MaliciousAttachmentTableModel generateTableModel = new MaliciousAttachmentGenerateTableModel();
tablesDialog.getFormField(MutationTables.GENERATE_FILE).setProperty("dimension", new Dimension(410, 120));
tablesDialog.getFormField(MutationTables.GENERATE_FILE).setProperty("component",
buildGenerateTable(generateTableModel));
MaliciousAttachmentTableModel replaceTableModel = new MaliciousAttachmentReplaceTableModel();
tablesDialog.getFormField(MutationTables.REPLACE_FILE).setProperty("dimension", new Dimension(410, 120));
tablesDialog.getFormField(MutationTables.REPLACE_FILE).setProperty("component",
buildReplacementTable(replaceTableModel));
holder.setGenerateTableModel(generateTableModel);
holder.setReplaceTableModel(replaceTableModel);
holder.setTablesDialog(tablesDialog);
JCheckBoxFormField remove = (JCheckBoxFormField) tablesDialog.getFormField(MutationTables.REMOVE_FILE);
remove.addFormFieldListener(new XFormFieldListener() {
@Override
public void valueChanged(XFormField sourceField, String newValue, String oldValue) {
int idx = holder.getFilesList().getList().getSelectedIndex();
if (idx != -1) {
ListModel listModel = holder.getFilesList().getList().getModel();
String key = ((AttachmentElement) listModel.getElementAt(idx)).getId();
for (MaliciousAttachmentElementConfig element : config.getElementList()) {
if (key.equals(element.getKey())) {
element.setRemove(Boolean.parseBoolean(newValue));
break;
}
}
}
}
});
return tablesDialog.getPanel();
}
protected JPanel buildGenerateTable(MaliciousAttachmentTableModel tableModel) {
final JPanel panel = new JPanel(new BorderLayout());
final JXTable table = JTableFactory.getInstance().makeJXTable(tableModel);
setupTable(table);
JScrollPane tableScrollPane = new JScrollPane(table);
tableScrollPane.setBorder(BorderFactory.createEmptyBorder());
JXToolBar toolbar = UISupport.createToolbar();
addGeneratedButton = UISupport.createToolbarButton(new GenerateFileAction());
toolbar.add(addGeneratedButton);
removeGeneratedButton = UISupport.createToolbarButton(new RemoveGeneratedFileAction(tableModel, table));
toolbar.add(removeGeneratedButton);
removeGeneratedButton.setEnabled(false);
toolbar.add(UISupport.createToolbarButton(new HelpAction(HelpUrls.SECURITY_MALICIOUS_ATTACHMENT_HELP)));
panel.add(toolbar, BorderLayout.PAGE_START);
panel.add(tableScrollPane, BorderLayout.CENTER);
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (removeGeneratedButton != null) {
removeGeneratedButton.setEnabled(table.getSelectedRowCount() > 0);
}
}
});
panel.setBorder(BorderFactory.createLineBorder(new Color(0), 1));
return panel;
}
protected JPanel buildReplacementTable(MaliciousAttachmentTableModel tableModel) {
final JPanel panel = new JPanel(new BorderLayout());
final JXTable table = JTableFactory.getInstance().makeJXTable(tableModel);
setupTable(table);
JScrollPane tableScrollPane = new JScrollPane(table);
tableScrollPane.setBorder(BorderFactory.createEmptyBorder());
JXToolBar toolbar = UISupport.createToolbar();
addReplacementButton = UISupport.createToolbarButton(new AddFileAction());
toolbar.add(addReplacementButton);
removeReplacementButton = UISupport.createToolbarButton(new RemoveReplacementFileAction(tableModel, table));
toolbar.add(removeReplacementButton);
removeReplacementButton.setEnabled(false);
toolbar.add(UISupport.createToolbarButton(new HelpAction(HelpUrls.SECURITY_MALICIOUS_ATTACHMENT_HELP)));
panel.add(toolbar, BorderLayout.PAGE_START);
panel.add(tableScrollPane, BorderLayout.CENTER);
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (removeReplacementButton != null) {
removeReplacementButton.setEnabled(table.getSelectedRowCount() > 0);
}
}
});
panel.setBorder(BorderFactory.createLineBorder(new Color(0), 1));
return panel;
}
protected void setupTable(JXTable table) {
table.setPreferredScrollableViewportSize(new Dimension(50, 90));
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getTableHeader().setReorderingAllowed(false);
table.setDefaultEditor(String.class, getDefaultCellEditor());
table.setSortable(false);
}
private Object createMutationsPanel() {
JPanel panel = new JPanel(new BorderLayout());
JSplitPane mainSplit = UISupport.createHorizontalSplit(buildFilesList(), buildTables());
mainSplit.setResizeWeight(1);
panel.add(mainSplit, BorderLayout.CENTER);
return panel;
}
public JComponent getPanel() {
MaliciousAttachmentFilesListForm filesList = holder.getFilesList();
Attachment[] data = new Attachment[request.getAttachments().length];
for (int i = 0; i < request.getAttachments().length; i++) {
data[i] = request.getAttachmentAt(i);
}
filesList.setData(data);
holder.refresh();
return dialog.getPanel();
}
@AForm(description = "Malicious Attachment Mutations", name = "Malicious Attachment Mutations")
public interface MutationSettings {
@AField(description = "###Mutations panel", name = "###Mutations panel", type = AFieldType.COMPONENT)
final static String MUTATIONS_PANEL = "###Mutations panel";
}
@AForm(description = "Malicious Attachment Mutation Tables", name = "Malicious Attachment Mutation Tables")
public interface MutationTables {
@AField(description = "<html><b>Specify below how selected attachment should be mutated</b></html>", name = "###Label", type = AFieldType.LABEL)
final static String LABEL = "###Label";
@AField(description = "Generate file", name = "Generate", type = AFieldType.COMPONENT)
final static String GENERATE_FILE = "Generate";
@AField(description = "Replace file", name = "Replace", type = AFieldType.COMPONENT)
final static String REPLACE_FILE = "Replace";
@AField(description = "Do not send the attachment with the request", name = "Remove", type = AFieldType.BOOLEAN)
final static String REMOVE_FILE = "Remove";
}
@AForm(description = "Generate File Mutation", name = "Generate File Mutation")
public interface GenerateFile {
@AField(description = "Size (bytes)", name = "Size (bytes)", type = AFieldType.INT)
final static String SIZE = "Size (bytes)";
@AField(description = "Content type", name = "Content type", type = AFieldType.STRING)
final static String CONTENT_TYPE = "Content type";
}
public class AddFileAction extends AbstractAction {
private JFileChooser fileChooser;
public AddFileAction() {
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/add.png"));
putValue(Action.SHORT_DESCRIPTION, "Add file");
}
@Override
public void actionPerformed(ActionEvent e) {
if (fileChooser == null) {
fileChooser = new JFileChooser();
}
String root = ProjectSettings.PROJECT_ROOT;
if (StringUtils.hasContent(root)) {
fileChooser.setCurrentDirectory(new File(root));
}
int returnVal = fileChooser.showOpenDialog(UISupport.getMainFrame());
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
Boolean retval = UISupport.confirmOrCancel("Cache attachment in request?", "Add Attachment");
if (retval == null) {
return;
}
String filename = file.getAbsolutePath();
Long size = file.length();
String contentType = new MimetypesFileTypeMap().getContentType(file);
Boolean enabled = new Boolean(true);
Boolean cached = retval;
boolean added = false;
int idx = holder.getFilesList().getList().getSelectedIndex();
if (idx != -1) {
ListModel listModel = holder.getFilesList().getList().getModel();
String key = ((AttachmentElement) listModel.getElementAt(idx)).getId();
for (MaliciousAttachmentElementConfig element : config.getElementList()) {
if (key.equals(element.getKey())) {
MaliciousAttachmentConfig att = element.addNewReplaceAttachment();
att.setFilename(filename);
att.setSize(size);
att.setContentType(contentType);
att.setEnabled(enabled);
att.setCached(cached);
holder.addResultToReplaceTable(att);
added = true;
}
}
}
if (!added) {
UISupport.showErrorMessage("No attachments found in test step");
}
}
}
}
public class GenerateFileAction extends AbstractAction {
private XFormDialog dialog;
public GenerateFileAction() {
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/add.png"));
putValue(Action.SHORT_DESCRIPTION, "Generate file");
}
@Override
public void actionPerformed(ActionEvent e) {
if (dialog == null) {
dialog = ADialogBuilder.buildDialog(GenerateFile.class);
((JTextFieldFormField) dialog.getFormField(GenerateFile.CONTENT_TYPE)).setWidth(30);
}
dialog.show();
if (dialog.getReturnValue() == XFormDialog.OK_OPTION) {
Long newSize = 0L;
String newSizeString = dialog.getValue(GenerateFile.SIZE);
String contentType = dialog.getFormField(GenerateFile.CONTENT_TYPE).getValue();
try {
newSize = Long.parseLong(newSizeString);
} catch (NumberFormatException nfe) {
UISupport.showErrorMessage("Size must be numeric value");
return;
}
try {
File file = File.createTempFile(StringUtils.createFileName("attachment", '-'), "."
+ ContentTypeHandler.getExtensionForContentType(contentType));
String filename = file.getAbsolutePath();
Boolean enabled = new Boolean(true);
Boolean cached = new Boolean(true);
boolean added = false;
int idx = holder.getFilesList().getList().getSelectedIndex();
if (idx != -1) {
ListModel listModel = holder.getFilesList().getList().getModel();
String key = ((AttachmentElement) listModel.getElementAt(idx)).getId();
for (MaliciousAttachmentElementConfig element : config.getElementList()) {
if (key.equals(element.getKey())) {
MaliciousAttachmentConfig att = element.addNewGenerateAttachment();
att.setFilename(filename);
att.setSize(newSize);
att.setContentType(contentType);
att.setEnabled(enabled);
att.setCached(cached);
holder.addResultToGenerateTable(att);
added = true;
}
}
}
if (!added) {
UISupport.showErrorMessage("No attachments found in test step");
}
} catch (Exception e1) {
UISupport.showErrorMessage(e1);
}
}
}
}
public class RemoveReplacementFileAction extends AbstractAction {
private final MaliciousAttachmentTableModel tableModel;
private final JXTable table;
public RemoveReplacementFileAction(MaliciousAttachmentTableModel tableModel, JXTable table) {
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/delete.png"));
putValue(Action.SHORT_DESCRIPTION, "Remove file");
this.tableModel = tableModel;
this.table = table;
}
@Override
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
if (row >= 0) {
tableModel.removeResult(row);
int idx = holder.getFilesList().getList().getSelectedIndex();
if (idx != -1) {
ListModel listModel = holder.getFilesList().getList().getModel();
String key = ((AttachmentElement) listModel.getElementAt(idx)).getId();
for (int i = 0; i < config.getElementList().size(); i++) {
MaliciousAttachmentElementConfig element = config.getElementList().get(i);
if (key.equals(element.getKey())) {
element.getReplaceAttachmentList().remove(row);
}
}
}
}
}
}
public class RemoveGeneratedFileAction extends AbstractAction {
private final MaliciousAttachmentTableModel tableModel;
private final JXTable table;
public RemoveGeneratedFileAction(MaliciousAttachmentTableModel tableModel, JXTable table) {
putValue(Action.SMALL_ICON, UISupport.createImageIcon("/delete.png"));
putValue(Action.SHORT_DESCRIPTION, "Remove file");
this.tableModel = tableModel;
this.table = table;
}
@Override
public void actionPerformed(ActionEvent e) {
int row = table.getSelectedRow();
if (row >= 0) {
tableModel.removeResult(row);
int idx = holder.getFilesList().getList().getSelectedIndex();
if (idx != -1) {
ListModel listModel = holder.getFilesList().getList().getModel();
String key = ((AttachmentElement) listModel.getElementAt(idx)).getId();
for (int i = 0; i < config.getElementList().size(); i++) {
MaliciousAttachmentElementConfig element = config.getElementList().get(i);
if (key.equals(element.getKey())) {
element.getGenerateAttachmentList().remove(row);
}
}
}
}
}
}
public class HelpAction extends AbstractAction implements HelpActionMarker {
private final String url;
public HelpAction(String url) {
this("Online Help", url, UISupport.getKeyStroke("F1"));
}
public HelpAction(String title, String url) {
this(title, url, null);
}
public HelpAction(String title, String url, KeyStroke accelerator) {
super(title);
this.url = url;
putValue(Action.SHORT_DESCRIPTION, "Show online help");
if (accelerator != null) {
putValue(Action.ACCELERATOR_KEY, accelerator);
}
putValue(Action.SMALL_ICON, UISupport.HELP_ICON);
}
@Override
public void actionPerformed(ActionEvent e) {
Tools.openURL(url);
}
}
protected TableCellEditor getDefaultCellEditor() {
return new XPathCellRender();
}
public MaliciousAttachmentSecurityScanConfig getConfig() {
return config;
}
public void setConfig(MaliciousAttachmentSecurityScanConfig config) {
this.config = config;
}
public void updateConfig(MaliciousAttachmentSecurityScanConfig config) {
setConfig(config);
MaliciousAttachmentFilesListForm filesList = holder.getFilesList();
if (filesList != null) {
filesList.updateConfig(config);
}
}
public MaliciousAttachmentListToTableHolder getHolder() {
return holder;
}
public void release() {
tablesDialog.release();
dialog.release();
config = null;
dialog = null;
request = null;
holder.release();
holder = null;
}
}