org.zaproxy.zap.extension.selenium.ExtensionSelenium.java Source code

Java tutorial

Introduction

Here is the source code for org.zaproxy.zap.extension.selenium.ExtensionSelenium.java

Source

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

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang.Validate;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.safari.SafariDriver;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.extension.ExtensionAdaptor;
import org.parosproxy.paros.extension.ExtensionHook;
import org.zaproxy.zap.Version;
import org.zaproxy.zap.extension.api.API;

/**
 * An {@code Extension} that provides {@code WebDriver} implementations for several {@code Browser}s.
 *
 * @see WebDriver
 * @see Browser
 */
public class ExtensionSelenium extends ExtensionAdaptor {

    public static final String NAME = "ExtensionSelenium";

    private static final int MIN_PORT = 1;

    private static final int MAX_PORT = 65535;

    /**
     * The version of the extension. As consistency should be kept in sync with the version of the add-on (under ZapAddOn.xml
     * file).
     */
    private static final Version CURRENT_VERSION = new Version("1.0.0");

    private SeleniumOptions options;
    private SeleniumOptionsPanel optionsPanel;

    private SeleniumAPI seleniumApi;

    /**
     * A list containing all supported browsers by this extension.
     * <p>
     * Lazy initialised with {@code initialiseBrowserUIList()}.
     * 
     * @see #initialiseBrowserUIList()
     */
    private List<BrowserUI> browserUIList;

    public ExtensionSelenium() {
        super(NAME, CURRENT_VERSION);
    }

    @Override
    public String getUIName() {
        return getMessages().getString("selenium.extension.ui.name");
    }

    @Override
    public String getDescription() {
        return getMessages().getString("selenium.extension.desc");
    }

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

    @Override
    public void init() {
        super.init();

        seleniumApi = new SeleniumAPI(getOptions());
    }

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

        extensionHook.addOptionsParamSet(getOptions());

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

        API.getInstance().registerApiImplementor(seleniumApi);
    }

    @Override
    public boolean canUnload() {
        return true;
    }

    @Override
    public void unload() {
        super.unload();

        API.getInstance().removeApiImplementor(seleniumApi);
    }

    /**
     * Returns the (internationalised) name of the given {@code browser}.
     *
     * @param browser the browser whose name will be obtained
     * @return a String containing the name of the browser
     * @see #getBrowserUIList()
     * @see #createBrowsersComboBoxModel()
     */
    public String getName(Browser browser) {
        return getMessages().getString("selenium.browser.name." + browser.getId());
    }

    /**
     * Returns a new {@code BrowsersComboBoxModel} with the browsers returned by {@code getBrowserUIList()}.
     *
     * @return a new {@code BrowsersComboBoxModel} with the browsers returned by {@code getBrowserUIList()}
     * @see #getBrowserUIList()
     */
    public BrowsersComboBoxModel createBrowsersComboBoxModel() {
        return new BrowsersComboBoxModel(getBrowserUIList());
    }

    /**
     * Gets the (unmodifiable) list of {@code BrowseUI} objects for all {@code Browser}s supported by this extension.
     *
     * @return an unmodifiable list with all browsers supported by this extension
     * @see #getName(Browser)
     * @see #createBrowsersComboBoxModel()
     */
    public List<BrowserUI> getBrowserUIList() {
        if (browserUIList == null) {
            initialiseBrowserUIList();
        }
        return browserUIList;
    }

    /**
     * Initialises the instance variable {@code browserUIList} with all {@code Browser}s supported by this extension.
     * 
     * @code {@link #browserUIList}
     */
    private synchronized void initialiseBrowserUIList() {
        if (browserUIList == null) {
            List<BrowserUI> browsers = new ArrayList<>(Browser.values().length);
            for (Browser browser : Browser.values()) {
                browsers.add(new BrowserUI(getName(browser), browser));
            }
            Collections.sort(browsers);
            browserUIList = Collections.unmodifiableList(browsers);
        }
    }

    private SeleniumOptions getOptions() {
        if (options == null) {
            options = new SeleniumOptions();
        }
        return options;
    }

    private SeleniumOptionsPanel getOptionsPanel() {
        if (optionsPanel == null) {
            optionsPanel = new SeleniumOptionsPanel(getMessages());
        }
        return optionsPanel;
    }

    /**
     * Gets a {@code WebDriver} for the given {@code browser}.
     *
     * @param browser the target browser
     * @return the {@code WebDriver} to the given {@code browser}
     * @see #getWebDriver(Browser, String, int)
     */
    public static WebDriver getWebDriver(Browser browser) {
        return getWebDriverImpl(browser, null, -1);
    }

    /**
     * Gets a {@code WebDriver} for the given {@code browser} proxying through the given address and port.
     *
     * @param browser the target browser
     * @param proxyAddress the address of the proxy
     * @param proxyPort the port of the proxy
     * @return the {@code WebDriver} to the given {@code browser}, proxying through the given address and port
     * @throws IllegalArgumentException if {@code proxyAddress} is {@code null} or empty, or if {@code proxyPort} is not a valid
     *             port number (between 1 and 65535)
     * @see #getWebDriver(Browser)
     */
    public static WebDriver getWebDriver(Browser browser, String proxyAddress, int proxyPort) {
        Validate.notEmpty(proxyAddress, "Parameter proxyAddress must not be null nor empty.");
        if (proxyPort < MIN_PORT || proxyPort > MAX_PORT) {
            throw new IllegalArgumentException(
                    "Parameter proxyPort must be under: " + MIN_PORT + " <= port <= " + MAX_PORT);
        }

        return getWebDriverImpl(browser, proxyAddress, proxyPort);
    }

    private static WebDriver getWebDriverImpl(Browser browser, String proxyAddress, int proxyPort) {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        if (proxyAddress != null) {
            String httpProxy = proxyAddress + ":" + proxyPort;
            Proxy proxy = new Proxy();
            proxy.setHttpProxy(httpProxy);
            proxy.setSslProxy(httpProxy);
            capabilities.setCapability(CapabilityType.PROXY, proxy);
        }

        switch (browser) {
        case CHROME:
            return new ChromeDriver(capabilities);
        case FIREFOX:
            return new FirefoxDriver(capabilities);
        case HTML_UNIT:
            return new HtmlUnitDriver(capabilities);
        case INTERNET_EXPLORER:
            capabilities.setCapability(InternetExplorerDriver.IE_USE_PRE_PROCESS_PROXY, true);

            return new InternetExplorerDriver(capabilities);
        /* No longer supported in the Selenium standalone jar
         * need to decide if we support older Opera versions 
        case OPERA:
        OperaDriver driver = new OperaDriver(capabilities);
        if (proxyAddress != null) {
            driver.proxy().setProxyLocal(true);
            // XXX Workaround, in operadriver <= 1.5 the HTTPS proxy settings are not set according to desired capabilities
            // For more details see OperaProxy.parse(Proxy)
            driver.proxy().setHttpsProxy(proxyAddress + ":" + proxyPort);
        }
            
        return driver;
        */
        case PHANTOM_JS:
            final ArrayList<String> cliArgs = new ArrayList<>(4);
            cliArgs.add("--ssl-protocol=any");
            cliArgs.add("--ignore-ssl-errors=yes");

            cliArgs.add("--webdriver-logfile=" + Constant.getZapHome() + "/phantomjsdriver.log");
            cliArgs.add("--webdriver-loglevel=WARN");

            capabilities.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cliArgs);

            return new PhantomJSDriver(capabilities);
        case SAFARI:
            return new SafariDriver(capabilities);
        default:
            throw new IllegalArgumentException("Unknown browser: " + browser);
        }
    }

    /**
     * Returns an error message for the given {@code browser} that failed to start.
     * <p>
     * Some browsers require extra steps to start them with a WebDriver, for such cases there's a custom error message, for the
     * remaining cases there's a generic error message.
     *
     * @param browser the browser that failed to start
     * @return a {@code String} with the error message
     */
    public String getWarnMessageFailedToStart(Browser browser) {
        switch (browser) {
        case CHROME:
            return getMessages().getString("selenium.warn.message.failed.start.browser.chrome");
        case INTERNET_EXPLORER:
            return getMessages().getString("selenium.warn.message.failed.start.browser.ie");
        case PHANTOM_JS:
            return getMessages().getString("selenium.warn.message.failed.start.browser.phantomjs");
        default:
            return MessageFormat.format(getMessages().getString("selenium.warn.message.failed.start.browser"),
                    getName(browser));
        }
    }

    public List<Browser> getConfiguredBrowsers() {
        List<Browser> browsers = new ArrayList<>();
        // No configurations, just install the browser or
        // browser plugins to work properly
        browsers.add(Browser.HTML_UNIT);
        browsers.add(Browser.FIREFOX);
        browsers.add(Browser.OPERA);
        browsers.add(Browser.SAFARI);

        if (!getOptions().getChromeDriverPath().isEmpty()) {
            browsers.add(Browser.CHROME);
        }
        if (!getOptions().getIeDriverPath().isEmpty()) {
            browsers.add(Browser.INTERNET_EXPLORER);
        }
        if (!getOptions().getPhantomJsBinaryPath().isEmpty()) {
            browsers.add(Browser.PHANTOM_JS);
        }
        return browsers;
    }
}