/* * 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.tools; import com.eviware.soapui.SoapUI; import com.eviware.soapui.impl.wsdl.WsdlProject; import com.eviware.soapui.impl.wsdl.WsdlTestSuite; import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase; import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner; import com.eviware.soapui.impl.wsdl.teststeps.WsdlRunTestCaseTestStep; import com.eviware.soapui.model.iface.Attachment; import com.eviware.soapui.model.iface.MessageExchange; import com.eviware.soapui.model.project.ProjectFactoryRegistry; import com.eviware.soapui.model.security.SecurityScan; import com.eviware.soapui.model.support.ModelSupport; import com.eviware.soapui.model.testsuite.TestCase; import com.eviware.soapui.model.testsuite.TestCaseRunContext; import com.eviware.soapui.model.testsuite.TestCaseRunner; import com.eviware.soapui.model.testsuite.TestStep; import com.eviware.soapui.model.testsuite.TestStepResult; import com.eviware.soapui.model.testsuite.TestSuite; import com.eviware.soapui.report.JUnitSecurityReportCollector; import com.eviware.soapui.security.SecurityTest; import com.eviware.soapui.security.SecurityTestRunContext; import com.eviware.soapui.security.SecurityTestRunner; import com.eviware.soapui.security.result.SecurityResult; import com.eviware.soapui.security.result.SecurityResult.ResultStatus; import com.eviware.soapui.security.result.SecurityScanRequestResult; import com.eviware.soapui.security.result.SecurityScanResult; import com.eviware.soapui.security.result.SecurityTestStepResult; import com.eviware.soapui.security.support.SecurityTestRunListener; import com.eviware.soapui.security.support.SecurityTestRunListenerAdapter; import com.eviware.soapui.support.StringUtils; import com.eviware.soapui.support.Tools; import org.apache.commons.cli.CommandLine; import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; /** * Standalone security test-runner used from maven-plugin, can also be used from * command-line (see xdocs) or directly from other classes. * <p> * For standalone usage, set the project file (with setProjectFile) and other * desired properties before calling run * </p> * * @author nebojsa.tasic */ public class SoapUISecurityTestRunner extends SoapUITestCaseRunner implements SecurityTestRunListener { public static final String SOAPUI_EXPORT_SEPARATOR = "soapui.export.separator"; public static final String TITLE = "SoapUI " + SoapUI.SOAPUI_VERSION + " Security Test Runner"; private String securityTestName; private int securityTestCount; private int securityScanCount; private int securityScanRequestCount; private int securityScanAlertCount; private List<SecurityTestStepResult> failedResults = new ArrayList<SecurityTestStepResult>(); private JUnitSecurityReportCollector reportCollector = new JUnitSecurityReportCollector(); /** * Runs the tests in the specified soapUI project file, see SoapUI xdocs for * details. * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { System.exit(new SoapUISecurityTestRunner().runFromCommandLine(args)); } protected boolean processCommandLine(CommandLine cmd) { if (cmd.hasOption("n")) { setSecurityTestName(cmd.getOptionValue("n")); } return super.processCommandLine(cmd); } public void setSecurityTestName(String securityTestName) { this.securityTestName = securityTestName; } protected SoapUIOptions initCommandLineOptions() { SoapUIOptions options = super.initCommandLineOptions(); options.addOption("n", true, "Sets the security test name"); return options; } public SoapUISecurityTestRunner() { super(SoapUISecurityTestRunner.TITLE); } public SoapUISecurityTestRunner(String title) { super(title); } public boolean runRunner() throws Exception { initGroovyLog(); getAssertions().clear(); String projectFile = getProjectFile(); WsdlProject project = (WsdlProject) ProjectFactoryRegistry.getProjectFactory("wsdl").createNew(projectFile, getProjectPassword()); if (project.isDisabled()) { throw new Exception("Failed to load SoapUI project file [" + projectFile + "]"); } initProject(project); ensureOutputFolder(project); log.info("Running SoapUI tests in project [" + project.getName() + "]"); String testSuite = getTestSuite(); String testCase = getTestCase(); long startTime = System.nanoTime(); List<TestCase> testCasesToRun = new ArrayList<TestCase>(); // start by listening to all testcases.. (since one testcase can call // another) for (int c = 0; c < project.getTestSuiteCount(); c++) { TestSuite suite = project.getTestSuiteAt(c); for (int i = 0; i < suite.getTestCaseCount(); i++) { TestCase tc = suite.getTestCaseAt(i); if ((testSuite == null || suite.getName().equals(suite.getName())) && testCase != null && tc.getName().equals(testCase)) { testCasesToRun.add(tc); } addListeners(tc); } } // decide what to run if (testCasesToRun.size() > 0) { for (TestCase tc : testCasesToRun) { runTestCase((WsdlTestCase) tc); } } else if (testSuite != null) { WsdlTestSuite ts = project.getTestSuiteByName(testSuite); if (ts == null) { throw new Exception("TestSuite with name [" + testSuite + "] not found in project"); } else { runSuite(ts); } } else { runProject(project); } long timeTaken = (System.nanoTime() - startTime) / 1000000; if (isPrintReport()) { printReport(timeTaken); } exportReports(project); if (isSaveAfterRun() && !project.isRemote()) { try { project.save(); } catch (Throwable t) { log.error("Failed to save project", t); } } if (securityScanAlertCount > 0 && !isIgnoreErrors()) { throw new Exception("SecurityTest execution failed with " + securityScanAlertCount + " alert" + (securityScanAlertCount > 1 ? "s" : "")); } return true; } protected void runProject(WsdlProject project) { try { log.info(("Running Project [" + project.getName() + "], runType = " + project.getRunType())); for (TestSuite testSuite : project.getTestSuiteList()) { runSuite((WsdlTestSuite) testSuite); } } catch (Exception e) { e.printStackTrace(); } } protected void initProject(WsdlProject project) throws Exception { initProjectProperties(project); } protected void exportReports(WsdlProject project) throws Exception { if (isJUnitReport()) { exportJUnitReports(reportCollector, getAbsoluteOutputFolder(project), project); } } protected void addListeners(TestCase tc) { tc.addTestRunListener(this); if (isJunitReport()) { tc.addTestRunListener(reportCollector); } } public void exportJUnitReports(JUnitSecurityReportCollector collector, String folder, WsdlProject project) throws Exception { collector.saveReports(folder == null ? "" : folder); } public void printReport(long timeTaken) { System.out.println(); System.out.println("SoapUI " + SoapUI.SOAPUI_VERSION + " Security TestCaseRunner Summary"); System.out.println("-----------------------------"); System.out.println("Time Taken: " + timeTaken + "ms"); System.out.println("Total SecurityTests: " + securityTestCount); System.out.println("Total SecurityScans: " + securityScanCount); System.out.println("Total SecurityScan Requests: " + securityScanRequestCount); System.out.println("Total Failed SecurityScan Requests: " + securityScanAlertCount); } /** * Run tests in the specified TestSuite * * @param suite the TestSuite to run */ protected void runSuite(WsdlTestSuite suite) { try { for (TestCase testCase : suite.getTestCaseList()) { runTestCase((WsdlTestCase) testCase); } } catch (Exception e) { e.printStackTrace(); } } /** * Runs the SecurityTests in the specified TestCase * * @param testCase the testcase to run * @param context */ protected void runTestCase(WsdlTestCase testCase) { try { for (SecurityTest securityTest : testCase.getSecurityTestList()) { securityTest.addSecurityTestRunListener(this); if (StringUtils.isNullOrEmpty(securityTestName) || securityTest.getName().equals(securityTestName)) { runSecurityTest(securityTest); } } } catch (Exception e) { e.printStackTrace(); } } /** * @param securityTest */ protected void runSecurityTest(SecurityTest securityTest) { securityTest.addSecurityTestRunListener(new SecurityTestRunListenerAdapter() { private int requestIndex = 0; @Override public void afterSecurityScanRequest(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityScanRequestResult securityCheckReqResult) { securityScanRequestCount++; if (securityCheckReqResult.getStatus() == ResultStatus.FAILED) { securityScanAlertCount++; } log.info(securityCheckReqResult.getSecurityScan().getName() + " - " + securityCheckReqResult.getChangedParamsInfo(++requestIndex)); } @Override public void afterSecurityScan(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityScanResult securityCheckResult) { securityScanCount++; } @Override public void beforeSecurityScan(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityScan securityCheck) { requestIndex = 0; } @Override public void afterStep(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityTestStepResult result) { if (result.getStatus() == ResultStatus.FAILED) { failedResults.add(result); } } }); if (isJUnitReport()) { securityTest.addSecurityTestRunListener(reportCollector); } log.info("Running SecurityTest [" + securityTest.getName() + "] in TestCase [" + securityTest.getTestCase().getName() + "] in TestSuite [" + securityTest.getTestCase().getTestSuite().getName() + "]"); SecurityTestRunner runner = securityTest.run(null, false); // log.info( "\n" + securityTest.getSecurityTestLog().getMessages() ); log.info("SecurityTest [" + securityTest.getName() + "] finished with status [" + runner.getStatus() + "] in " + (runner.getTimeTaken()) + "ms"); if (isJUnitReport()) { securityTest.removeSecurityTestRunListener(reportCollector); } } @Override public void afterStep(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityTestStepResult result) { if (!isPrintReport()) { return; } TestStep currentStep = runContext.getCurrentStep(); String securityTestName = ""; String securityScanName = ""; if (!result.getSecurityScanResultList().isEmpty()) { securityTestName = result.getSecurityScanResultList().get(0).getSecurityScan().getParent().getName(); securityScanName = result.getSecurityScanResultList().get(0).getSecurityScanName(); } String countPropertyName = currentStep.getName() + " run count"; Long count = new Long(getExportCount());// ( Long // )runContext.getProperty( // countPropertyName ); if (count == null) { count = new Long(0); } runContext.setProperty(countPropertyName, new Long(count.longValue() + 1)); if (result.getStatus() == SecurityResult.ResultStatus.FAILED || isExportAll()) { try { String exportSeparator = System.getProperty(SOAPUI_EXPORT_SEPARATOR, "-"); TestCase tc = currentStep.getTestCase(); String nameBase = StringUtils.createFileName(securityTestName, '_') + exportSeparator + StringUtils.createFileName(securityScanName, '_') + exportSeparator + StringUtils.createFileName(tc.getTestSuite().getName(), '_') + exportSeparator + StringUtils.createFileName(tc.getName(), '_') + exportSeparator + StringUtils.createFileName(currentStep.getName(), '_') + "-" + count.longValue() + "-" + result.getStatus(); WsdlTestCaseRunner callingTestCaseRunner = (WsdlTestCaseRunner) runContext .getProperty("#CallingTestCaseRunner#"); if (callingTestCaseRunner != null) { WsdlTestCase ctc = callingTestCaseRunner.getTestCase(); WsdlRunTestCaseTestStep runTestCaseTestStep = (WsdlRunTestCaseTestStep) runContext .getProperty("#CallingRunTestCaseStep#"); nameBase = StringUtils.createFileName(securityTestName, '_') + exportSeparator + StringUtils.createFileName(ctc.getTestSuite().getName(), '_') + exportSeparator + StringUtils.createFileName(ctc.getName(), '_') + exportSeparator + StringUtils.createFileName(runTestCaseTestStep.getName(), '_') + exportSeparator + StringUtils.createFileName(tc.getTestSuite().getName(), '_') + exportSeparator + StringUtils.createFileName(tc.getName(), '_') + exportSeparator + StringUtils.createFileName(currentStep.getName(), '_') + "-" + count.longValue() + "-" + result.getStatus(); } String absoluteOutputFolder = getAbsoluteOutputFolder(ModelSupport.getModelItemProject(tc)); String fileName = absoluteOutputFolder + File.separator + nameBase + ".txt"; if (result.getStatus() == SecurityResult.ResultStatus.FAILED) { log.error(currentStep.getName() + " failed, exporting to [" + fileName + "]"); } File file = new File(fileName); file.getParentFile().mkdirs(); PrintWriter writer = new PrintWriter(file); result.writeTo(writer); writer.close(); // write attachments if (result instanceof MessageExchange) { Attachment[] attachments = ((MessageExchange) result).getResponseAttachments(); if (attachments != null && attachments.length > 0) { for (int c = 0; c < attachments.length; c++) { fileName = nameBase + "-attachment-" + (c + 1) + "."; Attachment attachment = attachments[c]; String contentType = attachment.getContentType(); if (!"application/octet-stream".equals(contentType) && contentType != null && contentType.indexOf('/') != -1) { fileName += contentType.substring(contentType.lastIndexOf('/') + 1); } else { fileName += "dat"; } fileName = absoluteOutputFolder + File.separator + fileName; FileOutputStream outFile = new FileOutputStream(fileName); Tools.writeAll(outFile, attachment.getInputStream()); outFile.close(); } } } setExportCount(getExportCount() + 1); } catch (Exception e) { log.error("Error saving failed result: " + e, e); } } setTestStepCount(getTestStepCount() + 1); } public void afterRun(TestCaseRunner testRunner, TestCaseRunContext runContext) { } @Override public void afterOriginalStep(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityTestStepResult result) { // TODO Auto-generated method stub } @Override public void afterRun(TestCaseRunner testRunner, SecurityTestRunContext runContext) { // TODO Auto-generated method stub } @Override public void afterSecurityScan(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityScanResult securityScanResult) { // TODO Auto-generated method stub } @Override public void afterSecurityScanRequest(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityScanRequestResult securityScanReqResult) { // TODO Auto-generated method stub } @Override public void beforeRun(TestCaseRunner testRunner, SecurityTestRunContext runContext) { // TODO Auto-generated method stub } @Override public void beforeSecurityScan(TestCaseRunner testRunner, SecurityTestRunContext runContext, SecurityScan securityScan) { // TODO Auto-generated method stub } @Override public void beforeStep(TestCaseRunner testRunner, SecurityTestRunContext runContext, TestStepResult testStepResult) { // TODO Auto-generated method stub } }