All Downloads are FREE. Search and download functionalities are using the official Maven repository.

au.com.agic.apptesting.utils.impl.ZapProxyUtilsImpl Maven / Gradle / Ivy

package au.com.agic.apptesting.utils.impl;

import static com.google.common.base.Preconditions.checkNotNull;

import au.com.agic.apptesting.constants.Constants;
import au.com.agic.apptesting.exception.ProxyException;
import au.com.agic.apptesting.utils.FileSystemUtils;
import au.com.agic.apptesting.utils.LocalProxyUtils;
import au.com.agic.apptesting.utils.ProxyDetails;
import au.com.agic.apptesting.utils.ProxySettings;
import au.com.agic.apptesting.utils.ServerPortUtils;
import au.com.agic.apptesting.utils.SystemPropertyUtils;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zaproxy.clientapi.core.ClientApi;
import org.zaproxy.zap.ZAP;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import javax.validation.constraints.NotNull;

/**
 * An implementation of the local proxy service
 */
public class ZapProxyUtilsImpl implements LocalProxyUtils {

	public static final String PROXY_NAME = "ZAP";
	private static final Logger LOGGER = LoggerFactory.getLogger(ZapProxyUtilsImpl.class);
	private static final SystemPropertyUtils SYSTEM_PROPERTY_UTILS = new SystemPropertyUtilsImpl();
	private static final ServerPortUtils SERVER_PORT_UTILS = new ServerPortUtilsImpl();
	private static final FileSystemUtils FILE_SYSTEM_UTILS = new FileSystemUtilsImpl();

	private static final int WAIT_FOR_START = 30000;

	@Override
	public Optional> initProxy(
			@NotNull final List tempFolders,
			@NotNull final Optional upstreamProxy) {

		checkNotNull(tempFolders);
		checkNotNull(upstreamProxy);

		try {
			final String proxyName =
				SYSTEM_PROPERTY_UTILS.getProperty(Constants.START_INTERNAL_PROXY);

			if (StringUtils.equalsIgnoreCase(Constants.ZED_ATTACK_PROXY, proxyName)) {
				return Optional.of(startZAPProxy(tempFolders, upstreamProxy));
			}

			LOGGER.info("The value assigned to the \"{}\" system property "
				+ "of \"{}\" was empty or not recognised",
				Constants.START_INTERNAL_PROXY,
				proxyName);

			return Optional.empty();
		} catch (final Exception ex) {
			throw new ProxyException(ex);
		}
	}

	/**
	 * Starts the Zed Attack Proxy
	 *
	 * @param tempFolders A list of folders that need to be deleted once the app is finished
	 * @return The port that the proxy is listening on
	 */
	private ProxyDetails startZAPProxy(
			@NotNull final List tempFolders,
			@NotNull final Optional upstreamProxy) throws Exception {

		checkNotNull(tempFolders);
		checkNotNull(upstreamProxy);

		/*
			There is a small chance that between the call to getFreePort() and the
			actual execution of the ZAP application, some other thread could get
			the same port. We synchronize here to prevent threads in the testing app
			from colliding.

			Of course, there is also the small possibility that another application
			could also take the port between the call to getFreePort() and the
			actual execution of the ZAP application, but there isn't much we can do
			about that.
		 */
		synchronized (ServerPortUtils.class) {
			/*
				Grab an open port
			 */
			final Integer freePort = SERVER_PORT_UTILS.getFreePort();

			/*
				ZAP expects to find files on the filesystem, not in a self contained jar,
				so we copy them to a temp location
			 */
			final Path zapdir = Files.createTempDirectory("zaptmp");

			/*
				It is handy to be able to see this dir
			 */
			LOGGER.debug("Created install dir for ZAP in {}", zapdir);

			/*
				Make a note of the temp folder so it can be cleaned up later
			 */
			tempFolders.add(zapdir.toFile());

			/*
				Copy the ZAP files
			 */
			FILE_SYSTEM_UTILS.copyFromJar(getClass().getResource("/zap").toURI(), zapdir);

			/*
				Build up the command line args
			 */
			final List args = new ArrayList<>(Arrays.asList(
				"-daemon",
				"-port", freePort.toString(),
				"-dir", zapdir.toString(),
				"-installdir", zapdir.toString(),
				"-config", "api.disablekey=true"
			));

			if (upstreamProxy.isPresent()) {
				args.addAll(Arrays.asList(
					"-config", "connection.proxyChain.enabled=true",
					"-config", "connection.proxyChain.hostName="
						+ upstreamProxy.get().getHost(),
					"-config", "connection.proxyChain.port="
						+ upstreamProxy.get().getPort()
				));

				if (StringUtils.isNotBlank(upstreamProxy.get().getUsername())) {
					args.addAll(Arrays.asList(
						"-config", "connection.proxyChain.userName="
							+ upstreamProxy.get().getUsername(),
						"-config", "connection.proxyChain.password="
							+ upstreamProxy.get().getPassword()
					));
				}

				if (StringUtils.isNotBlank(upstreamProxy.get().getRealm())) {
					args.addAll(Arrays.asList(
						"-config", "connection.proxyChain.realm="
							+ upstreamProxy.get().getRealm()
					));
				}
			}

			/*
				Run ZAP
			 */
			ZAP.main(args.toArray(new String[args.size()]));

			final ClientApi clientApi = new ClientApi("localhost", freePort);
			clientApi.waitForSuccessfulConnectionToZap(WAIT_FOR_START);

			return new ProxyDetailsImpl<>(
				freePort,
				false,
				PROXY_NAME,
				new ClientApi("localhost", freePort));
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy