From b175a970d635004720894ee12640ff68b2d1da3e Mon Sep 17 00:00:00 2001 From: thc202 Date: Fri, 1 Nov 2024 15:36:48 +0000 Subject: [PATCH] sequence: add plans for the active scan job Add min/max plans for the active scan job. Signed-off-by: thc202 --- .../automation/SequenceActiveScanJob.java | 31 +++- .../resources/sequence-activeScan-max.yaml | 29 ++++ .../resources/sequence-activeScan-min.yaml | 3 + .../SequenceActiveScanJobUnitTest.java | 133 ++++++++++++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 addOns/sequence/src/main/resources/org/zaproxy/zap/extension/sequence/resources/sequence-activeScan-max.yaml create mode 100644 addOns/sequence/src/main/resources/org/zaproxy/zap/extension/sequence/resources/sequence-activeScan-min.yaml create mode 100644 addOns/sequence/src/test/java/org/zaproxy/zap/extension/sequence/automation/SequenceActiveScanJobUnitTest.java diff --git a/addOns/sequence/src/main/java/org/zaproxy/zap/extension/sequence/automation/SequenceActiveScanJob.java b/addOns/sequence/src/main/java/org/zaproxy/zap/extension/sequence/automation/SequenceActiveScanJob.java index 13211771974..dc99a048de5 100644 --- a/addOns/sequence/src/main/java/org/zaproxy/zap/extension/sequence/automation/SequenceActiveScanJob.java +++ b/addOns/sequence/src/main/java/org/zaproxy/zap/extension/sequence/automation/SequenceActiveScanJob.java @@ -19,6 +19,8 @@ */ package org.zaproxy.zap.extension.sequence.automation; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -27,9 +29,11 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.parosproxy.paros.CommandLine; import org.parosproxy.paros.Constant; import org.zaproxy.addon.automation.AutomationData; import org.zaproxy.addon.automation.AutomationEnvironment; @@ -57,6 +61,8 @@ public class SequenceActiveScanJob extends AutomationJob { public static final String JOB_NAME = "sequence-activeScan"; + private static final String RESOURCES_DIR = "/org/zaproxy/zap/extension/sequence/resources/"; + private static final Logger LOGGER = LogManager.getLogger(SequenceActiveScanJob.class); private static final String PARAM_CONTEXT = "context"; @@ -136,7 +142,7 @@ public void applyParameters(AutomationProgress progress) { this.getName(), new String[] {PARAM_SEQUENCE, PARAM_POLICY, PARAM_CONTEXT, PARAM_USER}, progress, - this.getPlan().getEnv()); + getEnv()); } @Override @@ -262,6 +268,29 @@ public String getType() { return JOB_NAME; } + @Override + public String getTemplateDataMin() { + return getResourceAsString(this.getType() + "-min.yaml"); + } + + @Override + public String getTemplateDataMax() { + return getResourceAsString(this.getType() + "-max.yaml"); + } + + private static String getResourceAsString(String name) { + try { + return IOUtils.toString( + SequenceActiveScanJob.class.getResourceAsStream(RESOURCES_DIR + name), + StandardCharsets.UTF_8); + } catch (IOException e) { + CommandLine.error( + Constant.messages.getString( + "sequence.automation.error.noresourcefile", RESOURCES_DIR + name)); + } + return ""; + } + @Override public Order getOrder() { return Order.ATTACK; diff --git a/addOns/sequence/src/main/resources/org/zaproxy/zap/extension/sequence/resources/sequence-activeScan-max.yaml b/addOns/sequence/src/main/resources/org/zaproxy/zap/extension/sequence/resources/sequence-activeScan-max.yaml new file mode 100644 index 00000000000..ca8bc1a7b6f --- /dev/null +++ b/addOns/sequence/src/main/resources/org/zaproxy/zap/extension/sequence/resources/sequence-activeScan-max.yaml @@ -0,0 +1,29 @@ + - type: sequence-activeScan # Active scans one or all sequences. + parameters: + sequence: # String: The name of the sequence, or empty to active scan all sequences. + context: # String: Context to use when active scanning, default: first context. + user: # String: An optional user to use for authentication, must be defined in the env. + policy: # String: Name of the scan policy to be used, default: Default Policy. + policyDefinition: # The policy definition - only used if the 'policy' is not set + defaultStrength: # String: The default Attack Strength for all rules, one of Low, Medium, High, Insane (not recommended), default: Medium + defaultThreshold: # String: The default Alert Threshold for all rules, one of Off, Low, Medium, High, default: Medium + rules: # A list of one or more active scan rules and associated settings which override the defaults + - id: # Int: The rule id as per https://www.zaproxy.org/docs/alerts/ + name: # Comment: The name of the rule for documentation purposes - this is not required or actually used + strength: # String: The Attack Strength for this rule, one of Low, Medium, High, Insane, default: Medium + threshold: # String: The Alert Threshold for this rule, one of Off, Low, Medium, High, default: Medium + tests: + - name: 'test one' # Name of the test, optional + type: alert # Specifies that the test is of type 'alert' + action: passIfPresent/passIfAbsent # String: The condition (presence/absence) of the alert, default: passIfAbsent + scanRuleId: # Integer: The id of the scanRule which generates the alert, mandatory + alertName: # String: The name of the alert generated, optional + url: http://www.example.com/path # String: The url of the request corresponding to the alert generated, optional + method: # String: The method of the request corresponding to the alert generated, optional + attack: # String: The actual attack which generated the alert, optional + param: # String: The parameter which was modified to generate the alert, optional + evidence: # String: The evidence corresponding to the alert generated, optional + confidence: # String: The confidence of the alert, one of 'False Positive', 'Low', 'Medium', 'High', 'Confirmed', optional + risk: # String: The risk of the alert, one of 'Informational', 'Low', 'Medium', 'High', optional + otherInfo: # String: Addional information corresponding to the alert, optional + onFail: 'info' # String: One of 'warn', 'error', 'info', mandatory diff --git a/addOns/sequence/src/main/resources/org/zaproxy/zap/extension/sequence/resources/sequence-activeScan-min.yaml b/addOns/sequence/src/main/resources/org/zaproxy/zap/extension/sequence/resources/sequence-activeScan-min.yaml new file mode 100644 index 00000000000..b7aec1933e4 --- /dev/null +++ b/addOns/sequence/src/main/resources/org/zaproxy/zap/extension/sequence/resources/sequence-activeScan-min.yaml @@ -0,0 +1,3 @@ + - type: sequence-activeScan # Active scans one or all sequences. + parameters: + sequence: # String: The name of the sequence, or empty to active scan all sequences. diff --git a/addOns/sequence/src/test/java/org/zaproxy/zap/extension/sequence/automation/SequenceActiveScanJobUnitTest.java b/addOns/sequence/src/test/java/org/zaproxy/zap/extension/sequence/automation/SequenceActiveScanJobUnitTest.java new file mode 100644 index 00000000000..59f9761cf60 --- /dev/null +++ b/addOns/sequence/src/test/java/org/zaproxy/zap/extension/sequence/automation/SequenceActiveScanJobUnitTest.java @@ -0,0 +1,133 @@ +/* + * Zed Attack Proxy (ZAP) and its related class files. + * + * ZAP is an HTTP/HTTPS proxy for assessing web application security. + * + * Copyright 2024 The ZAP Development Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.zaproxy.zap.extension.sequence.automation; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.withSettings; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.quality.Strictness; +import org.yaml.snakeyaml.Yaml; +import org.zaproxy.addon.automation.AutomationEnvironment; +import org.zaproxy.addon.automation.AutomationJob; +import org.zaproxy.addon.automation.AutomationProgress; +import org.zaproxy.zap.extension.ascan.ExtensionActiveScan; +import org.zaproxy.zap.extension.script.ExtensionScript; +import org.zaproxy.zap.extension.sequence.ExtensionSequence; +import org.zaproxy.zap.testutils.TestUtils; + +/** Unit test for {@link SequenceActiveScanJob}. */ +class SequenceActiveScanJobUnitTest extends TestUtils { + + private ExtensionActiveScan ascan; + private ExtensionScript script; + + private SequenceActiveScanJob job; + + @BeforeEach + void setUp() { + mockMessages(new ExtensionSequence()); + + ascan = mock(ExtensionActiveScan.class, withSettings().strictness(Strictness.LENIENT)); + script = mock(ExtensionScript.class, withSettings().strictness(Strictness.LENIENT)); + + job = new SequenceActiveScanJob(ascan, script); + } + + @Test + void shouldReturnDefaultFields() { + assertThat(job.getType(), is(equalTo("sequence-activeScan"))); + assertThat(job.getName(), is(equalTo("sequence-activeScan"))); + assertThat(job.getOrder(), is(equalTo(AutomationJob.Order.ATTACK))); + assertValidTemplate(job.getTemplateDataMin()); + assertValidTemplate(job.getTemplateDataMax()); + assertThat(job.getParamMethodObject(), is(nullValue())); + assertThat(job.getParamMethodName(), is(nullValue())); + } + + @Test + void shouldReturnCustomConfigParams() { + // Given / When + Map params = job.getCustomConfigParameters(); + + // Then + assertThat(params.size(), is(equalTo(1))); + assertThat(params.get("context"), is(equalTo(""))); + } + + @Test + void shouldApplyCustomConfigParams() { + // Given + AutomationProgress progress = new AutomationProgress(); + String sequence = "Sequence Name"; + String context = "Context"; + String user = "User"; + String policy = "Policy"; + String yamlStr = + "parameters:\n" + + " sequence: " + + sequence + + "\n" + + " context: " + + context + + "\n" + + " user: " + + user + + "\n" + + " policy: " + + policy + + "\n"; + Object data = new Yaml().load(yamlStr); + + AutomationEnvironment env = mock(AutomationEnvironment.class); + given(env.getAllUserNames()).willReturn(List.of(user)); + + job.setEnv(env); + job.setJobData(((LinkedHashMap) data)); + + // When + job.verifyParameters(progress); + job.applyParameters(progress); + + // Then + assertThat(job.getParameters().getSequence(), is(equalTo(sequence))); + assertThat(job.getParameters().getContext(), is(equalTo(context))); + assertThat(job.getParameters().getUser(), is(equalTo(user))); + assertThat(job.getParameters().getPolicy(), is(equalTo(policy))); + assertThat(progress.hasWarnings(), is(equalTo(false))); + assertThat(progress.hasErrors(), is(equalTo(false))); + } + + private static void assertValidTemplate(String value) { + assertThat(value, is(not(equalTo("")))); + assertDoesNotThrow(() -> new Yaml().load(value)); + } +}