/* * 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; import com.eviware.soapui.SoapUI; import com.eviware.soapui.config.TestStepConfig; import com.eviware.soapui.impl.wsdl.support.AbstractTestCaseRunner; import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase; import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestStep; import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestStepFactory; import com.eviware.soapui.impl.wsdl.teststeps.registry.WsdlTestStepRegistry; import com.eviware.soapui.model.security.SecurityScan; import com.eviware.soapui.model.testsuite.Assertable; import com.eviware.soapui.model.testsuite.TestAssertion; import com.eviware.soapui.model.testsuite.TestStep; import com.eviware.soapui.model.testsuite.TestStepResult; import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus; import com.eviware.soapui.security.result.SecurityResult.ResultStatus; import com.eviware.soapui.security.result.SecurityScanResult; import com.eviware.soapui.security.result.SecurityTestStepResult; import com.eviware.soapui.security.scan.AbstractSecurityScanWithProperties; import com.eviware.soapui.security.support.SecurityTestRunListener; import com.eviware.soapui.support.types.StringToObjectMap; import java.util.Arrays; import java.util.List; import java.util.Map; public class SecurityTestRunnerImpl extends AbstractTestCaseRunner<SecurityTest, SecurityTestRunContext> implements SecurityTestRunner { private SecurityTest securityTest; // private boolean stopped; private SecurityTestRunListener[] securityTestListeners = new SecurityTestRunListener[0]; private SecurityTestRunListener[] securityTestStepListeners = new SecurityTestRunListener[0]; private long timeTaken; /** * holds index of current securityScan out of summary number of scans on * SecurityTest level used in main progress bar on SecurityTest */ private int currentScanOnSecurityTestIndex; public SecurityTestRunnerImpl(SecurityTest test, StringToObjectMap properties) { super(test, properties); this.securityTest = test; this.currentScanOnSecurityTestIndex = 0; } public SecurityTestRunContext createContext(StringToObjectMap properties) { return new SecurityTestRunContext(this, properties); } public SecurityTest getSecurityTest() { return getTestRunnable(); } @Override public TestStepResult runTestStep(TestStep testStep, boolean discard, boolean process) { if (!runBeforeSteps(testStep)) { return null; } TestStepResult stepResult = testStep.run(this, getRunContext()); getResults().add(stepResult); setResultCount(getResultCount() + 1); // enforceMaxResults( getTestRunnable().getMaxResults() ); // discard? // if( discard && stepResult.getStatus() == TestStepStatus.OK && // getTestRunnable().getDiscardOkResults() // && !stepResult.isDiscarded() ) // { // stepResult.discard(); // } return stepResult; } /** * Clones original TestStep for security modification this does not alter the * original test step * * @param sourceTestStep * @return TestStep */ public TestStep cloneForSecurityScan(WsdlTestStep sourceTestStep) { WsdlTestStep clonedTestStep = null; TestStepConfig testStepConfig = (TestStepConfig) sourceTestStep.getConfig().copy(); WsdlTestStepFactory factory = WsdlTestStepRegistry.getInstance().getFactory(testStepConfig.getType()); if (factory != null) { clonedTestStep = factory.buildTestStep(securityTest.getTestCase(), testStepConfig, false); if (clonedTestStep instanceof Assertable) { for (TestAssertion assertion : ((Assertable) clonedTestStep).getAssertionList()) { ((Assertable) clonedTestStep).removeAssertion(assertion); } } } return clonedTestStep; } /** * Clones original TestStep for security modification this does not alter the * original test step * * @param sourceTestStep * @return TestStep */ public static TestStep cloneTestStepForSecurityScan(WsdlTestStep sourceTestStep) { WsdlTestStep clonedTestStep = null; TestStepConfig testStepConfig = (TestStepConfig) sourceTestStep.getConfig().copy(); WsdlTestStepFactory factory = WsdlTestStepRegistry.getInstance().getFactory(testStepConfig.getType()); if (factory != null) { clonedTestStep = factory.buildTestStep(sourceTestStep.getTestCase(), testStepConfig, false); if (clonedTestStep instanceof Assertable) { for (TestAssertion assertion : ((Assertable) clonedTestStep).getAssertionList()) { ((Assertable) clonedTestStep).removeAssertion(assertion); } } } return clonedTestStep; } protected int runCurrentTestStep(SecurityTestRunContext runContext, int currentStepIndex) { // flag for detecting if running has been interrupted either by canceling // securityScanRequest // or if request result is null(backward compatibility for running // TestCase ) boolean jumpExit = false; TestStep currentStep = runContext.getCurrentStep(); securityTestStepListeners = securityTest.getTestStepRunListeners(currentStep); if (!currentStep.isDisabled() && !securityTest.skipTest(currentStep)) { TestStepResult stepResult = runTestStep(currentStep, true, true); if (stepResult == null) { jumpExit = true; } // if( !isRunning() ) // return -2; SecurityTestStepResult securityStepResult = new SecurityTestStepResult(currentStep, stepResult); for (int i = 0; i < securityTestListeners.length; i++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestListeners[i])) { securityTestListeners[i].afterOriginalStep(this, getRunContext(), securityStepResult); } } for (int i = 0; i < securityTestListeners.length; i++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestListeners[i])) { securityTestListeners[i].beforeStep(this, getRunContext(), stepResult); } } for (int i = 0; i < securityTestStepListeners.length; i++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()) .contains(securityTestStepListeners[i])) { securityTestStepListeners[i].beforeStep(this, getRunContext(), stepResult); } } Map<String, List<SecurityScan>> secScanMap = securityTest.getSecurityScansMap(); if (secScanMap.containsKey(currentStep.getId())) { List<SecurityScan> testStepScansList = secScanMap.get(currentStep.getId()); for (int i = 0; i < testStepScansList.size(); i++) { SecurityScan securityScan = testStepScansList.get(i); // if security scan is disabled skip it. if (securityScan.isDisabled() || securityScan.isSkipFurtherRunning()) { continue; } //if step is failed and scan not applicable to failed steps just set it to skipped //run scan otherwise if (stepResult.getStatus() == TestStepStatus.FAILED && !securityScan.isApplyForFailedStep()) { SecurityScanResult securityScanResult = new SecurityScanResult(securityScan); if (securityScan.getAssertionCount() > 0) { securityScanResult.setStatus(ResultStatus.OK); } else if (securityScan instanceof AbstractSecurityScanWithProperties) { if (((AbstractSecurityScanWithProperties) securityScan).getParameterHolder().getParameterList() .size() > 0) { securityScanResult.setStatus(ResultStatus.OK); } else { securityScanResult.setStatus(ResultStatus.SKIPPED); } } else { securityScanResult.setStatus(ResultStatus.SKIPPED); } securityStepResult.addSecurityScanResult(securityScanResult); runAfterListeners(runContext, securityScanResult); } else { runContext.setCurrentScanIndex(i); runContext.setCurrentScanOnSecurityTestIndex(currentScanOnSecurityTestIndex++); SecurityScanResult securityScanResult = runTestStepSecurityScan(runContext, currentStep, securityScan); securityStepResult.addSecurityScanResult(securityScanResult); if (securityScanResult.isCanceled()) { jumpExit = true; break; } else if (securityScanResult.getStatus() == ResultStatus.FAILED) { if (getTestRunnable().getFailOnError()) { // setError( stepResult.getError() ); fail("Cancelling due to failed security scan"); } else { getRunContext().setProperty(SecurityTestRunner.Status.class.getName(), SecurityTestRunner.Status.FAILED); } } } } // in case no security scan is executed if (securityStepResult.getStatus() == ResultStatus.INITIALIZED) { securityStepResult.setStatus(ResultStatus.UNKNOWN); } securityTest.putSecurityTestStepResult(currentStep, securityStepResult); timeTaken += securityStepResult.getTimeTaken(); } for (int i = 0; i < securityTestStepListeners.length; i++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()) .contains(securityTestStepListeners[i])) { securityTestStepListeners[i].afterStep(this, getRunContext(), securityStepResult); } } for (int i = 0; i < securityTestListeners.length; i++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestListeners[i])) { securityTestListeners[i].afterStep(this, getRunContext(), securityStepResult); } } if (jumpExit) { return -2; } else if (getGotoStepIndex() != -1) { currentStepIndex = getGotoStepIndex() - 1; gotoStep(-1); } } runContext.setCurrentStep(currentStepIndex + 1); return currentStepIndex; } /** * @param runContext * @param securityScanResult */ private void runAfterListeners(SecurityTestRunContext runContext, SecurityScanResult securityScanResult) { for (int j = 0; j < securityTestStepListeners.length; j++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestStepListeners[j])) { securityTestStepListeners[j].afterSecurityScan(this, runContext, securityScanResult); } } for (int j = 0; j < securityTestListeners.length; j++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestListeners[j])) { securityTestListeners[j].afterSecurityScan(this, runContext, securityScanResult); } } } public SecurityScanResult runTestStepSecurityScan(SecurityTestRunContext runContext, TestStep currentStep, SecurityScan securityScan) { SecurityScanResult result = null; for (int j = 0; j < securityTestStepListeners.length; j++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestStepListeners[j])) { securityTestStepListeners[j].beforeSecurityScan(this, runContext, securityScan); } } for (int j = 0; j < securityTestListeners.length; j++) { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestListeners[j])) { securityTestListeners[j].beforeSecurityScan(this, runContext, securityScan); } } result = securityScan.run(cloneForSecurityScan((WsdlTestStep) currentStep), runContext, this); if (securityScan.isRunOnlyOnce()) { securityScan.setSkipFurtherRunning(true); } if (securityTest.getFailOnError() && result.getStatus() == ResultStatus.FAILED) { fail("Cancelling due to failed security scan"); } runAfterListeners(runContext, result); return result; } /* * (non-Javadoc) * * @see * com.eviware.soapui.impl.wsdl.support.AbstractTestCaseRunner#notifyBeforeRun * () * * The order of listeners notifications here is important, security listeners * first, so while monitoring execution TestCase log is disabled before * WsdlTestCaseDesktopPanel.InternalTestRunListener.beforeRun is executed * otherwise SecurityTest execution will temper with functional log. */ protected void notifyBeforeRun() { reset(); if (securityTestListeners == null || securityTestListeners.length == 0) { return; } for (int i = 0; i < securityTestListeners.length; i++) { try { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestListeners[i])) { securityTestListeners[i].beforeRun(this, getRunContext()); } } catch (Throwable t) { SoapUI.logError(t); } } super.notifyBeforeRun(); } private void reset() { securityTest.resetAllScansSkipFurtherRunning(); securityTest.clearSecurityTestStepResultMap(); timeTaken = 0; } /* * (non-Javadoc) * * @see * com.eviware.soapui.impl.wsdl.support.AbstractTestCaseRunner#notifyAfterRun * () * * The same as for notifyBeforeRun, security listeners come last */ protected void notifyAfterRun() { super.notifyAfterRun(); if (securityTestListeners == null || securityTestListeners.length == 0) { return; } for (int i = 0; i < securityTestListeners.length; i++) { try { if (Arrays.asList(getSecurityTest().getSecurityTestRunListeners()).contains(securityTestListeners[i])) { securityTestListeners[i].afterRun(this, getRunContext()); } } catch (Throwable t) { SoapUI.logError(t); } } } @Override public WsdlTestCase getTestCase() { return getTestRunnable().getTestCase(); } @Override protected void clear(SecurityTestRunContext runContext) { super.clear(runContext); securityTestListeners = null; securityTestStepListeners = null; } @Override protected void runSetupScripts(SecurityTestRunContext runContext) throws Exception { super.runSetupScripts(runContext); getTestRunnable().runStartupScript(runContext, this); } @Override protected void runTearDownScripts(SecurityTestRunContext runContext) throws Exception { getTestRunnable().runTearDownScript(runContext, this); super.runTearDownScripts(runContext); } @Override protected void fillInTestRunnableListeners() { super.fillInTestRunnableListeners(); securityTestListeners = getTestRunnable().getSecurityTestRunListeners(); } @Override protected void failTestRunnableOnErrors(SecurityTestRunContext runContext) { if (runContext.getProperty(SecurityTestRunner.Status.class.getName()) == SecurityTestRunner.Status.FAILED && getTestRunnable().getFailSecurityTestOnScanErrors()) { fail("Failing due to failed security scan"); } } public long getTimeTaken() { return timeTaken; } public long getFunctionalTimeTaken() { return super.getTimeTaken(); } }