Skip to content

Commit

Permalink
Merge pull request #5872 from thc202/sequence/ascan-plans
Browse files Browse the repository at this point in the history
sequence: add plans for the active scan job
  • Loading branch information
psiinon authored Nov 1, 2024
2 parents 494d2e3 + b175a97 commit 33aeee0
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,9 +30,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;
Expand All @@ -56,6 +60,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";
Expand Down Expand Up @@ -135,7 +141,7 @@ public void applyParameters(AutomationProgress progress) {
this.getName(),
new String[] {PARAM_SEQUENCE, PARAM_POLICY, PARAM_CONTEXT, PARAM_USER},
progress,
this.getPlan().getEnv());
getEnv());
}

@Override
Expand Down Expand Up @@ -276,6 +282,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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -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<String, String> 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));
}
}

0 comments on commit 33aeee0

Please sign in to comment.