Skip to content

Commit

Permalink
soap: convert variant script to Java class
Browse files Browse the repository at this point in the history
Convert the script into a Java class to no longer rely on the script
engine, which is not available in newer Java versions.

Fix zaproxy/zaproxy#6500.

Signed-off-by: thc202 <[email protected]>
  • Loading branch information
thc202 committed Aug 31, 2023
1 parent fdd2b08 commit 8268507
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 95 deletions.
1 change: 1 addition & 0 deletions addOns/soap/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Maintenance changes.
- Depend on newer versions of Automation Framework and Common Library add-ons (Related to Issue 7961).
- Use Common Library add-on to obtain the Value Generator (Issue 8016).
- The SOAP Support Script has been superseded by a variant (Issue 6500).

## [18] - 2023-07-11
### Changed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@

import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.security.InvalidParameterException;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -38,11 +35,7 @@
import org.parosproxy.paros.extension.SessionChangedListener;
import org.parosproxy.paros.model.Session;
import org.zaproxy.addon.commonlib.ExtensionCommonlib;
import org.zaproxy.zap.extension.ascan.ExtensionActiveScan;
import org.zaproxy.zap.extension.script.ExtensionScript;
import org.zaproxy.zap.extension.script.ScriptEngineWrapper;
import org.zaproxy.zap.extension.script.ScriptType;
import org.zaproxy.zap.extension.script.ScriptWrapper;
import org.zaproxy.zap.model.ValueGenerator;
import org.zaproxy.zap.view.ZapMenuItem;

