diff --git a/README.MD b/README.MD
index 425be9908..459fd49e6 100644
--- a/README.MD
+++ b/README.MD
@@ -55,7 +55,7 @@ wish to simply try/test/run the current development version of WebGoat
### Prerequisites:
* Java VM 1.8
-## Easy Run Instructions:
+## Standalone
#### 1. Download the easy run executable jar file which contains all the lessons and a embedded Tomcat server:
@@ -73,9 +73,35 @@ Using the `--help` option will show the allowed command line arguments.
#### 3. Browse to the url shown in the console and happy hacking !
+## Vagrant
+
+To run WebGoat with Vagrant you must first have Vagrant and Virtualbox installed.
+
+```shell
+ $ cd WebGoat/webgoat-images/vagrant-users
+ $ vagrant up
+```
+
+Once you see the message 'Browse to http://localhost:9999/WebGoat and happy hacking! you can open a
+browser.
+
# For Developers
+## Vagrant
+
+For an easy development experience you can use Vagrant. Note you should have Vagrant and Virtualbox installed on your system.
+
+```shell
+ $ cd WebGoat/webgoat-images/vagrant-developers
+ $ vagrant up
+```
+
+Once the provisioning is complete login to the Virtualbox with username vagrant and password vagrant.
+The source code will be available in the home directory.
+
+## Set up manual
+
Follow these instructions if you wish to run Webgoat and modify the source code as well.
### Prerequisites:
diff --git a/webgoat-container/src/test/java/org/owasp/webgoat/plugins/TestUtils.java b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/TestUtils.java
new file mode 100644
index 000000000..89c95cebd
--- /dev/null
+++ b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/TestUtils.java
@@ -0,0 +1,57 @@
+package org.owasp.webgoat.plugins;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.NoSuchElementException;
+import org.openqa.selenium.StaleElementReferenceException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.FluentWait;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+/**
+ * ************************************************************************************************
+ * This file is part of WebGoat, an Open Web Application Security Project utility. For details,
+ * please see http://www.owasp.org/
+ *
+ * Copyright (c) 2002 - 20014 Bruce Mayhew
+ *
+ * This program is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU General Public License as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with this program; if
+ * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Getting Source ==============
+ *
+ * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
+ * projects.
+ *
+ *
+ * @author WebGoat
+ * @version $Id: $Id
+ * @since September 22, 2016
+ */
+public class TestUtils {
+
+ public static void assertTitlePresent(WebDriver webDriver, String title) {
+ FluentWait wait = new WebDriverWait(webDriver, 15); // wait for a maximum of 15 seconds
+ wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-title"), title));
+ }
+
+ public static FluentWait createDefaultWait(WebDriver webDriver) {
+ return new FluentWait(webDriver)
+ .withTimeout(10, SECONDS)
+ .pollingEvery(2, SECONDS)
+ .ignoring(NoSuchElementException.class)
+ .ignoring(StaleElementReferenceException.class);
+
+ }
+}
diff --git a/webgoat-container/src/test/java/org/owasp/webgoat/plugins/WebGoatIT.java b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/WebGoatIT.java
index f465b020f..ec4fb9867 100644
--- a/webgoat-container/src/test/java/org/owasp/webgoat/plugins/WebGoatIT.java
+++ b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/WebGoatIT.java
@@ -14,7 +14,6 @@ import org.junit.runner.RunWith;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.NoSuchElementException;
-import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.CapabilityType;
@@ -29,11 +28,12 @@ import java.net.URL;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
-import static com.github.webdriverextensions.WebDriverExtensionsContext.getDriver;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.owasp.webgoat.plugins.TestUtils.assertTitlePresent;
+import static org.owasp.webgoat.plugins.TestUtils.createDefaultWait;
/**
@@ -138,10 +138,10 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
browsers.add(new String[]{"Windows 7", "45", "chrome", null, null});
// windows 10, Chrome 46
- browsers.add(new String[]{"Windows 10", "46", "chrome", null, null});
+ //browsers.add(new String[]{"Windows 10", "46", "chrome", null, null});
// windows 10, Firefox 38
- browsers.add(new String[]{"Windows 10", "38", "firefox", null, null});
+ // browsers.add(new String[]{"Windows 10", "38", "firefox", null, null});
// Linux, Firefox 37
browsers.add(new String[]{"Linux", "37", "firefox", null, null});
@@ -207,7 +207,7 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
new URL("http://" + authentication.getUsername() + ":" + authentication.getAccessKey() +
"@ondemand.saucelabs.com:80/wd/hub"),
capabilities));
- this.getWebDriver().manage().timeouts().implicitlyWait(2, SECONDS);
+ this.getWebDriver().manage().timeouts().implicitlyWait(4, SECONDS);
this.sessionId.set((((RemoteWebDriver) getWebDriver()).getSessionId()).toString());
String message = String.format("SauceOnDemandSessionID=%1$s job-name=%2$s", this.sessionId, methodName);
@@ -283,7 +283,6 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
String pageSource = getWebDriver().getPageSource();
-
assertTrue("Page source should contain lessons: Test 1", pageSource.contains("Reflected XSS"));
assertTrue("Page source should contain lessons: Test 2", pageSource.contains("Access Control Flaws"));
assertTrue("Page source should contain lessons: Test 34", pageSource.contains("Fail Open Authentication Scheme"));
@@ -297,17 +296,12 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().get(baseWebGoatUrl + "/service/restartlesson.mvc");
getWebDriver().get(baseWebGoatUrl + "/start.mvc#attack/1708534694/200");
- FluentWait wait = new WebDriverWait(getWebDriver(), 15); // wait for a maximum of 15 seconds
+ FluentWait wait = createDefaultWait(getWebDriver());
wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-title"), "Using an Access Control Matrix"));
- wait = new FluentWait(getWebDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class)
- .ignoring(StaleElementReferenceException.class);
WebElement user = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("User")));
user.click();
- user.sendKeys("Larry");
+ user.sendKeys("L");
WebElement resource = getWebDriver().findElement(By.name("Resource"));
resource.click();
@@ -316,11 +310,6 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
WebElement submit = getWebDriver().findElement(By.name("SUBMIT"));
submit.click();
- wait = new FluentWait(getWebDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
-
wait.until(new Predicate() {
public boolean apply(WebDriver webDriver) {
return webDriver.getPageSource().contains("Congratulations");
@@ -336,48 +325,35 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().get(baseWebGoatUrl + "/service/restartlesson.mvc");
getWebDriver().get(baseWebGoatUrl + "/start.mvc#attack/160587164/200");
- FluentWait wait = new WebDriverWait(getDriver(), 15); // wait for a maximum of 15 seconds
- wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-title"), "LAB: Role Based Access Control"));
+ assertTitlePresent(getWebDriver(), "LAB: Role Based Access Control");
+ this.getWebDriver().manage().timeouts().implicitlyWait(4, SECONDS);
- wait = new FluentWait(getDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class)
- .ignoring(StaleElementReferenceException.class);
+ FluentWait wait = createDefaultWait(getWebDriver());
WebElement user = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("employee_id")));
user.click();
user.sendKeys("T");
- WebElement resource = getDriver().findElement(By.name("password"));
+ WebElement resource = getWebDriver().findElement(By.name("password"));
resource.click();
resource.sendKeys("tom");
- WebElement submit = getDriver().findElement(By.name("action"));
+ WebElement submit = getWebDriver().findElement(By.name("action"));
submit.click();
- wait = new FluentWait(getDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
+ wait = createDefaultWait(getWebDriver());
wait.until(new Predicate() {
public boolean apply(WebDriver webDriver) {
return webDriver.getPageSource().contains("Welcome Back");
}
});
- JavascriptExecutor javascript = (JavascriptExecutor) getDriver();
+ JavascriptExecutor javascript = (JavascriptExecutor) getWebDriver();
String value = "document.getElementsByName('action')[0].value='DeleteProfile';";
javascript.executeScript(value);
-
- WebElement viewProfile = getDriver().findElements(By.name("action")).get(0);
+ WebElement viewProfile = getWebDriver().findElements(By.name("action")).get(0);
viewProfile.click();
- wait = new FluentWait(getDriver())
- .withTimeout(40, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
-
wait.until(new Predicate() {
public boolean apply(WebDriver webDriver) {
return webDriver.getPageSource().contains("Stage 2");
@@ -387,48 +363,37 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
//
// Stage 3
//
- getDriver().get(baseWebGoatUrl + "/start.mvc#attack/160587164/200/3");
+ getWebDriver().get(baseWebGoatUrl + "/start.mvc#attack/160587164/200/3");
+ assertTitlePresent(getWebDriver(), "LAB: Role Based Access Control");
user = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("employee_id")));
user.click();
user.sendKeys("T");
- resource = getDriver().findElement(By.name("password"));
+ resource = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("password")));
resource.click();
resource.sendKeys("tom");
- submit = getDriver().findElement(By.name("action"));
+ submit = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("action")));
submit.click();
- wait = new FluentWait(getDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
-
wait.until(new Predicate() {
public boolean apply(WebDriver webDriver) {
return webDriver.getPageSource().contains("Welcome Back");
}
});
- javascript = (JavascriptExecutor) getDriver();
+ javascript = (JavascriptExecutor) getWebDriver();
value = "var select = document.getElementsByName('employee_id')[0]; select.options[0].value='106'; ";
javascript.executeScript(value);
-
- viewProfile = getDriver().findElements(By.name("action")).get(0);
+ viewProfile = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.name("action"))).get(0);
viewProfile.click();
- wait = new FluentWait(getDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
-
wait.until(new Predicate() {
public boolean apply(WebDriver webDriver) {
- return webDriver.getPageSource().contains("You have completed Stage 3");
+ return webDriver.getPageSource().contains("Stage 4");
}
});
-
}
@Test
@@ -439,14 +404,9 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().get(baseWebGoatUrl + "/service/restartlesson.mvc");
getWebDriver().get(baseWebGoatUrl + "/start.mvc#attack/1075773632/200");
- FluentWait wait = new WebDriverWait(getWebDriver(), 15); // wait for a maximum of 15 seconds
+ FluentWait wait = createDefaultWait(getWebDriver());
wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-title"), "Fail Open Authentication Scheme"));
- wait = new FluentWait(getWebDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class)
- .ignoring(StaleElementReferenceException.class);
WebElement user = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("Username")));
user.click();
user.sendKeys("Larry");
@@ -458,11 +418,6 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
WebElement submit = getWebDriver().findElement(By.name("SUBMIT"));
submit.click();
- wait = new FluentWait(getWebDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
-
wait.until(new Predicate() {
public boolean apply(WebDriver webDriver) {
return webDriver.getPageSource().contains("Congratulations");
@@ -478,17 +433,13 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().get(baseWebGoatUrl + "/service/restartlesson.mvc");
getWebDriver().get(baseWebGoatUrl + "/start.mvc#attack/1537271095/200");
- FluentWait wait = new FluentWait(getWebDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
+ FluentWait wait = createDefaultWait(getWebDriver());
wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-title"), "LAB: SQL Injection"));
assertFalse(getWebDriver().getPageSource().contains("Lesson Plan Title: How to Perform a SQL Injection"));
WebElement user = getWebDriver().findElement(By.id("show-plan-button"));
user.click();
- wait = new WebDriverWait(getWebDriver(), 15); // wait for a maximum of 15 seconds
wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-plan-content"), "Lesson Plan Title: How to Perform a SQL Injection"));
}
@@ -500,7 +451,7 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().get(baseWebGoatUrl + "/service/restartlesson.mvc");
getWebDriver().get(baseWebGoatUrl + "/start.mvc#attack/1129417221/200");
- FluentWait wait = new WebDriverWait(getWebDriver(), 15); // wait for a maximum of 15 seconds
+ FluentWait wait = createDefaultWait(getWebDriver());
wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-title"), "Insecure Client Storage"));
getWebDriver().manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
@@ -512,10 +463,6 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
WebElement submit = getWebDriver().findElement(By.name("SUBMIT"));
submit.click();
- wait = new FluentWait(getWebDriver())
- .withTimeout(20, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
wait.until(new Predicate() {
@Override
public boolean apply(WebDriver input) {
@@ -524,11 +471,6 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
});
//Stage 2
- wait = new FluentWait(getWebDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class)
- .ignoring(StaleElementReferenceException.class);
WebElement qty = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("QTY1")));
qty.click();
qty.sendKeys("8");
@@ -544,7 +486,6 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
-
submit = getWebDriver().findElement(By.name("SUBMIT"));
submit.click();
wait = new FluentWait(getWebDriver())
@@ -566,13 +507,14 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().get(baseWebGoatUrl + "/service/restartlesson.mvc");
getWebDriver().get(baseWebGoatUrl + "/start.mvc#attack/1574219258/1700");
- FluentWait wait = new WebDriverWait(getWebDriver(), 15); // wait for a maximum of 15 seconds
+ FluentWait wait = createDefaultWait(getWebDriver());
wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-title"), "Bypass Client Side JavaScript Validation"));
getWebDriver().manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
for (int i = 1; i <= 7; i++) {
- WebElement field = getWebDriver().findElement(By.name("field" + i));
+
+ WebElement field = wait.until(ExpectedConditions.presenceOfElementLocated(By.name("field" + i)));
field.click();
field.sendKeys("@#@{@#{");
}
@@ -586,11 +528,6 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
-
- wait = new FluentWait(getWebDriver())
- .withTimeout(10, SECONDS)
- .pollingEvery(2, SECONDS)
- .ignoring(NoSuchElementException.class);
wait.until(new Predicate() {
public boolean apply(WebDriver webDriver) {
return webDriver.getPageSource().contains("Congratulations");
@@ -606,16 +543,20 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider {
getWebDriver().get(baseWebGoatUrl + "/service/restartlesson.mvc");
getWebDriver().get(baseWebGoatUrl + "/start.mvc#attack/1537271095/200");
- FluentWait wait = new WebDriverWait(getWebDriver(), 15); // wait for a maximum of 15 seconds
+ FluentWait wait = createDefaultWait(getWebDriver());
wait.until(ExpectedConditions.textToBePresentInElementLocated(By.id("lesson-title"), "LAB: SQL Injection"));
+ this.getWebDriver().manage().timeouts().implicitlyWait(4, SECONDS);
- WebElement user = getWebDriver().findElement(By.id("show-solution-button"));
+ WebElement user = wait.until(ExpectedConditions.presenceOfElementLocated(By.id("show-solution-button")));
user.click();
- assertTrue(getWebDriver().getPageSource().contains("Could not find the solution file"));
+ wait.until(new Predicate() {
+ public boolean apply(WebDriver webDriver) {
+ return webDriver.getPageSource().contains("Could not find the solution file");
+ }
+ });
}
-
@Test
public void testLogoutMvc() {
diff --git a/webgoat-images/vagrant-developers/Vagrantfile b/webgoat-images/vagrant-developers/Vagrantfile
new file mode 100644
index 000000000..8b17363b2
--- /dev/null
+++ b/webgoat-images/vagrant-developers/Vagrantfile
@@ -0,0 +1,31 @@
+Vagrant.configure(2) do |config|
+ config.vm.box = "boxcutter/ubuntu1604-desktop"
+
+
+ config.vm.provider "virtualbox" do |vb|
+ vb.gui = true
+ vb.memory = "4096"
+ vb.cpus = 2
+ vb.name = "WebGoat-Developers"
+ vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
+ end
+
+ config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"
+
+ config.vm.provision 'shell' do |s|
+ s.path = '../vagrant_provision.sh'
+ s.privileged = true
+ end
+
+ config.vm.provision :shell, inline: <<-SHELL
+ echo -e "Cloning the WebGoat container repository"
+ git clone https://github.com/WebGoat/WebGoat.git
+ echo -e "Cloning the WebGoat Lessons repository"
+ git clone https://github.com/WebGoat/WebGoat-Lessons.git
+ SHELL
+
+ config.vm.provision 'shell' do |s|
+ s.inline = "echo Finished provisioning, login with user vagrant pass vagrant"
+ end
+
+end
diff --git a/webgoat-images/vagrant-users/Vagrantfile b/webgoat-images/vagrant-users/Vagrantfile
new file mode 100644
index 000000000..f24bee340
--- /dev/null
+++ b/webgoat-images/vagrant-users/Vagrantfile
@@ -0,0 +1,41 @@
+#For now use the same as for developers but start WebGoat
+#In the future we can add Docker as well and then Vagrant can start the
+#Docker container
+
+Vagrant.configure(2) do |config|
+ config.vm.box = "boxcutter/ubuntu1604-desktop"
+ config.vm.network :forwarded_port, guest: 8080, host: 9999
+ config.vm.provider "virtualbox" do |vb|
+ vb.gui = false
+ vb.memory = "4096"
+ vb.cpus = 2
+ vb.name = "WebGoat-Users"
+ vb.customize ["modifyvm", :id, "--nictype1", "virtio"]
+ end
+
+ config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"
+
+ config.vm.provision 'shell' do |s|
+ s.path = '../vagrant_provision.sh'
+ s.privileged = true
+ end
+
+ config.vm.provision :shell, inline: <<-SHELL
+ echo -e "Cloning the WebGoat container repository"
+ git clone https://github.com/WebGoat/WebGoat.git
+ echo -e "Cloning the WebGoat Lessons repository"
+ git clone https://github.com/WebGoat/WebGoat-Lessons.git
+ echo -e "Compiling and installing the WebGoat Container lesson server....."
+ mvn -q -DskipTests -file WebGoat/pom.xml clean compile install
+ echo -e "Compiling and installing the WebGoat Lessons $COL_RESET"
+ mvn -q -DskipTests -file WebGoat-Lessons/pom.xml package
+ echo -e "Copying the compiled lessons jars into the container so we can start the lesson server with some base lessons"
+ cp -fa ./WebGoat-Lessons/target/plugins/*.jar ./WebGoat/webgoat-container/src/main/webapp/plugin_lessons/
+ nohup mvn -q -DskipTests -file WebGoat/pom.xml -pl webgoat-container tomcat7:run-war 0<&- &>/dev/null &
+ SHELL
+
+ config.vm.provision 'shell' do |s|
+ s.inline = "echo Finished provisioning, open a browser and browse to http://localhost:9999/WebGoat/"
+ end
+
+end
diff --git a/webgoat-images/vagrant_provision.sh b/webgoat-images/vagrant_provision.sh
new file mode 100644
index 000000000..f85b36122
--- /dev/null
+++ b/webgoat-images/vagrant_provision.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+set -e
+
+echo "Setting locale..."
+sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
+
+sudo kill -9 $(lsof -t /var/lib/dpkg/lock) || true
+sudo apt-get update
+sudo apt-get install -y git
+
+echo "Installing required packages..."
+sudo apt-get install -y -q build-essential autotools-dev automake pkg-config expect
+
+
+## Chrome
+wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
+sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
+sudo apt-get update
+sudo apt-get install -y google-chrome-stable
+
+## Java 8
+echo "Provisioning Java 8..."
+mkdir -p /home/vagrant/java
+cd /home/vagrant/java
+test -f /tmp/jdk-8-linux-x64.tar.gz || curl -q -L --cookie "oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u101-b13/jdk-8u101-linux-x64.tar.gz -o /tmp/jdk-8-linux-x64.tar.gz
+
+sudo mkdir -p /usr/lib/jvm
+sudo tar zxf /tmp/jdk-8-linux-x64.tar.gz -C /usr/lib/jvm
+
+sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.8.0_101/bin/java" 1
+sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.8.0_101/bin/javac" 1
+sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.8.0_101/bin/javaws" 1
+
+sudo chmod a+x /usr/bin/java
+sudo chmod a+x /usr/bin/javac
+sudo chmod a+x /usr/bin/javaws
+sudo chown -R root:root /usr/lib/jvm/jdk1.8.0_101
+
+echo "export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_101" >> /home/vagrant/.bashrc
+
+
+## Maven
+echo "Installing Maven.."
+sudo apt-get install -y maven
+
+## ZAP
+echo "Provisioning ZAP..."
+cd /home/vagrant
+mkdir tools
+cd tools
+wget https://github.com/zaproxy/zaproxy/releases/download/2.5.0/ZAP_2.5.0_Linux.tar.gz
+tar xvfx ZAP_2.5.0_Linux.tar.gz
+rm -rf ZAP_2.5.0_Linux.tar.gz