diff --git a/zap/src/main/java/org/parosproxy/paros/core/scanner/PluginFactory.java b/zap/src/main/java/org/parosproxy/paros/core/scanner/PluginFactory.java
index f158b70e4cd..6d7f0eddf0b 100644
--- a/zap/src/main/java/org/parosproxy/paros/core/scanner/PluginFactory.java
+++ b/zap/src/main/java/org/parosproxy/paros/core/scanner/PluginFactory.java
@@ -60,6 +60,7 @@
// ZAP: 2022/02/03 Removed loadedPlugin and unloadedPlugin.
// ZAP: 2022/09/21 Use format specifiers instead of concatenation when logging.
// ZAP: 2023/01/10 Tidy up logger.
+// ZAP: 2025/11/17 Support locked policy.
package org.parosproxy.paros.core.scanner;
import java.util.ArrayList;
@@ -77,6 +78,7 @@
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.parosproxy.paros.core.scanner.Plugin.AlertThreshold;
import org.zaproxy.zap.control.ExtensionFactory;
public class PluginFactory {
@@ -96,6 +98,7 @@ public class PluginFactory {
private int totalPluginToRun = 0;
private boolean init = false;
private Configuration config;
+ private boolean locked;
public PluginFactory() {
super();
@@ -104,6 +107,30 @@ public PluginFactory() {
config = configuration;
}
+ /**
+ * Tells whether or not this factory is locked.
+ *
+ *
Locked factories automatically disable any rules not defined in the loaded configuration.
+ *
+ * @return {@code true} if the factory is locked, {@code false} otherwise.
+ * @since 2.17.0
+ * @see #loadAllPlugin(Configuration)
+ */
+ public boolean isLocked() {
+ return locked;
+ }
+
+ /**
+ * Sets whether or not this factory should be locked.
+ *
+ * @param locked {@code true} if the factory should be locked, {@code false} otherwise.
+ * @since 2.17.0
+ * @see #isLocked()
+ */
+ public void setLocked(boolean locked) {
+ this.locked = locked;
+ }
+
private static synchronized void initPlugins() {
if (loadedPlugins == null) {
init(true);
@@ -396,7 +423,14 @@ public synchronized void loadAllPlugin(Configuration config) {
continue;
}
+ boolean disable =
+ locked && !config.getKeys("plugins.p" + loadedPlugin.getId()).hasNext();
+
Plugin plugin = createNewPlugin(loadedPlugin, config);
+ if (disable) {
+ plugin.setAlertThreshold(AlertThreshold.OFF);
+ }
+
LOGGER.debug(
"loaded plugin {} with: Threshold={} Strength={}",
plugin.getName(),
diff --git a/zap/src/main/java/org/parosproxy/paros/model/SiteMap.java b/zap/src/main/java/org/parosproxy/paros/model/SiteMap.java
index ca0f76e6c90..5783145a594 100644
--- a/zap/src/main/java/org/parosproxy/paros/model/SiteMap.java
+++ b/zap/src/main/java/org/parosproxy/paros/model/SiteMap.java
@@ -79,6 +79,7 @@
// ZAP: 2022/09/21 Use format specifiers instead of concatenation when logging.
// ZAP: 2023/01/10 Tidy up logger.
// ZAP: 2024/01/19 Store clean node name when adding leaf node.
+// ZAP: 2025/11/17 Add contentType to ADD events.
package org.parosproxy.paros.model;
import java.awt.EventQueue;
@@ -530,7 +531,11 @@ private SiteNode findAndAddChild(
hrefMap.put(result.getHistoryReference().getHistoryId(), result);
applyFilter(newNode);
- handleEvent(parent, result, EventType.ADD);
+ handleEvent(
+ parent,
+ result,
+ EventType.ADD,
+ getAddEventParameters(HistoryReference.TYPE_TEMPORARY, baseMsg));
}
// ZAP: Cope with getSiteNode() returning null
if (baseRef.getSiteNode() == null) {
@@ -597,7 +602,8 @@ private SiteNode findAndAddLeaf(
this.applyFilter(node);
- handleEvent(parent, node, EventType.ADD);
+ handleEvent(
+ parent, node, EventType.ADD, getAddEventParameters(ref.getHistoryType(), msg));
} else if (hrefMap.get(ref.getHistoryId()) != node) {
// Give preference to successful requests but update same statuses'.
@@ -615,6 +621,16 @@ private SiteNode findAndAddLeaf(
return node;
}
+ private Map getAddEventParameters(int hrefType, HttpMessage msg) {
+ if (hrefType != HistoryReference.TYPE_TEMPORARY) {
+ String contentType = msg.getResponseHeader().getNormalisedContentTypeValue();
+ if (contentType != null) {
+ return Map.of("contentType", contentType);
+ }
+ }
+ return Map.of();
+ }
+
public HistoryReference createReference(
SiteNode node, HistoryReference baseRef, HttpMessage base)
throws HttpMalformedHeaderException,
@@ -761,7 +777,7 @@ private void clearParentFilter(SiteNode parent) {
public void removeNodeFromParent(MutableTreeNode node) {
SiteNode parent = (SiteNode) node.getParent();
super.removeNodeFromParent(node);
- handleEvent(parent, (SiteNode) node, EventType.REMOVE);
+ handleEvent(parent, (SiteNode) node, EventType.REMOVE, Map.of());
}
/**
@@ -774,18 +790,19 @@ public void removeNodeFromParent(MutableTreeNode node) {
* @see EventType
* @since 2.5.0
*/
- private void handleEvent(SiteNode parent, SiteNode node, EventType eventType) {
+ private void handleEvent(
+ SiteNode parent, SiteNode node, EventType eventType, Map parameters) {
switch (eventType) {
case ADD:
- publishEvent(SiteMapEventPublisher.SITE_NODE_ADDED_EVENT, node);
+ publishEvent(SiteMapEventPublisher.SITE_NODE_ADDED_EVENT, node, parameters);
if (parent == getRoot()) {
- publishEvent(SiteMapEventPublisher.SITE_ADDED_EVENT, node);
+ publishEvent(SiteMapEventPublisher.SITE_ADDED_EVENT, node, parameters);
}
break;
case REMOVE:
- publishEvent(SiteMapEventPublisher.SITE_NODE_REMOVED_EVENT, node);
+ publishEvent(SiteMapEventPublisher.SITE_NODE_REMOVED_EVENT, node, parameters);
if (parent == getRoot()) {
- publishEvent(SiteMapEventPublisher.SITE_REMOVED_EVENT, node);
+ publishEvent(SiteMapEventPublisher.SITE_REMOVED_EVENT, node, parameters);
}
}
}
@@ -797,11 +814,15 @@ private void handleEvent(SiteNode parent, SiteNode node, EventType eventType) {
* @param node the node being acted upon
* @since 2.5.0
*/
- private static void publishEvent(String event, SiteNode node) {
+ private static void publishEvent(String event, SiteNode node, Map parameters) {
ZAP.getEventBus()
.publishSyncEvent(
SiteMapEventPublisher.getPublisher(),
- new Event(SiteMapEventPublisher.getPublisher(), event, new Target(node)));
+ new Event(
+ SiteMapEventPublisher.getPublisher(),
+ event,
+ new Target(node),
+ parameters));
}
@Override
diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/PolicyAllCategoryPanel.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/PolicyAllCategoryPanel.java
index 25d4b1f5544..949e6f38c94 100644
--- a/zap/src/main/java/org/zaproxy/zap/extension/ascan/PolicyAllCategoryPanel.java
+++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/PolicyAllCategoryPanel.java
@@ -28,6 +28,7 @@
// not important).
// ZAP: 2019/06/01 Normalise line endings.
// ZAP: 2019/06/05 Normalise format/style.
+// ZAP: 2025/11/17 Support locked policy.
package org.zaproxy.zap.extension.ascan;
import java.awt.GridBagConstraints;
@@ -44,6 +45,7 @@
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
+import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
@@ -75,6 +77,7 @@ public class PolicyAllCategoryPanel extends AbstractParamPanel {
private static final Logger LOGGER = LogManager.getLogger(PolicyAllCategoryPanel.class);
private ZapTextField policyName = null;
+ private JCheckBox locked;
private JTable tableTest = null;
private JScrollPane jScrollPane = null;
private AllCategoryTableModel allCategoryTableModel = null;
@@ -146,6 +149,30 @@ private void initialize() {
0,
GridBagConstraints.HORIZONTAL,
new Insets(2, 2, 2, 2)));
+
+ locked = new JCheckBox();
+ locked.setSelected(policy.isLocked());
+ row++;
+ this.add(
+ new JLabel(Constant.messages.getString("ascan.policy.locked.label")),
+ LayoutHelper.getGBC(
+ 0,
+ row,
+ 1,
+ 0.0D,
+ 0,
+ GridBagConstraints.HORIZONTAL,
+ new Insets(2, 2, 2, 2)));
+ this.add(
+ locked,
+ LayoutHelper.getGBC(
+ 1,
+ row,
+ 2,
+ 1.0D,
+ 0,
+ GridBagConstraints.HORIZONTAL,
+ new Insets(2, 2, 2, 2)));
}
row++;
@@ -549,6 +576,9 @@ public void validateParam(Object obj) throws Exception {
@Override
public void saveParam(Object obj) throws Exception {
this.policy.setName(getPolicyName().getText());
+ if (locked != null) {
+ policy.setLocked(locked.isSelected());
+ }
}
/**
diff --git a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ScanPolicy.java b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ScanPolicy.java
index 7493dc7c762..6cf668376a3 100644
--- a/zap/src/main/java/org/zaproxy/zap/extension/ascan/ScanPolicy.java
+++ b/zap/src/main/java/org/zaproxy/zap/extension/ascan/ScanPolicy.java
@@ -39,6 +39,7 @@ public class ScanPolicy {
private String name;
private String statsId;
private boolean readOnly;
+ private boolean locked;
private PluginFactory pluginFactory = new PluginFactory();
private AlertThreshold defaultThreshold;
private AttackStrength defaultStrength;
@@ -57,10 +58,12 @@ public ScanPolicy(ZapXmlConfiguration conf) throws ConfigurationException {
name = conf.getString("policy", "");
statsId = conf.getString("statsId", null);
readOnly = conf.getBoolean("readonly", false);
+ locked = conf.getBoolean("locked", false);
if (statsId == null
&& name.equals(Constant.messages.getString("ascan.policymgr.default.name"))) {
statsId = "default";
}
+ pluginFactory.setLocked(locked);
pluginFactory.loadAllPlugin(conf);
setDefaultThreshold(getAlertThresholdFromConfig());
@@ -85,6 +88,7 @@ public void cloneInto(ScanPolicy policy) {
policy.defaultThreshold = this.getDefaultThreshold();
policy.statsId = this.statsId;
policy.readOnly = this.readOnly;
+ policy.locked = this.locked;
}
/**
@@ -94,6 +98,7 @@ public void cloneInto(ScanPolicy policy) {
*/
public void saveTo(Configuration conf) throws ConfigurationException {
conf.setProperty("policy", getName());
+ conf.setProperty("locked", isLocked());
conf.setProperty("scanner.level", getDefaultThreshold().name());
conf.setProperty("scanner.strength", getDefaultStrength().name());
getPluginFactory().saveTo(conf);
@@ -190,4 +195,29 @@ public String getStatsId() {
public boolean isReadOnly() {
return readOnly;
}
+
+ /**
+ * Tells whether or not the policy is locked.
+ *
+ * Locked policies do not allow the use of any other scan rules than the ones defined in
+ * their configuration.
+ *
+ * @return {@code true} if the policy is locked, {@code false} otherwise.
+ * @since 2.17.0
+ */
+ public boolean isLocked() {
+ return locked;
+ }
+
+ /**
+ * Sets whether or not this policy should be locked.
+ *
+ * @param locked {@code true} if the policy should be locked, {@code false} otherwise.
+ * @since 2.17.0
+ * @see #isLocked()
+ */
+ public void setLocked(boolean locked) {
+ this.locked = locked;
+ pluginFactory.setLocked(locked);
+ }
}
diff --git a/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties b/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties
index 66467353cda..f707483fe90 100644
--- a/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties
+++ b/zap/src/main/resources/org/zaproxy/zap/resources/Messages.properties
@@ -539,6 +539,7 @@ ascan.policy.level.low = Low
ascan.policy.level.medium = Medium
ascan.policy.level.off = OFF
ascan.policy.load.error = Failed to load policy file, see log for detail
+ascan.policy.locked.label = Locked:
ascan.policy.name.default = Default Policy
ascan.policy.name.label = Policy:
ascan.policy.namedialog.name.label = New Policy Name:
diff --git a/zap/src/test/java/org/parosproxy/paros/core/scanner/PluginFactoryUnitTest.java b/zap/src/test/java/org/parosproxy/paros/core/scanner/PluginFactoryUnitTest.java
index 7f64eaaf7ec..a72fb12be06 100644
--- a/zap/src/test/java/org/parosproxy/paros/core/scanner/PluginFactoryUnitTest.java
+++ b/zap/src/test/java/org/parosproxy/paros/core/scanner/PluginFactoryUnitTest.java
@@ -36,11 +36,15 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.quality.Strictness;
import org.parosproxy.paros.Constant;
import org.zaproxy.zap.control.AddOn;
+import org.zaproxy.zap.extension.ascan.ScanPolicy;
import org.zaproxy.zap.utils.I18N;
+import org.zaproxy.zap.utils.ZapXmlConfiguration;
/** Unit test for {@link PluginFactory}. */
@ExtendWith(MockitoExtension.class)
@@ -183,6 +187,97 @@ void shouldHaveDifferentPluginInstancesPerPluginFactory() {
is(not(sameInstance(otherPluginFactory.getAllPlugin().get(0)))));
}
+ @Test
+ void shouldNotBeLockedByDefault() {
+ // Given
+ PluginFactory pluginFactory = new PluginFactory();
+ // When / Then
+ assertThat(pluginFactory.isLocked(), is(equalTo(false)));
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void shouldSetLocked(boolean locked) {
+ // Given
+ PluginFactory pluginFactory = new PluginFactory();
+ // When
+ pluginFactory.setLocked(locked);
+ // Then
+ assertThat(pluginFactory.isLocked(), is(equalTo(locked)));
+ }
+
+ @Test
+ void shouldDisableUnconfiguredPluginsWhenLocked() {
+ // Given
+ PluginFactory pluginFactory = new PluginFactory();
+ pluginFactory.setLocked(true);
+ ZapXmlConfiguration conf = configWithPlugin();
+ // When
+ pluginFactory.loadAllPlugin(conf);
+ // Then
+ List plugins = pluginFactory.getAllPlugin();
+ assertThat(plugins.get(0).getId(), is(equalTo(1)));
+ assertThat(plugins.get(0).isEnabled(), is(equalTo(true)));
+ assertThat(plugins.get(1).getId(), is(equalTo(2)));
+ assertThat(plugins.get(1).isEnabled(), is(equalTo(false)));
+ }
+
+ @Test
+ void shouldDisableUnconfiguredPluginsWhenLockedThroughScanPolicy() throws Exception {
+ // Given
+ ZapXmlConfiguration conf = configWithPlugin();
+ conf.setProperty("locked", true);
+ // When
+ ScanPolicy scanPolicy = new ScanPolicy(conf);
+ // Then
+ List plugins = scanPolicy.getPluginFactory().getAllPlugin();
+ assertThat(plugins.get(0).getId(), is(equalTo(1)));
+ assertThat(plugins.get(0).isEnabled(), is(equalTo(true)));
+ assertThat(plugins.get(1).getId(), is(equalTo(2)));
+ assertThat(plugins.get(1).isEnabled(), is(equalTo(false)));
+ }
+
+ static ZapXmlConfiguration configWithPlugin() {
+ AbstractPlugin plugin1 = createAbstractPlugin(1);
+ AbstractPlugin plugin2 = createAbstractPlugin(2);
+ PluginFactory.loadedPlugin(plugin1);
+ PluginFactory.loadedPlugin(plugin2);
+ ZapXmlConfiguration conf = new ZapXmlConfiguration();
+ conf.setProperty("plugins.p1.level", "DEFAULT");
+ return conf;
+ }
+
+ @Test
+ void shouldUseUnconfiguredPluginsWhenNotLocked() {
+ // Given
+ PluginFactory pluginFactory = new PluginFactory();
+ pluginFactory.setLocked(false);
+ ZapXmlConfiguration conf = configWithPlugin();
+ // When
+ pluginFactory.loadAllPlugin(conf);
+ // Then
+ List plugins = pluginFactory.getAllPlugin();
+ assertThat(plugins.get(0).getId(), is(equalTo(1)));
+ assertThat(plugins.get(0).isEnabled(), is(equalTo(true)));
+ assertThat(plugins.get(1).getId(), is(equalTo(2)));
+ assertThat(plugins.get(1).isEnabled(), is(equalTo(true)));
+ }
+
+ @Test
+ void shouldUseUnconfiguredPluginsWhenNotLockedThroughScanPolicy() throws Exception {
+ // Given
+ ZapXmlConfiguration conf = configWithPlugin();
+ conf.setProperty("locked", false);
+ // When
+ ScanPolicy scanPolicy = new ScanPolicy(conf);
+ // Then
+ List plugins = scanPolicy.getPluginFactory().getAllPlugin();
+ assertThat(plugins.get(0).getId(), is(equalTo(1)));
+ assertThat(plugins.get(0).isEnabled(), is(equalTo(true)));
+ assertThat(plugins.get(1).getId(), is(equalTo(2)));
+ assertThat(plugins.get(1).isEnabled(), is(equalTo(true)));
+ }
+
@Test
void shouldOrderHighRiskAlertPluginsBeforeMedium() {
// Given
diff --git a/zap/src/test/java/org/parosproxy/paros/model/SiteMapUnitTest.java b/zap/src/test/java/org/parosproxy/paros/model/SiteMapUnitTest.java
index bd62c2e137e..9fe194cedd1 100644
--- a/zap/src/test/java/org/parosproxy/paros/model/SiteMapUnitTest.java
+++ b/zap/src/test/java/org/parosproxy/paros/model/SiteMapUnitTest.java
@@ -33,8 +33,10 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.TreeSet;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
@@ -51,6 +53,9 @@
import org.parosproxy.paros.network.HtmlParameter;
import org.parosproxy.paros.network.HttpMalformedHeaderException;
import org.parosproxy.paros.network.HttpMessage;
+import org.zaproxy.zap.ZAP;
+import org.zaproxy.zap.eventBus.Event;
+import org.zaproxy.zap.eventBus.EventConsumer;
import org.zaproxy.zap.extension.ascan.VariantFactory;
import org.zaproxy.zap.model.StandardParameterParser;
@@ -313,6 +318,100 @@ void shouldGetCleanNameForLeafNodeWithQueryAndFormParams() throws Exception {
assertThat(leaf.getCleanNodeName(), is(equalTo("cat")));
}
+ @Test
+ void shouldPublishAddedEvents() throws Exception {
+ // Given
+ String uri = "http://example.com/";
+ HistoryReference href = createHistoryReference(uri);
+ given(href.getHistoryType()).willReturn(HistoryReference.TYPE_ZAP_USER);
+ given(href.getHistoryId()).willReturn(100);
+
+ TestEventConsumer testConsumer = new TestEventConsumer();
+ ZAP.getEventBus()
+ .registerConsumer(testConsumer, SiteMapEventPublisher.class.getCanonicalName());
+
+ // When
+ siteMap.addPath(href);
+ // Then
+ assertThat(testConsumer.events.size(), is(equalTo(3)));
+ assertThat(testConsumer.events.get(0).getEventType(), is(equalTo("siteNode.added")));
+ assertThat(
+ testConsumer.events.get(0).getTarget().getStartNode().getHierarchicNodeName(),
+ is(equalTo("http://example.com")));
+ assertThat(testConsumer.events.get(0).getParameters().size(), is(equalTo(0)));
+
+ assertThat(testConsumer.events.get(1).getEventType(), is(equalTo("site.added")));
+ assertThat(
+ testConsumer.events.get(1).getTarget().getStartNode().getHierarchicNodeName(),
+ is(equalTo("http://example.com")));
+ assertThat(testConsumer.events.get(1).getParameters().size(), is(equalTo(0)));
+
+ assertThat(testConsumer.events.get(2).getEventType(), is(equalTo("siteNode.added")));
+ assertThat(
+ testConsumer.events.get(2).getTarget().getStartNode().getHierarchicNodeName(),
+ is(equalTo("http://example.com/")));
+ assertThat(testConsumer.events.get(2).getParameters().size(), is(equalTo(1)));
+ assertThat(
+ testConsumer.events.get(2).getParameters().containsKey("contentType"),
+ is(equalTo(true)));
+ assertThat(
+ testConsumer.events.get(2).getParameters().get("contentType"),
+ is(equalTo("text/html")));
+ }
+
+ @Test
+ void shouldOnlyAddContentTypeToLeafPublishEvents() throws Exception {
+ // Given
+ String uri = "http://example.com/a/b/c";
+ HistoryReference href = createHistoryReference(uri);
+ given(href.getHistoryType()).willReturn(HistoryReference.TYPE_ZAP_USER);
+ given(href.getHistoryId()).willReturn(100);
+
+ TestEventConsumer testConsumer = new TestEventConsumer();
+ ZAP.getEventBus()
+ .registerConsumer(testConsumer, SiteMapEventPublisher.class.getCanonicalName());
+
+ // When
+ siteMap.addPath(href);
+ // Then
+ assertThat(testConsumer.events.size(), is(equalTo(5)));
+ assertThat(testConsumer.events.get(0).getEventType(), is(equalTo("siteNode.added")));
+ assertThat(
+ testConsumer.events.get(0).getTarget().getStartNode().getHierarchicNodeName(),
+ is(equalTo("http://example.com")));
+ assertThat(testConsumer.events.get(0).getParameters().size(), is(equalTo(0)));
+
+ assertThat(testConsumer.events.get(1).getEventType(), is(equalTo("site.added")));
+ assertThat(
+ testConsumer.events.get(1).getTarget().getStartNode().getHierarchicNodeName(),
+ is(equalTo("http://example.com")));
+ assertThat(testConsumer.events.get(1).getParameters().size(), is(equalTo(0)));
+
+ assertThat(testConsumer.events.get(2).getEventType(), is(equalTo("siteNode.added")));
+ assertThat(
+ testConsumer.events.get(2).getTarget().getStartNode().getHierarchicNodeName(),
+ is(equalTo("http://example.com/a")));
+ assertThat(testConsumer.events.get(2).getParameters().size(), is(equalTo(0)));
+
+ assertThat(testConsumer.events.get(3).getEventType(), is(equalTo("siteNode.added")));
+ assertThat(
+ testConsumer.events.get(3).getTarget().getStartNode().getHierarchicNodeName(),
+ is(equalTo("http://example.com/a/b")));
+ assertThat(testConsumer.events.get(3).getParameters().size(), is(equalTo(0)));
+
+ assertThat(testConsumer.events.get(4).getEventType(), is(equalTo("siteNode.added")));
+ assertThat(
+ testConsumer.events.get(4).getTarget().getStartNode().getHierarchicNodeName(),
+ is(equalTo("http://example.com/a/b/c")));
+ assertThat(testConsumer.events.get(4).getParameters().size(), is(equalTo(1)));
+ assertThat(
+ testConsumer.events.get(4).getParameters().containsKey("contentType"),
+ is(equalTo(true)));
+ assertThat(
+ testConsumer.events.get(4).getParameters().get("contentType"),
+ is(equalTo("text/html")));
+ }
+
private void siteMapWithNodes(String... uris) {
Arrays.stream(uris).forEach(uri -> siteMap.addPath(createHistoryReference(uri)));
}
@@ -328,6 +427,7 @@ private static HistoryReference createHistoryReference(String uri, String method
try {
HttpMessage httpMessage = new HttpMessage(requestUri);
httpMessage.getRequestHeader().setMethod(method);
+ httpMessage.getResponseHeader().addHeader("content-type", "text/html");
given(historyReference.getHttpMessage()).willReturn(httpMessage);
} catch (HttpMalformedHeaderException | DatabaseException e) {
throw new RuntimeException(e);
@@ -342,4 +442,14 @@ private static URI createUri(String uri) {
throw new RuntimeException(e);
}
}
+
+ private class TestEventConsumer implements EventConsumer {
+
+ List events = new ArrayList<>();
+
+ @Override
+ public void eventReceived(Event event) {
+ events.add(event);
+ }
+ }
}
diff --git a/zap/src/test/java/org/zaproxy/zap/extension/ascan/ScanPolicyUnitTest.java b/zap/src/test/java/org/zaproxy/zap/extension/ascan/ScanPolicyUnitTest.java
index 534142a0615..33ac2bcef9e 100644
--- a/zap/src/test/java/org/zaproxy/zap/extension/ascan/ScanPolicyUnitTest.java
+++ b/zap/src/test/java/org/zaproxy/zap/extension/ascan/ScanPolicyUnitTest.java
@@ -25,6 +25,8 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
import org.parosproxy.paros.core.scanner.Plugin;
import org.zaproxy.zap.WithConfigsTest;
import org.zaproxy.zap.utils.ZapXmlConfiguration;
@@ -120,4 +122,53 @@ void shouldUseMediumIfDefaultScannerStrengthFromConfigIsDefault() throws Excepti
// Then
assertThat(scanPolicy.getDefaultStrength(), is(equalTo(Plugin.AttackStrength.MEDIUM)));
}
+
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void shouldLoadLockedStateFromConfig(boolean locked) throws Exception {
+ // Given
+ ZapXmlConfiguration conf = new ZapXmlConfiguration();
+ conf.setProperty("locked", locked);
+ // When
+ ScanPolicy scanPolicy = new ScanPolicy(conf);
+ // Then
+ assertThat(scanPolicy.isLocked(), is(equalTo(locked)));
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void shouldSetPluginFactoryLockedStateFromConfig(boolean locked) throws Exception {
+ // Given
+ ZapXmlConfiguration conf = new ZapXmlConfiguration();
+ conf.setProperty("locked", locked);
+ // When
+ ScanPolicy scanPolicy = new ScanPolicy(conf);
+ // Then
+ assertThat(scanPolicy.getPluginFactory().isLocked(), is(equalTo(locked)));
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void shouldSetLockedState(boolean locked) {
+ // Given
+ ScanPolicy scanPolicy = new ScanPolicy();
+ // When
+ scanPolicy.setLocked(locked);
+ // Then
+ assertThat(scanPolicy.isLocked(), is(equalTo(locked)));
+ assertThat(scanPolicy.getPluginFactory().isLocked(), is(equalTo(locked)));
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {true, false})
+ void shouldSaveLockedState(boolean locked) throws Exception {
+ // Given
+ ZapXmlConfiguration conf = new ZapXmlConfiguration();
+ ScanPolicy scanPolicy = new ScanPolicy();
+ scanPolicy.setLocked(locked);
+ // When
+ scanPolicy.saveTo(conf);
+ // Then
+ assertThat(conf.getBoolean("locked"), is(equalTo(locked)));
+ }
}