Expand All @@ -56,7 +49,6 @@ public class ExtensionImportWSDL extends ExtensionAdaptor {

private static final Logger LOGGER = LogManager.getLogger(ExtensionImportWSDL.class);
private static final String THREAD_PREFIX = "ZAP-Import-WSDL-";
private static final String SCRIPT_NAME = "SOAP Support.js";

private ZapMenuItem menuImportWsdl;
private ImportDialog importDialog;
Expand Down Expand Up @@ -91,6 +83,7 @@ public void hook(ExtensionHook extensionHook) {
super.hook(extensionHook);

extensionHook.addApiImplementor(new SoapAPI(this));
extensionHook.addVariant(VariantSoap.class);

if (hasView()) {
extensionHook.getHookMenu().addImportMenuItem(getMenuImportWsdl());
Expand All @@ -117,11 +110,11 @@ public void sessionModeChanged(Control.Mode mode) {}

@Override
public void postInit() {
super.postInit();
try {
addScript();
} catch (IOException e) {
LOGGER.warn("Could not add SOAP Support script.");
ExtensionScript extScript =
Control.getSingleton().getExtensionLoader().getExtension(ExtensionScript.class);
String scriptName = "SOAP Support.js";
if (extScript != null && extScript.getScript(scriptName) != null) {
extScript.removeScript(extScript.getScript(scriptName));
}
}

Expand All @@ -131,7 +124,6 @@ public void unload() {
if (importDialog != null) {
importDialog.dispose();
}
removeScript();
}

@Override
Expand Down Expand Up @@ -180,55 +172,6 @@ public void fileUrlWSDLImport(final File file) {
parser.extFileWSDLImport(file, THREAD_PREFIX + threadId++);
}

private void addScript() throws IOException {
ExtensionScript extScript =
Control.getSingleton().getExtensionLoader().getExtension(ExtensionScript.class);
if (extScript != null && extScript.getScript(SCRIPT_NAME) == null) {
ScriptType variantType =
extScript.getScriptType(ExtensionActiveScan.SCRIPT_TYPE_VARIANT);
ScriptEngineWrapper engine = getEngine(extScript, "Oracle Nashorn");
if (variantType != null && engine != null) {
File scriptPath =
Paths.get(
Constant.getZapHome(),
ExtensionScript.SCRIPTS_DIR,
ExtensionScript.SCRIPTS_DIR,
ExtensionActiveScan.SCRIPT_TYPE_VARIANT,
SCRIPT_NAME)
.toFile();
ScriptWrapper script =
new ScriptWrapper(
SCRIPT_NAME,
Constant.messages.getString("soap.script.description"),
engine,
variantType,
true,
scriptPath);
script.setLoadOnStart(true);
script.reloadScript();
extScript.addScript(script, false);
}
}
}

private void removeScript() {
ExtensionScript extScript =
Control.getSingleton().getExtensionLoader().getExtension(ExtensionScript.class);
if (extScript != null && extScript.getScript(SCRIPT_NAME) != null) {
extScript.removeScript(extScript.getScript(SCRIPT_NAME));
}
}

private static ScriptEngineWrapper getEngine(ExtensionScript ext, String engineName) {
try {
return ext.getEngineWrapper(engineName);
} catch (InvalidParameterException e) {
LOGGER.warn(
"The {} engine was not found, script variant will not be added.", engineName);
}
return null;
}

@Override
public boolean canUnload() {
return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2023 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.soap;

import java.util.ArrayList;
import java.util.List;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.parosproxy.paros.core.scanner.NameValuePair;
import org.parosproxy.paros.core.scanner.Variant;
import org.parosproxy.paros.network.HttpMessage;

public class VariantSoap implements Variant {

private static final String[] EMPTY_ARRAY = {};

@Override
public void setMessage(HttpMessage msg) {}

@Override
public List<NameValuePair> getParamList() {
return List.of();
}

@Override
public String setEscapedParameter(
HttpMessage msg, NameValuePair originalPair, String param, String value) {
return setParameter(msg, originalPair, param, value);
}

@Override
public String setParameter(
HttpMessage msg, NameValuePair originalPair, String param, String value) {
return null;
}

@Override
public List<String> getTreePath(HttpMessage msg) throws URIException {
String nodeName = SitesTreeHelper.getNodeName(msg);
if (nodeName.isEmpty()) {
// Not a SOAP message.
return null;
}

URI uri = msg.getRequestHeader().getURI();
String[] path = uri.getRawPath() != null ? uri.getPath().split("/", 0) : EMPTY_ARRAY;
List<String> list = new ArrayList<>(path.length);
for (var i = 1; i < path.length; i++) {
list.add(path[i]);
}
list.add(nodeName);

return list;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ soap.importDialog.title = Import WSDL File

soap.name = SOAP/WSDL Support

soap.script.description = Script for representing each SOAP operation uniquely in the Sites Tree.

soap.soapactionspoofing.alertInfo = \ SOAP version 1.{0}\nOriginal SOAP Action: {1}\nSpoofed SOAP Action: {2}
soap.soapactionspoofing.desc = An unintended SOAP operation was executed by the server.
soap.soapactionspoofing.empty_response = Response is empty.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Zed Attack Proxy (ZAP) and its related class files.
*
* ZAP is an HTTP/HTTPS proxy for assessing web application security.
*
* Copyright 2023 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.soap;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;

import java.util.List;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.parosproxy.paros.network.HttpMessage;

/** Unit test for {@link VariantSoap}. */
class VariantSoapUnitTest {

private HttpMessage msg;
private VariantSoap variant;

@BeforeEach
void setUp() throws Exception {
variant = new VariantSoap();
msg = new HttpMessage();
msg.getRequestHeader().setURI(new URI("http://www.example.org/temp", true));
msg.setRequestBody(
"<?xml version=\"1.0\"?>\n"
+ "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" soap:encodingStyle=\"http://www.w3.org/2003/05/soap-encoding\">\n"
+ "<soap:Body xmlns:m=\"http://www.example.org/temp\">\n"
+ " <m:GetTemp>\n"
+ " <m:Location>Sun</m:Location>\n"
+ " </m:GetTemp>\n"
+ "</soap:Body>\n"
+ "</soap:Envelope>");
}

@Test
void shouldHaveNoParameters() {
// Given / When
variant.setMessage(msg);
// Then
assertThat(variant.getParamList(), is(empty()));
}

@Test
void shouldUseDefaultLeafName() {
// Given / When
String leafName = variant.getLeafName("nodeName", msg);
// Then
assertThat(leafName, is(nullValue()));
}

@Test
void shouldReturnTreePathForSoapMessage() throws URIException {
// Given / When
List<String> treePath = variant.getTreePath(msg);
// Then
assertThat(treePath, is(contains("temp", "GetTemp (v1.2)")));
}

@Test
void shouldReturnDefaultPathForNonSoapMessage() throws URIException {
// Given
msg = new HttpMessage();
// When
List<String> treePath = variant.getTreePath(msg);
// Then
assertThat(treePath, is(nullValue()));
}
}

0 comments on commit 8268507

Please sign in to comment.