org.zaproxy.zap.extension.proxies.ExtensionProxies.java Source code

Java tutorial

Introduction

Here is the source code for org.zaproxy.zap.extension.proxies.ExtensionProxies.java

Source

/*
 * Zed Attack Proxy (ZAP) and its related class files.
 * 
 * ZAP is an HTTP/HTTPS proxy for assessing web application security.
 * 
 * Copyright 2017 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.proxies;

import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.httpclient.URI;
import org.apache.log4j.Logger;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.control.Control;
import org.parosproxy.paros.core.proxy.ProxyParam;
import org.parosproxy.paros.core.proxy.ProxyServer;
import org.parosproxy.paros.extension.ExtensionAdaptor;
import org.parosproxy.paros.extension.ExtensionHook;
import org.parosproxy.paros.extension.OptionsChangedListener;
import org.parosproxy.paros.extension.history.ExtensionHistory;
import org.parosproxy.paros.model.OptionsParam;
import org.zaproxy.zap.utils.ZapXmlConfiguration;

public class ExtensionProxies extends ExtensionAdaptor implements OptionsChangedListener {

    public static final String NAME = "ExtensionProxies";
    public static final String ZAP_PROXY_THREAD_PREFIX = "ZAP-";

    private ProxiesParam proxiesParam = null;
    private OptionsProxiesPanel optionsProxiesPanel = null;
    private Map<String, ProxyServer> proxyServers = new HashMap<String, ProxyServer>();

    private static Logger log = Logger.getLogger(ExtensionProxies.class);

    public ExtensionProxies() {
        super();
        initialize();
    }

    private void initialize() {
        this.setName(NAME);
        this.setOrder(310);
    }

    @Override
    public void init() {
    }

    @Override
    public String getUIName() {
        return Constant.messages.getString("proxies.name");
    }

    @Override
    public void hook(ExtensionHook extensionHook) {
        super.hook(extensionHook);

        extensionHook.addOptionsParamSet(this.getParam());
        extensionHook.addOptionsChangedListener(this);

        if (getView() != null) {
            extensionHook.getHookView().addOptionPanel(getOptionsProxiesPanel());
        }

        extensionHook.addApiImplementor(new ProxiesAPI(this));
    }

    @Override
    public void stop() {
        super.stop();
        // Stop all of the running servers
        for (Entry<String, ProxyServer> entry : proxyServers.entrySet()) {
            stopProxyServer(entry.getKey(), entry.getValue());
        }
        proxyServers.clear();
    }

    @Override
    public void start() {
        restartProxies();
    }

    @Override
    public void optionsChanged(OptionsParam optionsParam) {
        restartProxies();
    }

    private void restartProxies() {
        List<ProxiesParamProxy> proxyParams = this.getParam().getProxies();
        Map<String, ProxyServer> currentProxies = proxyServers;
        proxyServers = new HashMap<String, ProxyServer>();
        for (ProxiesParamProxy proxyParam : proxyParams) {
            if (proxyParam.isEnabled()) {
                // Treat disabled proxies as if they dont really exist
                String key = createProxyKey(proxyParam.getAddress(), proxyParam.getPort());
                ProxyServer proxy = currentProxies.remove(key);
                if (proxy == null) {
                    // Its a new one
                    proxy = startProxyServer(proxyParam);
                } else {
                    applyProxyOptions(proxyParam, proxy);
                }
                proxyServers.put(key, proxy);
            }
        }
        // Any proxies left have been removed
        for (Entry<String, ProxyServer> entry : currentProxies.entrySet()) {
            stopProxyServer(entry.getKey(), entry.getValue());
        }
    }

    private static void applyProxyOptions(ProxiesParamProxy param, ProxyServer proxyServer) {
        ProxyParam proxyParam = proxyServer.getProxyParam();
        proxyParam.setAlwaysDecodeGzip(param.isAlwaysDecodeGzip());
        proxyParam.setBehindNat(param.isBehindNat());
        proxyParam.setRemoveUnsupportedEncodings(param.isRemoveUnsupportedEncodings());
    }

    /**
     * Creates a key that identifies a proxy, to be used with {@link #proxyServers}.
     *
     * @param address the address of the proxy.
     * @param port the port of the proxy.
     * @return a key that identifies the proxy.
     */
    private static String createProxyKey(String address, int port) {
        return address + ":" + port;
    }

    private ProxyServer startProxyServer(ProxiesParamProxy param) {
        String address = param.getAddress();
        int port = param.getPort();
        String key = createProxyKey(address, port);
        log.info("Starting alt proxy server: " + key);
        ProxyServer proxyServer = new ProxyServer(ZAP_PROXY_THREAD_PREFIX + key) {

            @Override
            public boolean excludeUrl(URI uri) {
                String uriString = uri.toString();
                for (String excludePattern : getModel().getOptionsParam().getGlobalExcludeURLParam()
                        .getTokensNames()) {
                    if (uriString.matches(excludePattern)) {
                        return true;
                    }
                }

                for (String excludePattern : getModel().getSession().getExcludeFromProxyRegexs()) {
                    if (uriString.matches(excludePattern)) {
                        return true;
                    }
                }
                return false;
            }
        };
        proxyServer.getProxyParam().load(new ZapXmlConfiguration());
        applyProxyOptions(param, proxyServer);
        proxyServer.setConnectionParam(getModel().getOptionsParam().getConnectionParam());
        // Note that if this is _not_ set then the proxy will go into a nasty loop if you point a browser at it
        proxyServer.setEnableApi(true);
        if (proxyServer.startServer(address, port, false) > 0) {
            Control.getSingleton().getExtensionLoader().getExtension(ExtensionHistory.class)
                    .registerProxy(proxyServer);
        }
        return proxyServer;
    }

    private void stopProxyServer(String proxyKey, ProxyServer proxyServer) {
        log.info("Stopping alt proxy server: " + proxyKey);
        Control.getSingleton().getExtensionLoader().getExtension(ExtensionHistory.class)
                .unregisterProxy(proxyServer);
        proxyServer.stopServer();
    }

    public List<ProxiesParamProxy> getAdditionalProxies() {
        return this.getParam().getProxies();
    }

    public ProxiesParamProxy getAdditionalProxy(String address, int port) {
        for (ProxiesParamProxy p : this.getParam().getProxies()) {
            if (p.getAddress().equals(address) && p.getPort() == port) {
                return new ProxiesParamProxy(p);
            }
        }
        return null;
    }

    public void addProxy(ProxiesParamProxy proxy) {
        String key = createProxyKey(proxy.getAddress(), proxy.getPort());
        if (this.getAdditionalProxy(proxy.getAddress(), proxy.getPort()) != null) {
            throw new IllegalArgumentException("Proxy already exists: " + key);
        }
        if (!this.canListenOn(proxy.getAddress(), proxy.getPort())) {
            throw new IllegalArgumentException("Cannot listen on: " + key);
        }

        ProxyServer proxyServer = startProxyServer(proxy);
        proxyServers.put(key, proxyServer);
        this.getParam().addProxy(proxy);
    }

    public void removeProxy(String address, int port) {
        String key = createProxyKey(address, port);
        ProxyServer proxyServer = proxyServers.remove(key);
        if (proxyServer == null) {
            throw new IllegalArgumentException("Proxy not found: " + key);
        }
        this.stopProxyServer(key, proxyServer);
        this.getParam().removeProxy(address, port);
    }

    protected boolean canListenOn(String address, int port) {
        ServerSocket socket = null;
        try {
            socket = new ServerSocket(port, 5, InetAddress.getByName(address));
            return true;
        } catch (IOException e) {
            return false;
        } finally {
            if (socket != null)
                try {
                    socket.close();
                } catch (IOException e) {
                    // Ignore
                }
        }
    }

    private OptionsProxiesPanel getOptionsProxiesPanel() {
        if (optionsProxiesPanel == null) {
            optionsProxiesPanel = new OptionsProxiesPanel(this);
        }
        return optionsProxiesPanel;
    }

    private ProxiesParam getParam() {
        if (this.proxiesParam == null) {
            this.proxiesParam = new ProxiesParam();
        }
        return this.proxiesParam;
    }

    @Override
    public String getAuthor() {
        return Constant.ZAP_TEAM;
    }

    @Override
    public String getDescription() {
        return Constant.messages.getString("proxies.desc");
    }

    @Override
    public URL getURL() {
        try {
            return new URL(Constant.ZAP_HOMEPAGE);
        } catch (MalformedURLException e) {
            return null;
        }
    }

}