Compare commits
154 Commits
gh-1165
...
nbaars/187
Author | SHA1 | Date | |
---|---|---|---|
bf02077427 | |||
e1e00bca73 | |||
d59153d6d7 | |||
87fae00f03 | |||
3f6a74ad86 | |||
1d37ee0877 | |||
4f6ab25ebd | |||
af687e71fe | |||
83ed4c3d5c | |||
62cdfd0824 | |||
e7457f4821 | |||
4efaf87c7e | |||
cf5101a633 | |||
3f049ba53a | |||
7e294fbdb5 | |||
2177eb663a | |||
50692300eb | |||
e2c2d425cb | |||
6bbd3cb66b | |||
d08a56d351 | |||
ec97568ec2 | |||
9b68368b23 | |||
ab068901f1 | |||
cb7c508046 | |||
f4c86be6c7 | |||
cf2c115093 | |||
bb6e84ddcf | |||
5fc2666b43 | |||
6e946f21a2 | |||
d38ba2a626 | |||
4c7e6ae4f4 | |||
58b762eade | |||
2b0c22ac68 | |||
85103bbcad | |||
b98e1a98e1 | |||
73de259809 | |||
4a804fabb6 | |||
7f652dadec | |||
f66dff1aeb | |||
777cec5a57 | |||
98fd280459 | |||
8e0addff0b | |||
a30fbc223a | |||
a0b6decf34 | |||
1531987da5 | |||
bec6580c84 | |||
900702481b | |||
f35b23970e | |||
074fd8f5ff | |||
8c890b090c | |||
630c1e1afd | |||
061c75a05f | |||
5e5a1363b0 | |||
47df923c8c | |||
5dbc642264 | |||
96bc6fa608 | |||
1d5a2bb6a2 | |||
8b37bd58d7 | |||
6545e2a066 | |||
9573b30667 | |||
30e40f2e59 | |||
8f11fb6729 | |||
10e36c203f | |||
edcce09b5f | |||
3134f18066 | |||
e219887f14 | |||
508703ffce | |||
e308d7cde7 | |||
4ab820e1d1 | |||
1a6a7e0be1 | |||
2e9140ab64 | |||
b79c83a52e | |||
297c6f49b5 | |||
d2049a8fcc | |||
24db39eae2 | |||
98443184e9 | |||
62931a1836 | |||
c18430752a | |||
57d5b313b9 | |||
dd0f135088 | |||
ad0286d5ba | |||
b67eb44142 | |||
7e75e9b8fc | |||
40c679ec5a | |||
4ebb869f5d | |||
6bb7a182dc | |||
cb2c99d38d | |||
84029345b4 | |||
a0ca199cdc | |||
2058298e2d | |||
17acef57b4 | |||
d913967ec5 | |||
87edc7d1db | |||
ac7a9c7863 | |||
2803ef45e4 | |||
5357a65e05 | |||
d343c60781 | |||
98acc1f55a | |||
f99888e61b | |||
29dda49190 | |||
369be6f688 | |||
d5f869c006 | |||
a9caaabb47 | |||
fb2ff01775 | |||
89ecf1d2ad | |||
1b66a742da | |||
a831da5886 | |||
fd5189c102 | |||
ae261f201a | |||
3d651526be | |||
c7c2a61f65 | |||
b7f657ad2c | |||
7fea42afe9 | |||
826887cc83 | |||
62db86246e | |||
f7a9995fe0 | |||
d6c4e8e454 | |||
26628a39e1 | |||
2d26a318d1 | |||
dc16e9a0fb | |||
88a321c268 | |||
8450c5a5be | |||
ba75e10efd | |||
d1e44bbc98 | |||
5a4974f3c2 | |||
4fc1d1fb22 | |||
084a105c69 | |||
7485cb8b9a | |||
c312ae989f | |||
5fde7fbf29 | |||
a32c56bfc7 | |||
6fd3eb57eb | |||
1743d017ff | |||
2b2638943b | |||
45c26d8aaf | |||
be30551850 | |||
49862f6b90 | |||
4009785bb8 | |||
d8341c86a1 | |||
055578893d | |||
b89ebd70ad | |||
7b81247dd1 | |||
3bc2e57c9c | |||
c3ec168d59 | |||
a67fbf5a5a | |||
3365c8d447 | |||
368c046779 | |||
8749137d1e | |||
786cabd251 | |||
dda8b10f55 | |||
d6ca083529 | |||
7c92d625dd | |||
4ba818533c | |||
a9b1fd66b8 |
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
@ -12,4 +12,3 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
|
54
.github/workflows/branchbuild.txt
vendored
Normal file
54
.github/workflows/branchbuild.txt
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
name: "Branch build"
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
- "!main"
|
||||
|
||||
jobs:
|
||||
branch-build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
java-version: [ 21 ]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK ${{ matrix.java-version }}
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java-version }}
|
||||
architecture: x64
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v3.3.1
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ${{ runner.os }}-m2-
|
||||
- name: Build with Maven
|
||||
run: mvn --no-transfer-progress verify
|
||||
- name: "Set up QEMU"
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-qemu-action@v2.2.0
|
||||
- name: "Set up Docker Buildx"
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: "Verify Docker WebGoat build"
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile
|
||||
push: false
|
||||
build-args: |
|
||||
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
||||
- name: "Verify Docker WebGoat desktop build"
|
||||
uses: docker/build-push-action@v5.1.0
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile_desktop
|
||||
push: false
|
||||
build-args: |
|
||||
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
83
.github/workflows/build.yml
vendored
83
.github/workflows/build.yml
vendored
@ -1,60 +1,51 @@
|
||||
name: "Pull requests build"
|
||||
name: "Main / Pull requests build"
|
||||
on:
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.txt'
|
||||
- 'LICENSE'
|
||||
- 'docs/**'
|
||||
branches: [ main ]
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
pr-build:
|
||||
if: >
|
||||
github.event_name == 'pull_request' && !github.event.pull_request.draft && (
|
||||
github.event.action == 'opened' ||
|
||||
github.event.action == 'reopened' ||
|
||||
github.event.action == 'synchronize'
|
||||
)
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
pre-commit:
|
||||
name: Pre-commit check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
- name: Checkout git repository
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
architecture: x64
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v3.3.1
|
||||
java-version: '21'
|
||||
- name: Pre-commit checks
|
||||
uses: pre-commit/action@v3.0.1
|
||||
- name: pre-commit-ci-lite
|
||||
uses: pre-commit-ci/lite-action@v1.1.0
|
||||
if: always()
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [ pre-commit ]
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [ windows-latest, ubuntu-latest, macos-13 ]
|
||||
max-parallel: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4.2.1
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ${{ runner.os }}-m2-
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
architecture: x64
|
||||
cache: 'maven'
|
||||
- name: Build with Maven
|
||||
run: mvn --no-transfer-progress verify
|
||||
- name: "Set up QEMU"
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-qemu-action@v2.2.0
|
||||
- name: "Set up Docker Buildx"
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: "Verify Docker WebGoat build"
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/build-push-action@v4.1.1
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile
|
||||
push: false
|
||||
build-args: |
|
||||
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
||||
- name: "Verify Docker WebGoat desktop build"
|
||||
uses: docker/build-push-action@v4.1.1
|
||||
if: runner.os == 'Linux'
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile_desktop
|
||||
push: false
|
||||
build-args: |
|
||||
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
||||
|
39
.github/workflows/release.yml
vendored
39
.github/workflows/release.yml
vendored
@ -8,24 +8,20 @@ jobs:
|
||||
if: github.repository == 'WebGoat/WebGoat'
|
||||
name: Release WebGoat
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
environment:
|
||||
name: release
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
java-version: 21
|
||||
architecture: x64
|
||||
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v3.3.1
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ${{ runner.os }}-m2
|
||||
cache: 'maven'
|
||||
|
||||
- name: "Set labels for ${{ github.ref }}"
|
||||
run: |
|
||||
@ -72,26 +68,26 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: "Set up QEMU"
|
||||
uses: docker/setup-qemu-action@v2.2.0
|
||||
uses: docker/setup-qemu-action@v3.1.0
|
||||
with:
|
||||
platforms: all
|
||||
|
||||
- name: "Set up Docker Buildx"
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: "Login to dockerhub"
|
||||
uses: docker/login-action@v2.2.0
|
||||
uses: docker/login-action@v3.3.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: "Build and push WebGoat"
|
||||
uses: docker/build-push-action@v4.1.1
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64, linux/arm64, linux/arm/v7
|
||||
platforms: linux/amd64, linux/arm64
|
||||
tags: |
|
||||
webgoat/webgoat:${{ env.WEBGOAT_TAG_VERSION }}
|
||||
webgoat/webgoat:latest
|
||||
@ -99,7 +95,7 @@ jobs:
|
||||
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
||||
|
||||
- name: "Build and push WebGoat desktop"
|
||||
uses: docker/build-push-action@v4.1.1
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
with:
|
||||
context: ./
|
||||
file: ./Dockerfile_desktop
|
||||
@ -116,15 +112,15 @@ jobs:
|
||||
needs: [ release ]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
java-version: 21
|
||||
architecture: x64
|
||||
|
||||
- name: Set version to next snapshot
|
||||
@ -145,4 +141,3 @@ jobs:
|
||||
github_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
title: ${{ github.event.commits[0].message }}
|
||||
target_branch: main
|
||||
|
||||
|
22
.github/workflows/test.yml
vendored
22
.github/workflows/test.yml
vendored
@ -21,27 +21,21 @@ jobs:
|
||||
name: "Robot framework test"
|
||||
steps:
|
||||
# Uses an default action to checkout the code
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4.1.6
|
||||
# Uses an action to add Python to the VM
|
||||
- name: Setup Pyton
|
||||
uses: actions/setup-python@v4
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.7'
|
||||
architecture: x64
|
||||
# Uses an action to add JDK 17 to the VM (and mvn?)
|
||||
- name: set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
# Uses an action to add JDK 21 to the VM (and mvn?)
|
||||
- name: set up JDK 21
|
||||
uses: actions/setup-java@v4.2.1
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
java-version: 21
|
||||
architecture: x64
|
||||
#Uses an action to set up a cache using a certain key based on the hash of the dependencies
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v3.3.1
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ubuntu-latest-m2-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: ubuntu-latest-m2-
|
||||
cache: 'maven'
|
||||
- uses: BSFishy/pip-action@v1
|
||||
with:
|
||||
packages: |
|
||||
|
2
.github/workflows/welcome.yml
vendored
2
.github/workflows/welcome.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
if: github.repository == 'WebGoat/WebGoat'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/first-interaction@v1.1.1
|
||||
- uses: actions/first-interaction@v1.3.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-message: 'Thanks for submitting your first issue, we will have a look as quickly as possible.'
|
||||
|
28
.pre-commit-config.yaml
Normal file
28
.pre-commit-config.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
ci:
|
||||
autofix_commit_msg: |
|
||||
[pre-commit.ci] auto fixes from pre-commit.com hooks
|
||||
autofix_prs: false # managed in the action step
|
||||
autoupdate_branch: ""
|
||||
autoupdate_commit_msg: "[pre-commit.ci] pre-commit autoupdate"
|
||||
autoupdate_schedule: weekly
|
||||
skip: []
|
||||
submodules: false
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: end-of-file-fixer
|
||||
exclude: ^(README.md|CREATE_RELEASE.md)
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
|
||||
rev: v9.5.0
|
||||
hooks:
|
||||
- id: commitlint
|
||||
stages: [commit-msg]
|
||||
- repo: https://github.com/ejba/pre-commit-maven
|
||||
rev: v0.3.4
|
||||
hooks:
|
||||
- id: maven
|
||||
args: [ 'clean compile' ]
|
||||
- id: maven-spotless-apply
|
@ -8,7 +8,7 @@ and 2023.01 in the `pom.xml`.
|
||||
### Release notes:
|
||||
|
||||
Update the release notes with the correct version. Use `git shortlog -s -n --since "JAN 06 2023"` for the list of
|
||||
committers.
|
||||
committers. In order to fetch the list of issues included use: `git log --graph --pretty='%C(auto)%d%Creset%s' v2023.4..origin/main`
|
||||
|
||||
```
|
||||
mvn versions:set
|
||||
|
19
Dockerfile
19
Dockerfile
@ -1,6 +1,8 @@
|
||||
FROM docker.io/eclipse-temurin:19-jre-focal
|
||||
LABEL NAME = "WebGoat: A deliberately insecure Web Application"
|
||||
MAINTAINER "WebGoat team"
|
||||
# We need JDK as some of the lessons needs to be able to compile Java code
|
||||
FROM docker.io/eclipse-temurin:21-jdk-jammy
|
||||
|
||||
LABEL name="WebGoat: A deliberately insecure Web Application"
|
||||
LABEL maintainer="WebGoat team"
|
||||
|
||||
RUN \
|
||||
useradd -ms /bin/bash webgoat && \
|
||||
@ -14,6 +16,8 @@ COPY --chown=webgoat target/webgoat-*.jar /home/webgoat/webgoat.jar
|
||||
EXPOSE 8080
|
||||
EXPOSE 9090
|
||||
|
||||
ENV TZ=Europe/Amsterdam
|
||||
|
||||
WORKDIR /home/webgoat
|
||||
ENTRYPOINT [ "java", \
|
||||
"-Duser.home=/home/webgoat", \
|
||||
@ -30,8 +34,7 @@ ENTRYPOINT [ "java", \
|
||||
"--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", \
|
||||
"--add-opens", "java.base/java.io=ALL-UNNAMED", \
|
||||
"-Drunning.in.docker=true", \
|
||||
"-Dwebgoat.host=0.0.0.0", \
|
||||
"-Dwebwolf.host=0.0.0.0", \
|
||||
"-Dwebgoat.port=8080", \
|
||||
"-Dwebwolf.port=9090", \
|
||||
"-jar", "webgoat.jar" ]
|
||||
"-jar", "webgoat.jar", "--server.address", "0.0.0.0" ]
|
||||
|
||||
HEALTHCHECK --interval=5s --timeout=3s \
|
||||
CMD curl --fail http://localhost:8080/WebGoat/actuator/health || exit 1
|
||||
|
@ -1,6 +1,6 @@
|
||||
FROM lscr.io/linuxserver/webtop:ubuntu-xfce
|
||||
LABEL NAME = "WebGoat: A deliberately insecure Web Application"
|
||||
MAINTAINER "WebGoat team"
|
||||
LABEL maintainer = "WebGoat team"
|
||||
|
||||
WORKDIR /config
|
||||
|
||||
@ -9,26 +9,38 @@ COPY config/desktop/start_webgoat.sh /config/start_webgoat.sh
|
||||
COPY config/desktop/start_zap.sh /config/start_zap.sh
|
||||
COPY config/desktop/WebGoat.txt /config/Desktop/
|
||||
|
||||
RUN \
|
||||
apt-get update && \
|
||||
apt-get --yes install vim nano gzip
|
||||
|
||||
RUN \
|
||||
case $(uname -m) in \
|
||||
x86_64) ARCH=x64;; \
|
||||
aarch64) ARCH=aarch64;; \
|
||||
*) ARCH=unknown;; \
|
||||
esac && \
|
||||
curl -LO https://github.com/zaproxy/zaproxy/releases/download/v2.12.0/ZAP_2.12.0_Linux.tar.gz && \
|
||||
tar zfxv ZAP_2.12.0_Linux.tar.gz && \
|
||||
rm -rf ZAP_2.12.0_Linux.tar.gz && \
|
||||
curl -LO https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6%2B10/OpenJDK17U-jre_${ARCH}_linux_hotspot_17.0.6_10.tar.gz && \
|
||||
tar zfxv OpenJDK17U-jre_${ARCH}_linux_hotspot_17.0.6_10.tar.gz && \
|
||||
rm -rf OpenJDK17U-jre_${ARCH}_linux_hotspot_17.0.6_10.tar.gz && \
|
||||
echo ${ARCH}
|
||||
|
||||
RUN \
|
||||
curl -LO https://github.com/zaproxy/zaproxy/releases/download/v2.15.0/ZAP_2.15.0_Linux.tar.gz && \
|
||||
tar zfxv ZAP_2.15.0_Linux.tar.gz && \
|
||||
rm -rf ZAP_2.15.0_Linux.tar.gz
|
||||
|
||||
RUN \
|
||||
case $(uname -m) in \
|
||||
x86_64) ARCH=x64;; \
|
||||
aarch64) ARCH=aarch64;; \
|
||||
*) ARCH=unknown;; \
|
||||
esac && \
|
||||
echo "oeps == ${ARCH}==" && \
|
||||
curl -L https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.3%2B9/OpenJDK21U-jre_"${ARCH}"_linux_hotspot_21.0.3_9.tar.gz -o java.tar.gz && \
|
||||
tar zfxv java.tar.gz && \
|
||||
rm -rf java.tar.gz && \
|
||||
chmod +x /config/start_webgoat.sh && \
|
||||
chmod +x /config/start_zap.sh && \
|
||||
apt-get update && \
|
||||
apt-get --yes install vim nano && \
|
||||
echo "JAVA_HOME=/config/jdk-17.0.6+10-jre/" >> .bash_aliases && \
|
||||
echo "JAVA_HOME=/config/jdk-21.0.3+9-jre/" >> .bash_aliases && \
|
||||
echo "PATH=$PATH:$JAVA_HOME/bin" >> .bash_aliases
|
||||
|
||||
|
||||
ENV JAVA_HOME=/home/webgoat/jdk-17.0.6+10-jre
|
||||
ENV JAVA_HOME=/config/jdk-21.0.3+9-jre
|
||||
|
||||
WORKDIR /config/Desktop
|
||||
|
1
FAQ.md
1
FAQ.md
@ -5,4 +5,3 @@
|
||||
### Integration tests fail
|
||||
|
||||
Try to run the command in the console `java -jar ...` and remove `-Dlogging.pattern.console=` from the command line.
|
||||
|
||||
|
40
README.md
40
README.md
@ -1,7 +1,7 @@
|
||||
# WebGoat 8: A deliberately insecure Web Application
|
||||
# WebGoat: A deliberately insecure Web Application
|
||||
|
||||
[](https://github.com/WebGoat/WebGoat/actions/workflows/build.yml)
|
||||
[](https://jdk.java.net/)
|
||||
[](https://jdk.java.net/)
|
||||
[](https://owasp.org/projects/)
|
||||
[](https://github.com/WebGoat/WebGoat/releases/latest)
|
||||
[](https://gitter.im/OWASPWebGoat/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
@ -44,19 +44,27 @@ Every release is also published on [DockerHub](https://hub.docker.com/r/webgoat/
|
||||
docker run -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 webgoat/webgoat
|
||||
```
|
||||
|
||||
If you want to reuse the container, give it a name:
|
||||
For some lessons you need the container run in the same timezone. For this you can set the TZ environment variable.
|
||||
E.g.
|
||||
|
||||
```shell
|
||||
docker run --name webgoat -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 webgoat/webgoat
|
||||
docker run -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 -e TZ=America/Boise webgoat/webgoat
|
||||
```
|
||||
|
||||
As long as you don't remove the container you can use:
|
||||
If you want to use OWASP ZAP or another proxy, you can no longer use 127.0.0.1 or localhost. but
|
||||
you can use custom host entries. For example:
|
||||
|
||||
```shell
|
||||
docker start webgoat
|
||||
127.0.0.1 www.webgoat.local www.webwolf.local
|
||||
```
|
||||
|
||||
This way, you can start where you left off. If you remove the container, you need to use `docker run` again.
|
||||
Then you can run the container with:
|
||||
|
||||
```shell
|
||||
docker run -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 -e WEBGOAT_HOST=www.webgoat.local -e WEBWOLF_HOST=www.webwolf.local -e TZ=America/Boise webgoat/webgoat
|
||||
```
|
||||
|
||||
Then visit http://www.webgoat.local:8080/WebGoat/ and http://www.webwolf.local:9090/WebWolf/
|
||||
|
||||
## 2. Run using Docker with complete Linux Desktop
|
||||
|
||||
@ -71,16 +79,27 @@ docker run -p 127.0.0.1:3000:3000 webgoat/webgoat-desktop
|
||||
Download the latest WebGoat release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
|
||||
|
||||
```shell
|
||||
java -Dfile.encoding=UTF-8 -Dwebgoat.port=8080 -Dwebwolf.port=9090 -jar webgoat-2023.3.jar
|
||||
export TZ=Europe/Amsterdam # or your timezone
|
||||
java -Dfile.encoding=UTF-8 -jar webgoat-2023.8.jar
|
||||
```
|
||||
|
||||
Click the link in the log to start WebGoat.
|
||||
|
||||
### 3.1 Running on a different port
|
||||
|
||||
If for some reason you want to run WebGoat on a different port, you can do so by adding the following parameter:
|
||||
|
||||
```shell
|
||||
java -jar webgoat-2023.8.jar --webgoat.port=8001 --webwolf.port=8002
|
||||
```
|
||||
|
||||
For a full overview of all the parameters you can use, please check the [WebGoat properties file](webgoat-container/src/main/resources/application-{webgoat, webwolf}.properties).
|
||||
|
||||
## 4. Run from the sources
|
||||
|
||||
### Prerequisites:
|
||||
|
||||
* Java 17
|
||||
* Java 17 or 21
|
||||
* Your favorite IDE
|
||||
* Git, or Git support in your IDE
|
||||
|
||||
@ -132,9 +151,10 @@ For specialist only. There is a way to set up WebGoat with a personalized menu.
|
||||
For instance running as a jar on a Linux/macOS it will look like this:
|
||||
|
||||
```Shell
|
||||
export TZ=Europe/Amsterdam # or your timezone
|
||||
export EXCLUDE_CATEGORIES="CLIENT_SIDE,GENERAL,CHALLENGE"
|
||||
export EXCLUDE_LESSONS="SqlInjectionAdvanced,SqlInjectionMitigations"
|
||||
java -jar target/webgoat-2023.3-SNAPSHOT.jar
|
||||
java -jar target/webgoat-2023.8-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
Or in a docker run it would (once this version is pushed into docker hub) look like this:
|
||||
|
@ -16,19 +16,19 @@ The following steps are required when you want to add a new language
|
||||
|
||||
1. Update [main_new.html](src/main/resources/webgoat/static/main_new.html)
|
||||
1. Add the parts for showing the flag and providing the correct value for the flag= parameter
|
||||
2.
|
||||
3. Add a flag image to src/main/resources/webgoat/static/css/img
|
||||
2.
|
||||
2. Add a flag image to src/main/resources/webgoat/static/css/img
|
||||
1. See the main_new.html for a link to download flag resources
|
||||
4. Add a welcome page to the introduction lesson
|
||||
3. Add a welcome page to the introduction lesson
|
||||
1. Copy Introduction_.adoc to Introduction_es.adoc (if in this case you want to add Spanish)
|
||||
2. Add a highlighted section that explains that most parts of WebGoat will still be in English and invite people to translate parts where it would be valuable
|
||||
5. Translate the main labels
|
||||
4. Translate the main labels
|
||||
1. Copy messages.properties to messages_es.properties (if in this case you want to add Spanish)
|
||||
2. Translate the label values
|
||||
6. Optionally translate lessons by
|
||||
5. Optionally translate lessons by
|
||||
1. Adding lang specifc adoc files in documentation folder of the lesson
|
||||
2. Adding WebGoatLabels.properties of a specific language if you want to
|
||||
7. Run mvn clean to see if the LabelAndHintIntegration test passes
|
||||
8. Run WebGoat and verify that your own language and the other languages work as expected
|
||||
6. Run mvn clean to see if the LabelAndHintIntegration test passes
|
||||
7. Run WebGoat and verify that your own language and the other languages work as expected
|
||||
|
||||
If you only want to translate more for a certain language, you only need to do step 4-8
|
||||
|
@ -1,5 +1,60 @@
|
||||
# WebGoat release notes
|
||||
|
||||
## Version 2023.8
|
||||
|
||||
### 🚀 New functionality
|
||||
|
||||
- Consistent environment values and url references (#1677)
|
||||
- Show directly requested file in requests overview
|
||||
- Show creating time in file upload overview
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
- Fix startup message (#1687)
|
||||
- Fix/state of software supply chain links (#1683)
|
||||
- Fix WebWolf UI (#1686)
|
||||
|
||||
### 🔄 Technical tasks
|
||||
|
||||
- bump actions/setup-java from 3 to 4 (#1690)
|
||||
- bump commons-io:commons-io from 2.14.0 to 2.15.1 (#1689)
|
||||
- bump com.diffplug.spotless:spotless-maven-plugin (#1688)
|
||||
|
||||
## Version 2023.5
|
||||
|
||||
### New functionality
|
||||
|
||||
- Implement JWT jku example (#1552)
|
||||
- Java 21 initial support (#1622)
|
||||
- improve MFAC lesson hint texts for a better user experience (#1424)
|
||||
- upgrade to Spring Boot version 3 (#1477)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- typo in WebGoad.txt (#1667)
|
||||
- search box moved and jwt encode/decode with little delay (#1664)
|
||||
- skip validation for JWT (#1663)
|
||||
- fixed issue in JWT test tool and added robot test (#1658)
|
||||
- Password reset link test condition more strict and move all WebWolf links to /WebWolf (#1645)
|
||||
- fix servers id (#1619)
|
||||
- potential NPE in the stored XSS assignment
|
||||
- crypto basics broken links
|
||||
- fixes the default change in trailing slash matching and address the affected assignments
|
||||
- hint that was breaking the template, causing hints from different assignments to mix (#1424)
|
||||
- HijackSession lesson template deprecated Tymeleaf attribute
|
||||
- Fix NPE in IDOR lesson
|
||||
- Add new assignment IT tests
|
||||
- XSS mitigation
|
||||
- Stored Cross-Site Scripting Lesson
|
||||
- Add Assignment7 Tests
|
||||
- Fix IDOR lesson
|
||||
- remove steps from release script (#1509)
|
||||
- robotframework fails due to updated dependencies (#1508)
|
||||
- fix Java image inside Docker file The image now downloads the correct Java version based on the architecture.
|
||||
- Fix typo of HijackSession_content0.adoc
|
||||
- Restrict SSRF Regexes
|
||||
- update challenge code - Flags are now wired through a Spring config - Introduced Flag class - Removed Flags from the FlagController
|
||||
|
||||
## Version 2023.4
|
||||
|
||||
### New functionality
|
||||
@ -160,4 +215,3 @@ Special thanks to the following contributors providing us with a pull request:
|
||||
And everyone who provided feedback through Github.
|
||||
|
||||
Team WebGoat
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
With this image you have WebGoat and ZAP and a browser available to you in a browser running on Ubuntu.
|
||||
You can start WebGoat and ZAP by opening a terminal and type:
|
||||
|
||||
./start-webgoat.sh
|
||||
./start_webgoat.sh
|
||||
./start_zap.sh
|
||||
|
||||
Happy hacking,
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
/config/jdk-17.0.6+10-jre/bin/java \
|
||||
/config/jdk-21.0.3+9-jre/bin/java \
|
||||
-Duser.home=/config \
|
||||
-Dfile.encoding=UTF-8 \
|
||||
-DTZ=Europe/Amsterdam \
|
||||
|
@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
/config/jdk-17.0.6+10-jre/bin/java -jar /config/ZAP_2.12.0/zap-2.12.0.jar
|
||||
/config/jdk-21.0.3+9-jre/bin/java -jar /config/ZAP_2.15.0/zap-2.15.0.jar
|
||||
|
@ -1,4 +1,3 @@
|
||||
# WebGoat landing page
|
||||
|
||||
Old GitHub page which now redirects to OWASP website.
|
||||
|
||||
|
238
pom.xml
238
pom.xml
@ -5,12 +5,12 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<version>3.3.5</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.owasp.webgoat</groupId>
|
||||
<artifactId>webgoat</artifactId>
|
||||
<version>2023.5-SNAPSHOT</version>
|
||||
<version>2024.2-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>WebGoat</name>
|
||||
@ -29,13 +29,6 @@
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>mayhew64</id>
|
||||
<name>Bruce Mayhew</name>
|
||||
<email>webgoat@owasp.org</email>
|
||||
<organization>OWASP</organization>
|
||||
<organizationUrl>https://github.com/WebGoat/WebGoat</organizationUrl>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>nbaars</id>
|
||||
<name>Nanne Baars</name>
|
||||
@ -43,11 +36,6 @@
|
||||
<organizationUrl>https://github.com/nbaars</organizationUrl>
|
||||
<timezone>Europe/Amsterdam</timezone>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>misfir3</id>
|
||||
<name>Jason White</name>
|
||||
<email>jason.white@owasp.org</email>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>zubcevic</id>
|
||||
<name>René Zubcevic</name>
|
||||
@ -58,43 +46,8 @@
|
||||
<name>Àngel Ollé Blázquez</name>
|
||||
<email>angel@olleb.com</email>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>jwayman</id>
|
||||
<name>Jeff Wayman</name>
|
||||
<email></email>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>dcowden</id>
|
||||
<name>Dave Cowden</name>
|
||||
<email></email>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>lawson89</id>
|
||||
<name>Richard Lawson</name>
|
||||
<email></email>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>dougmorato</id>
|
||||
<name>Doug Morato</name>
|
||||
<email>doug.morato@owasp.org</email>
|
||||
<organization>OWASP</organization>
|
||||
<organizationUrl>https://github.com/dougmorato</organizationUrl>
|
||||
<timezone>America/New_York</timezone>
|
||||
<properties>
|
||||
<picUrl>https://avatars2.githubusercontent.com/u/9654?v=3&s=150</picUrl>
|
||||
</properties>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<mailingLists>
|
||||
<mailingList>
|
||||
<name>OWASP WebGoat Mailing List</name>
|
||||
<subscribe>https://lists.owasp.org/mailman/listinfo/owasp-webgoat</subscribe>
|
||||
<unsubscribe>Owasp-webgoat-request@lists.owasp.org</unsubscribe>
|
||||
<post>owasp-webgoat@lists.owasp.org</post>
|
||||
<archive>http://lists.owasp.org/pipermail/owasp-webgoat/</archive>
|
||||
</mailingList>
|
||||
</mailingLists>
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:WebGoat/WebGoat.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:WebGoat/WebGoat.git</developerConnection>
|
||||
@ -109,60 +62,56 @@
|
||||
|
||||
<properties>
|
||||
<!-- Shared properties with plugins and version numbers across submodules-->
|
||||
<asciidoctorj.version>2.5.10</asciidoctorj.version>
|
||||
<!-- Upgrading needs UI work in WebWolf -->
|
||||
<bootstrap.version>3.3.7</bootstrap.version>
|
||||
<asciidoctorj.version>3.0.0</asciidoctorj.version>
|
||||
<bootstrap.version>5.3.3</bootstrap.version>
|
||||
<cglib.version>3.3.0</cglib.version>
|
||||
<!-- do not update necessary for lesson -->
|
||||
<checkstyle.version>3.3.0</checkstyle.version>
|
||||
<checkstyle.version>3.6.0</checkstyle.version>
|
||||
<commons-collections.version>3.2.1</commons-collections.version>
|
||||
<commons-io.version>2.11.0</commons-io.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<commons-text.version>1.10.0</commons-text.version>
|
||||
<guava.version>32.1.1-jre</guava.version>
|
||||
<jacoco.version>0.8.10</jacoco.version>
|
||||
<java.version>17</java.version>
|
||||
<commons-compress.version>1.27.1</commons-compress.version>
|
||||
<commons-io.version>2.17.0</commons-io.version>
|
||||
<commons-lang3.version>3.14.0</commons-lang3.version>
|
||||
<commons-text.version>1.12.0</commons-text.version>
|
||||
<guava.version>33.3.1-jre</guava.version>
|
||||
<jacoco.version>0.8.11</jacoco.version>
|
||||
<java.version>21</java.version>
|
||||
<jaxb.version>2.3.1</jaxb.version>
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<jose4j.version>0.9.3</jose4j.version>
|
||||
<jquery.version>3.6.4</jquery.version>
|
||||
<jsoup.version>1.16.1</jsoup.version>
|
||||
<jquery.version>3.7.1</jquery.version>
|
||||
<jsoup.version>1.18.1</jsoup.version>
|
||||
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||
<maven-failsafe-plugin.version>2.22.0</maven-failsafe-plugin.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>3.1.2</maven-surefire-plugin.version>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven-surefire-plugin.version>3.5.1</maven-surefire-plugin.version>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<pmd.version>3.15.0</pmd.version>
|
||||
<!-- Use UTF-8 Encoding -->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<thymeleaf.version>3.1.1.RELEASE</thymeleaf.version>
|
||||
<webdriver.version>5.3.2</webdriver.version>
|
||||
<webgoat.port>8080</webgoat.port>
|
||||
<webwolf.port>9090</webwolf.port>
|
||||
<wiremock.version>2.27.2</wiremock.version>
|
||||
<thymeleaf.version>3.1.2.RELEASE</thymeleaf.version>
|
||||
<waittimeForServerStart>60</waittimeForServerStart>
|
||||
<webdriver.version>5.9.2</webdriver.version>
|
||||
<webgoat.context>/</webgoat.context>
|
||||
<webgoat.sslenabled>false</webgoat.sslenabled>
|
||||
<webjars-locator-core.version>0.59</webjars-locator-core.version>
|
||||
<webwolf.context>/</webwolf.context>
|
||||
<wiremock.version>3.9.2</wiremock.version>
|
||||
<xml-resolver.version>1.2</xml-resolver.version>
|
||||
<xstream.version>1.4.5</xstream.version>
|
||||
<!-- do not update necessary for lesson -->
|
||||
<zxcvbn.version>1.8.0</zxcvbn.version>
|
||||
<zxcvbn.version>1.9.0</zxcvbn.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>9.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-exec</artifactId>
|
||||
<version>1.3</version>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
@ -200,6 +149,17 @@
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>jwks-rsa</artifactId>
|
||||
<version>0.22.1</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>4.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
@ -231,8 +191,13 @@
|
||||
<version>${jquery.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock</artifactId>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>webjars-locator-core</artifactId>
|
||||
<version>${webjars-locator-core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wiremock</groupId>
|
||||
<artifactId>wiremock-standalone</artifactId>
|
||||
<version>${wiremock.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -243,12 +208,12 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.23.0</version>
|
||||
<version>${commons-compress.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jruby</groupId>
|
||||
<artifactId>jruby</artifactId>
|
||||
<version>9.4.2.0</version>
|
||||
<version>9.4.8.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
@ -267,24 +232,26 @@
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>1.20.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>1.20.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>${jaxb.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<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>org.springframework.boot</groupId>
|
||||
@ -294,6 +261,10 @@
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-database-hsqldb</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctorj</artifactId>
|
||||
@ -310,6 +281,10 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
|
||||
@ -346,6 +321,15 @@
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>jwks-rsa</artifactId>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.auth0/java-jwt -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
@ -374,6 +358,10 @@
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>jquery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>webjars-locator-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
@ -383,6 +371,12 @@
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.terma</groupId>
|
||||
<artifactId>javaniotcpproxy</artifactId>
|
||||
<version>1.6</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -395,10 +389,8 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock</artifactId>
|
||||
<version>3.0.0-beta-2</version>
|
||||
<scope>test</scope>
|
||||
<groupId>org.wiremock</groupId>
|
||||
<artifactId>wiremock-standalone</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
@ -478,10 +470,19 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<environmentVariables>
|
||||
<WEBGOAT_SSLENABLED>${webgoat.sslenabled}</WEBGOAT_SSLENABLED>
|
||||
<WEBGOAT_HOST>127.0.0.1</WEBGOAT_HOST>
|
||||
<WEBGOAT_PORT>${webgoat.port}</WEBGOAT_PORT>
|
||||
<WEBGOAT_CONTEXT>${webgoat.context}</WEBGOAT_CONTEXT>
|
||||
<WEBWOLF_HOST>127.0.0.1</WEBWOLF_HOST>
|
||||
<WEBWOLF_PORT>${webwolf.port}</WEBWOLF_PORT>
|
||||
<WEBWOLF_CONTEXT>${webwolf.context}</WEBWOLF_CONTEXT>
|
||||
</environmentVariables>
|
||||
<systemPropertyVariables>
|
||||
<logback.configurationFile>${basedir}/src/test/resources/logback-test.xml</logback.configurationFile>
|
||||
</systemPropertyVariables>
|
||||
<argLine>-Xmx512m -Dwebgoatport=${webgoat.port} -Dwebwolfport=${webwolf.port}</argLine>
|
||||
<argLine>-Xmx512m</argLine>
|
||||
<includes>org/owasp/webgoat/*Test</includes>
|
||||
</configuration>
|
||||
<executions>
|
||||
@ -504,6 +505,8 @@
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<forkedProcessTimeoutInSeconds>600</forkedProcessTimeoutInSeconds>
|
||||
<!-- Necessary for vulnerable components lesson -->
|
||||
<argLine>--add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
|
||||
--add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED
|
||||
--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED
|
||||
@ -511,8 +514,6 @@
|
||||
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED</argLine>
|
||||
<excludes>
|
||||
<exclude>**/*IntegrationTest.java</exclude>
|
||||
<exclude>src/it/java</exclude>
|
||||
<exclude>org/owasp/webgoat/*Test</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@ -521,7 +522,6 @@
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<version>${checkstyle.version}</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
<consoleOutput>true</consoleOutput>
|
||||
<failsOnError>true</failsOnError>
|
||||
<configLocation>config/checkstyle/checkstyle.xml</configLocation>
|
||||
@ -532,7 +532,7 @@
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<version>2.38.0</version>
|
||||
<version>2.41.1</version>
|
||||
<configuration>
|
||||
<formats>
|
||||
<format>
|
||||
@ -593,7 +593,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.5.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>restrict-log4j-versions</id>
|
||||
@ -617,10 +617,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
@ -650,16 +646,15 @@
|
||||
<portNames>
|
||||
<portName>webgoat.port</portName>
|
||||
<portName>webwolf.port</portName>
|
||||
<portName>jmxPort</portName>
|
||||
</portNames>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.bazaarvoice.maven.plugins</groupId>
|
||||
<groupId>org.honton.chas</groupId>
|
||||
<artifactId>process-exec-maven-plugin</artifactId>
|
||||
<version>0.9</version>
|
||||
<version>0.9.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>start-jar</id>
|
||||
@ -667,8 +662,18 @@
|
||||
<goal>start</goal>
|
||||
</goals>
|
||||
<phase>pre-integration-test</phase>
|
||||
|
||||
<configuration>
|
||||
<workingDir>${project.build.directory}</workingDir>
|
||||
<environment>
|
||||
<WEBGOAT_SSLENABLED>${webgoat.sslenabled}</WEBGOAT_SSLENABLED>
|
||||
<WEBGOAT_HOST>127.0.0.1</WEBGOAT_HOST>
|
||||
<WEBGOAT_PORT>${webgoat.port}</WEBGOAT_PORT>
|
||||
<WEBGOAT_CONTEXT>${webgoat.context}</WEBGOAT_CONTEXT>
|
||||
<WEBWOLF_HOST>127.0.0.1</WEBWOLF_HOST>
|
||||
<WEBWOLF_PORT>${webwolf.port}</WEBWOLF_PORT>
|
||||
<WEBWOLF_CONTEXT>${webwolf.context}</WEBWOLF_CONTEXT>
|
||||
</environment>
|
||||
<arguments>
|
||||
<argument>java</argument>
|
||||
<argument>-jar</argument>
|
||||
@ -676,8 +681,6 @@
|
||||
<argument>-Dwebgoat.server.directory=${java.io.tmpdir}/webgoat_${webgoat.port}</argument>
|
||||
<argument>-Dwebgoat.user.directory=${java.io.tmpdir}/webgoat_${webgoat.port}</argument>
|
||||
<argument>-Dspring.main.banner-mode=off</argument>
|
||||
<argument>-Dwebgoat.port=${webgoat.port}</argument>
|
||||
<argument>-Dwebwolf.port=${webwolf.port}</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.base/java.lang=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
@ -685,25 +688,18 @@
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.base/java.lang.reflect=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.base/java.text=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.desktop/java.beans=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.desktop/java.awt.font=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.base/sun.nio.ch=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.base/java.io=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.base/java.util=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.base/sun.nio.ch=ALL-UNNAMED</argument>
|
||||
<argument>--add-opens</argument>
|
||||
<argument>java.base/java.io=ALL-UNNAMED</argument>
|
||||
<argument>${project.build.directory}/webgoat-${project.version}.jar</argument>
|
||||
</arguments>
|
||||
<waitForInterrupt>false</waitForInterrupt>
|
||||
<healthcheckUrl>http://localhost:${webgoat.port}/WebGoat/actuator/health</healthcheckUrl>
|
||||
<waitAfterLaunch>${waittimeForServerStart}</waitAfterLaunch>
|
||||
<healthCheckUrl>http://127.0.0.1:${webgoat.port}${webgoat.context}login</healthCheckUrl>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
@ -728,7 +724,6 @@
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>6.5.1</version>
|
||||
<configuration>
|
||||
<failBuildOnCVSS>7</failBuildOnCVSS>
|
||||
<skipProvidedScope>false</skipProvidedScope>
|
||||
@ -777,7 +772,6 @@
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>before-unit-test</id>
|
||||
|
@ -12,8 +12,10 @@ Then see security settings and allow the file to run
|
||||
pip3 install virtualenv --user
|
||||
python3 -m virtualenv .venv
|
||||
source .venv/bin/activate
|
||||
pip install robotframework
|
||||
pip install robotframework-SeleniumLibrary
|
||||
pip install webdriver-manager
|
||||
pip install --upgrade robotframework
|
||||
pip install --upgrade robotframework-SeleniumLibrary
|
||||
pip install --upgrade webdriver-manager
|
||||
brew upgrade
|
||||
robot --variable HEADLESS:"0" --variable ENDPOINT:"http://127.0.0.1:8080/WebGoat" goat.robot
|
||||
|
||||
Make sure that the Chrome version, the webdriver version and all related components are up-to-date and compatible!
|
||||
|
@ -2,6 +2,7 @@
|
||||
Documentation Setup WebGoat Robotframework tests
|
||||
Library SeleniumLibrary timeout=100 run_on_failure=Capture Page Screenshot
|
||||
Library String
|
||||
Library OperatingSystem
|
||||
|
||||
Suite Setup Initial_Page ${ENDPOINT} ${BROWSER}
|
||||
Suite Teardown Close_Page
|
||||
@ -11,7 +12,7 @@ ${BROWSER} chrome
|
||||
${SLEEP} 100
|
||||
${DELAY} 0.25
|
||||
${ENDPOINT} http://127.0.0.1:8080/WebGoat
|
||||
${ENDPOINT_WOLF} http://127.0.0.1:9090
|
||||
${ENDPOINT_WOLF} http://127.0.0.1:9090/WebWolf
|
||||
${USERNAME} robotuser
|
||||
${PASSWORD} password
|
||||
${HEADLESS} ${FALSE}
|
||||
@ -22,22 +23,25 @@ Initial_Page
|
||||
[Arguments] ${ENDPOINT} ${BROWSER}
|
||||
Log To Console Start WebGoat UI Testing
|
||||
IF ${HEADLESS}
|
||||
Open Browser ${ENDPOINT} ${BROWSER} options=add_argument("-headless");add_argument("--start-maximized");add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webgoat
|
||||
Open Browser ${ENDPOINT} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'});add_argument("-headless");add_argument("--start-maximized") alias=webgoat
|
||||
ELSE
|
||||
Open Browser ${ENDPOINT} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webgoat
|
||||
END
|
||||
IF ${HEADLESS}
|
||||
Open Browser ${ENDPOINT_WOLF}/WebWolf ${BROWSER} options=add_argument("-headless");add_argument("--start-maximized");add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webwolf
|
||||
ELSE
|
||||
Open Browser ${ENDPOINT_WOLF}/WebWolf ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webwolf
|
||||
END
|
||||
Switch Browser webgoat
|
||||
Maximize Browser Window
|
||||
Set Window Size ${1400} ${1000}
|
||||
Set Window Position ${0} ${0}
|
||||
Set Selenium Speed ${DELAY}
|
||||
Log To Console Start WebWolf UI Testing
|
||||
IF ${HEADLESS}
|
||||
Open Browser ${ENDPOINT_WOLF} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'});add_argument("-headless");add_argument("--start-maximized") alias=webwolf
|
||||
ELSE
|
||||
Open Browser ${ENDPOINT_WOLF} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webwolf
|
||||
END
|
||||
Switch Browser webwolf
|
||||
Maximize Browser Window
|
||||
Set Window Size ${1400} ${1000}
|
||||
Set Window Position ${400} ${200}
|
||||
Set Window Position ${500} ${0}
|
||||
Set Selenium Speed ${DELAY}
|
||||
|
||||
Close_Page
|
||||
@ -53,6 +57,7 @@ Close_Page
|
||||
*** Test Cases ***
|
||||
|
||||
Check_Initial_Page
|
||||
[Tags] WebGoatTests
|
||||
Switch Browser webgoat
|
||||
Page Should Contain Username
|
||||
Click Button Sign in
|
||||
@ -60,6 +65,7 @@ Check_Initial_Page
|
||||
Click Link /WebGoat/registration
|
||||
|
||||
Check_Registration_Page
|
||||
[Tags] WebGoatTests
|
||||
Page Should Contain Username
|
||||
Input Text username ${USERNAME}
|
||||
Input Text password ${PASSWORD}
|
||||
@ -68,6 +74,7 @@ Check_Registration_Page
|
||||
Click Button Sign up
|
||||
|
||||
Check_Welcome_Page
|
||||
[Tags] WebGoatTests
|
||||
Page Should Contain WebGoat
|
||||
Go To ${ENDPOINT}/login
|
||||
Page Should Contain Username
|
||||
@ -77,6 +84,7 @@ Check_Welcome_Page
|
||||
Page Should Contain WebGoat
|
||||
|
||||
Check_Menu_Page
|
||||
[Tags] WebGoatTests
|
||||
Click Element css=a[category='Introduction']
|
||||
Click Element Introduction-WebGoat
|
||||
CLick Element Introduction-WebWolf
|
||||
@ -93,9 +101,29 @@ Check_Menu_Page
|
||||
|
||||
Check_WebWolf
|
||||
Switch Browser webwolf
|
||||
location should be ${ENDPOINT_WOLF}/WebWolf
|
||||
Go To ${ENDPOINT_WOLF}/mail
|
||||
location should be ${ENDPOINT_WOLF}/login
|
||||
Input Text username ${USERNAME}
|
||||
Input Text password ${PASSWORD}
|
||||
Click Button Sign In
|
||||
Go To ${ENDPOINT_WOLF}/mail
|
||||
Go To ${ENDPOINT_WOLF}/requests
|
||||
Go To ${ENDPOINT_WOLF}/files
|
||||
|
||||
Check_JWT_Page
|
||||
Go To ${ENDPOINT_WOLF}/jwt
|
||||
Click Element token
|
||||
Wait Until Element Is Enabled token 5s
|
||||
Input Text token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
|
||||
Click Element secretKey
|
||||
Input Text secretKey none
|
||||
Sleep 2s # Pause before reading the result
|
||||
${OUT_VALUE} Get Value xpath=//textarea[@id='token']
|
||||
Log To Console Found token ${OUT_VALUE}
|
||||
${OUT_RESULT} Evaluate "ImuPnHvLdU7ULKfbD4aJU" in """${OUT_VALUE}"""
|
||||
Log To Console Found token ${OUT_RESULT}
|
||||
Capture Page Screenshot
|
||||
|
||||
Check_Files_Page
|
||||
Go To ${ENDPOINT_WOLF}/files
|
||||
Choose File css:input[type="file"] ${CURDIR}/goat.robot
|
||||
Click Button Upload files
|
||||
|
@ -15,7 +15,7 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
||||
assignment2();
|
||||
assignment3();
|
||||
|
||||
checkResults("/access-control");
|
||||
checkResults("MissingFunctionAC");
|
||||
}
|
||||
|
||||
private void assignment3() {
|
||||
@ -25,7 +25,7 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.contentType(ContentType.JSON)
|
||||
.get(url("/WebGoat/access-control/users-admin-fix"))
|
||||
.get(url("access-control/users-admin-fix"))
|
||||
.then()
|
||||
.statusCode(HttpStatus.SC_FORBIDDEN);
|
||||
|
||||
@ -40,7 +40,7 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.contentType(ContentType.JSON)
|
||||
.body(String.format(userTemplate, this.getUser(), this.getUser()))
|
||||
.post(url("/WebGoat/access-control/users"))
|
||||
.post(url("access-control/users"))
|
||||
.then()
|
||||
.statusCode(HttpStatus.SC_OK);
|
||||
|
||||
@ -51,15 +51,14 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.contentType(ContentType.JSON)
|
||||
.get(url("/WebGoat/access-control/users-admin-fix"))
|
||||
.get(url("access-control/users-admin-fix"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.jsonPath()
|
||||
.get("find { it.username == \"Jerry\" }.userHash");
|
||||
|
||||
checkAssignment(
|
||||
url("/WebGoat/access-control/user-hash-fix"), Map.of("userHash", userHash), true);
|
||||
checkAssignment(url("access-control/user-hash-fix"), Map.of("userHash", userHash), true);
|
||||
}
|
||||
|
||||
private void assignment2() {
|
||||
@ -69,18 +68,18 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.contentType(ContentType.JSON)
|
||||
.get(url("/WebGoat/access-control/users"))
|
||||
.get(url("access-control/users"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.jsonPath()
|
||||
.get("find { it.username == \"Jerry\" }.userHash");
|
||||
|
||||
checkAssignment(url("/WebGoat/access-control/user-hash"), Map.of("userHash", userHash), true);
|
||||
checkAssignment(url("access-control/user-hash"), Map.of("userHash", userHash), true);
|
||||
}
|
||||
|
||||
private void assignment1() {
|
||||
var params = Map.of("hiddenMenu1", "Users", "hiddenMenu2", "Config");
|
||||
checkAssignment(url("/WebGoat/access-control/hidden-menu"), params, true);
|
||||
checkAssignment(url("access-control/hidden-menu"), params, true);
|
||||
}
|
||||
}
|
||||
|
@ -64,12 +64,12 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
public void init() {
|
||||
startLesson("CSRF");
|
||||
webwolfFileDir = getWebWolfFileServerLocation();
|
||||
uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("/csrf/basic-get-flag")));
|
||||
uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("/csrf/review")));
|
||||
uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("/csrf/feedback/message")));
|
||||
uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("csrf/basic-get-flag")));
|
||||
uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("csrf/review")));
|
||||
uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("csrf/feedback/message")));
|
||||
uploadTrickHtml(
|
||||
"csrf8.html",
|
||||
trickHTML8.replace("WEBGOATURL", url("/login")).replace("USERNAME", this.getUser()));
|
||||
trickHTML8.replace("WEBGOATURL", url("login")).replace("USERNAME", this.getUser()));
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
@ -86,7 +86,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
// logout();
|
||||
login(); // because old cookie got replaced and invalidated
|
||||
startLesson("CSRF", false);
|
||||
checkResults("/csrf");
|
||||
checkResults("CSRF");
|
||||
}
|
||||
|
||||
private void uploadTrickHtml(String htmlName, String htmlContent) throws IOException {
|
||||
@ -103,7 +103,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.multiPart("file", htmlName, htmlContent.getBytes())
|
||||
.post(webWolfUrl("/WebWolf/fileupload"))
|
||||
.post(new WebWolfUrlBuilder().path("fileupload").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -118,7 +118,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.get(webWolfUrl("/files/" + this.getUser() + "/" + htmlName))
|
||||
.get(new WebWolfUrlBuilder().path("files/%s/%s", this.getUser(), htmlName).build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -136,7 +136,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.header("Referer", webWolfUrl("/files/fake.html"))
|
||||
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
|
||||
.post(goatURL)
|
||||
.then()
|
||||
.extract()
|
||||
@ -146,7 +146,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("confirmFlagVal", flag);
|
||||
checkAssignment(url("/WebGoat/csrf/confirm-flag-1"), params, true);
|
||||
checkAssignment(url("csrf/confirm-flag-1"), params, true);
|
||||
}
|
||||
|
||||
private void checkAssignment4(String goatURL) {
|
||||
@ -163,7 +163,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.header("Referer", webWolfUrl("/files/fake.html"))
|
||||
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
|
||||
.formParams(params)
|
||||
.post(goatURL)
|
||||
.then()
|
||||
@ -184,7 +184,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.header("Referer", webWolfUrl("/files/fake.html"))
|
||||
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
|
||||
.contentType(ContentType.TEXT)
|
||||
.body(
|
||||
"{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is"
|
||||
@ -198,7 +198,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
|
||||
params.clear();
|
||||
params.put("confirmFlagVal", flag);
|
||||
checkAssignment(url("/WebGoat/csrf/feedback"), params, true);
|
||||
checkAssignment(url("csrf/feedback"), params, true);
|
||||
}
|
||||
|
||||
private void checkAssignment8(String goatURL) {
|
||||
@ -217,7 +217,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.header("Referer", webWolfUrl("/files/fake.html"))
|
||||
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
|
||||
.params(params)
|
||||
.post(goatURL)
|
||||
.then()
|
||||
@ -239,7 +239,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", newCookie)
|
||||
.post(url("/csrf/login"))
|
||||
.post(url("csrf/login"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -253,15 +253,16 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
||||
Overview[] assignments =
|
||||
RestAssured.given()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/service/lessonoverview.mvc"))
|
||||
.relaxedHTTPSValidation()
|
||||
.get(url("service/lessonoverview.mvc/CSRF"))
|
||||
.then()
|
||||
.extract()
|
||||
.jsonPath()
|
||||
.getObject("$", Overview[].class);
|
||||
// assertThat(assignments)
|
||||
// .filteredOn(a -> a.getAssignment().getName().equals("CSRFLogin"))
|
||||
// .extracting(o -> o.solved)
|
||||
// .containsExactly(true);
|
||||
assertThat(assignments)
|
||||
.filteredOn(a -> a.getAssignment().getName().equals("CSRFLogin"))
|
||||
.extracting(o -> o.solved)
|
||||
.containsExactly(true);
|
||||
}
|
||||
|
||||
@Data
|
||||
|
@ -22,7 +22,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/WebGoat/challenge/logo"))
|
||||
.get(url("challenge/logo"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -34,14 +34,14 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
||||
params.put("username", "admin");
|
||||
params.put("password", "!!webgoat_admin_1234!!".replace("1234", pincode));
|
||||
|
||||
checkAssignment(url("/WebGoat/challenge/1"), params, true);
|
||||
checkAssignment(url("challenge/1"), params, true);
|
||||
String result =
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.formParams(params)
|
||||
.post(url("/WebGoat/challenge/1"))
|
||||
.post(url("challenge/1"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -50,16 +50,16 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||
params.clear();
|
||||
params.put("flag", flag);
|
||||
checkAssignment(url("/WebGoat/challenge/flag"), params, true);
|
||||
checkAssignment(url("challenge/flag/1"), params, true);
|
||||
|
||||
checkResults("/challenge/1");
|
||||
checkResults("Challenge1");
|
||||
|
||||
List<String> capturefFlags =
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/WebGoat/scoreboard-data"))
|
||||
.get(url("scoreboard-data"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -83,7 +83,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.formParams(params)
|
||||
.post(url("/WebGoat/challenge/5"))
|
||||
.post(url("challenge/5"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -92,16 +92,16 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||
params.clear();
|
||||
params.put("flag", flag);
|
||||
checkAssignment(url("/WebGoat/challenge/flag"), params, true);
|
||||
checkAssignment(url("challenge/flag/5"), params, true);
|
||||
|
||||
checkResults("/challenge/5");
|
||||
checkResults("Challenge5");
|
||||
|
||||
List<String> capturefFlags =
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/WebGoat/scoreboard-data"))
|
||||
.get(url("scoreboard-data"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -120,19 +120,19 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/WebGoat/challenge/7/.git"))
|
||||
.get(url("challenge/7/.git"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.asString();
|
||||
|
||||
// Should send an email to WebWolf inbox this should give a hint to the link being static
|
||||
// Should email WebWolf inbox this should give a hint to the link being static
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.formParams("email", getUser() + "@webgoat.org")
|
||||
.post(url("/WebGoat/challenge/7"))
|
||||
.post(url("challenge/7"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -144,7 +144,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.get(webWolfUrl("/mail"))
|
||||
.get(new WebWolfUrlBuilder().path("mail").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -158,13 +158,13 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/challenge/7/reset-password/{link}"), "375afe1104f4a487a73823c50a9292a2")
|
||||
.get(url("challenge/7/reset-password/{link}"), "375afe1104f4a487a73823c50a9292a2")
|
||||
.then()
|
||||
.statusCode(HttpStatus.ACCEPTED.value())
|
||||
.extract()
|
||||
.asString();
|
||||
|
||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||
checkAssignment(url("/WebGoat/challenge/flag"), Map.of("flag", flag), true);
|
||||
checkAssignment(url("challenge/flag/7"), Map.of("flag", flag), true);
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
|
||||
checkAssignmentDefaults();
|
||||
|
||||
checkResults("/crypto");
|
||||
checkResults("Cryptography");
|
||||
}
|
||||
|
||||
private void checkAssignment2() {
|
||||
@ -52,7 +52,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/crypto/encoding/basic"))
|
||||
.get(url("crypto/encoding/basic"))
|
||||
.then()
|
||||
.extract()
|
||||
.asString();
|
||||
@ -64,7 +64,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
params.clear();
|
||||
params.put("answer_user", answer_user);
|
||||
params.put("answer_pwd", answer_pwd);
|
||||
checkAssignment(url("/crypto/encoding/basic-auth"), params, true);
|
||||
checkAssignment(url("crypto/encoding/basic-auth"), params, true);
|
||||
}
|
||||
|
||||
private void checkAssignment3() {
|
||||
@ -72,7 +72,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("answer_pwd1", answer_1);
|
||||
checkAssignment(url("/crypto/encoding/xor"), params, true);
|
||||
checkAssignment(url("crypto/encoding/xor"), params, true);
|
||||
}
|
||||
|
||||
private void checkAssignment4() throws NoSuchAlgorithmException {
|
||||
@ -82,7 +82,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/crypto/hashing/md5"))
|
||||
.get(url("crypto/hashing/md5"))
|
||||
.then()
|
||||
.extract()
|
||||
.asString();
|
||||
@ -92,7 +92,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/crypto/hashing/sha256"))
|
||||
.get(url("crypto/hashing/sha256"))
|
||||
.then()
|
||||
.extract()
|
||||
.asString();
|
||||
@ -112,7 +112,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
params.clear();
|
||||
params.put("answer_pwd1", answer_1);
|
||||
params.put("answer_pwd2", answer_2);
|
||||
checkAssignment(url("/WebGoat/crypto/hashing"), params, true);
|
||||
checkAssignment(url("crypto/hashing"), params, true);
|
||||
}
|
||||
|
||||
private void checkAssignmentSigning() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
@ -122,7 +122,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/crypto/signing/getprivate"))
|
||||
.get(url("crypto/signing/getprivate"))
|
||||
.then()
|
||||
.extract()
|
||||
.asString();
|
||||
@ -135,7 +135,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
params.clear();
|
||||
params.put("modulus", modulus);
|
||||
params.put("signature", signature);
|
||||
checkAssignment(url("/crypto/signing/verify"), params, true);
|
||||
checkAssignment(url("crypto/signing/verify"), params, true);
|
||||
}
|
||||
|
||||
private void checkAssignmentDefaults() {
|
||||
@ -151,6 +151,6 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
||||
params.clear();
|
||||
params.put("secretText", text);
|
||||
params.put("secretFileName", "default_secret");
|
||||
checkAssignment(url("/crypto/secure/defaults"), params, true);
|
||||
checkAssignment(url("crypto/secure/defaults"), params, true);
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +26,8 @@ public class DeserializationIntegrationTest extends IntegrationTest {
|
||||
params.put(
|
||||
"token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")));
|
||||
}
|
||||
checkAssignment(url("/WebGoat/InsecureDeserialization/task"), params, true);
|
||||
checkAssignment(url("InsecureDeserialization/task"), params, true);
|
||||
|
||||
checkResults("/InsecureDeserialization/");
|
||||
checkResults("InsecureDeserialization");
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,17 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
params.put("magic_num", "33");
|
||||
checkAssignment(url("HttpBasics/attack2"), params, true);
|
||||
|
||||
checkResults("/HttpBasics/");
|
||||
checkResults("HttpBasics");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void solveAsOtherUserHttpBasics() {
|
||||
login("steven");
|
||||
startLesson("HttpBasics");
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("person", "goatuser");
|
||||
checkAssignment(url("HttpBasics/attack1"), params, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -51,7 +61,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
.path("lessonCompleted"),
|
||||
CoreMatchers.is(true));
|
||||
|
||||
checkResults("/HttpProxies/");
|
||||
checkResults("HttpProxies");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -72,8 +82,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
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/");
|
||||
checkAssignment(url("cia/quiz"), params, true);
|
||||
checkResults("CIA");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -95,8 +105,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("payload", solution);
|
||||
checkAssignment(url("/WebGoat/VulnerableComponents/attack1"), params, true);
|
||||
checkResults("/VulnerableComponents/");
|
||||
checkAssignment(url("VulnerableComponents/attack1"), params, true);
|
||||
checkResults("VulnerableComponents");
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,8 +117,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
params.clear();
|
||||
params.put("username", "CaptainJack");
|
||||
params.put("password", "BlackPearl");
|
||||
checkAssignment(url("/WebGoat/InsecureLogin/task"), params, true);
|
||||
checkResults("/InsecureLogin/");
|
||||
checkAssignment(url("InsecureLogin/task"), params, true);
|
||||
checkResults("InsecureLogin");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -117,8 +127,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("password", "ajnaeliclm^&&@kjn.");
|
||||
checkAssignment(url("/WebGoat/SecurePasswords/assignment"), params, true);
|
||||
checkResults("SecurePasswords/");
|
||||
checkAssignment(url("SecurePasswords/assignment"), params, true);
|
||||
checkResults("SecurePasswords");
|
||||
|
||||
startLesson("AuthBypass");
|
||||
params.clear();
|
||||
@ -127,8 +137,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
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/");
|
||||
checkAssignment(url("auth-bypass/verify-account"), params, true);
|
||||
checkResults("AuthBypass");
|
||||
|
||||
startLesson("HttpProxies");
|
||||
MatcherAssert.assertThat(
|
||||
@ -138,14 +148,13 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.header("x-request-intercepted", "true")
|
||||
.contentType(ContentType.JSON)
|
||||
.get(
|
||||
url("/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
|
||||
.get(url("HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.path("lessonCompleted"),
|
||||
CoreMatchers.is(true));
|
||||
checkResults("/HttpProxies/");
|
||||
checkResults("HttpProxies");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -165,7 +174,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
.header("webgoat-requested-by", "dom-xss-vuln")
|
||||
.header("X-Requested-With", "XMLHttpRequest")
|
||||
.formParams(params)
|
||||
.post(url("/WebGoat/CrossSiteScripting/phone-home-xss"))
|
||||
.post(url("CrossSiteScripting/phone-home-xss"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -174,14 +183,14 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
|
||||
params.clear();
|
||||
params.put("successMessage", secretNumber);
|
||||
checkAssignment(url("/WebGoat/ChromeDevTools/dummy"), params, true);
|
||||
checkAssignment(url("ChromeDevTools/dummy"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("number", "24");
|
||||
params.put("network_num", "24");
|
||||
checkAssignment(url("/WebGoat/ChromeDevTools/network"), params, true);
|
||||
checkAssignment(url("ChromeDevTools/network"), params, true);
|
||||
|
||||
checkResults("/ChromeDevTools/");
|
||||
checkResults("ChromeDevTools");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -194,8 +203,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
params.put("jsEnabled", "1");
|
||||
params.put("verifyMethod", "SEC_QUESTIONS");
|
||||
params.put("userId", "12309746");
|
||||
checkAssignment(url("/auth-bypass/verify-account"), params, true);
|
||||
checkResults("/auth-bypass/");
|
||||
checkAssignment(url("auth-bypass/verify-account"), params, true);
|
||||
checkResults("AuthBypass");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -205,7 +214,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
||||
params.clear();
|
||||
params.put("param1", "secr37Value");
|
||||
params.put("param2", "Main");
|
||||
checkAssignment(url("/lesson-template/sample-attack"), params, true);
|
||||
checkResults("/lesson-template/");
|
||||
checkAssignment(url("lesson-template/sample-attack"), params, true);
|
||||
checkResults("LessonTemplate");
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,9 @@ import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.SneakyThrows;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@ -19,7 +17,6 @@ import org.junit.jupiter.api.TestFactory;
|
||||
public class IDORIntegrationTest extends IntegrationTest {
|
||||
|
||||
@BeforeEach
|
||||
@SneakyThrows
|
||||
public void init() {
|
||||
startLesson("IDOR");
|
||||
}
|
||||
@ -27,56 +24,63 @@ public class IDORIntegrationTest extends IntegrationTest {
|
||||
@TestFactory
|
||||
Iterable<DynamicTest> testIDORLesson() {
|
||||
return Arrays.asList(
|
||||
dynamicTest("login", () -> loginIDOR()), dynamicTest("profile", () -> profile()));
|
||||
dynamicTest("assignment 2 - login", this::loginIDOR),
|
||||
dynamicTest("profile", this::profile));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void shutdown() throws IOException {
|
||||
checkResults("/IDOR");
|
||||
public void shutdown() {
|
||||
checkResults("IDOR");
|
||||
}
|
||||
|
||||
private void loginIDOR() throws IOException {
|
||||
private void loginIDOR() {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("username", "tom");
|
||||
params.put("password", "cat");
|
||||
|
||||
checkAssignment(url("/WebGoat/IDOR/login"), params, true);
|
||||
checkAssignment(url("IDOR/login"), params, true);
|
||||
}
|
||||
|
||||
private void profile() {
|
||||
|
||||
// View profile - assignment 3a
|
||||
MatcherAssert.assertThat(
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/WebGoat/IDOR/profile"))
|
||||
.get(url("IDOR/profile"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.path("userId"),
|
||||
CoreMatchers.is("2342384"));
|
||||
|
||||
// Show difference - assignment 3b
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("attributes", "userId,role");
|
||||
checkAssignment(url("/WebGoat/IDOR/diff-attributes"), params, true);
|
||||
checkAssignment(url("IDOR/diff-attributes"), params, true);
|
||||
|
||||
// View profile another way - assignment 4
|
||||
params.clear();
|
||||
params.put("url", "WebGoat/IDOR/profile/2342384");
|
||||
checkAssignment(url("/WebGoat/IDOR/profile/alt-path"), params, true);
|
||||
checkAssignment(url("IDOR/profile/alt-path"), params, true);
|
||||
|
||||
// assignment 5a
|
||||
MatcherAssert.assertThat(
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/WebGoat/IDOR/profile/2342388"))
|
||||
.get(url("IDOR/profile/2342388"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.path("lessonCompleted"),
|
||||
CoreMatchers.is(true));
|
||||
|
||||
// assignment 5b
|
||||
MatcherAssert.assertThat(
|
||||
RestAssured.given()
|
||||
.when()
|
||||
@ -86,7 +90,7 @@ public class IDORIntegrationTest extends IntegrationTest {
|
||||
.body(
|
||||
"{\"role\":\"1\", \"color\":\"red\", \"size\":\"large\", \"name\":\"Buffalo Bill\","
|
||||
+ " \"userId\":\"2342388\"}")
|
||||
.put(url("/WebGoat/IDOR/profile/2342388"))
|
||||
.put(url("IDOR/profile/2342388"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
|
@ -3,9 +3,9 @@ package org.owasp.webgoat;
|
||||
import static io.restassured.RestAssured.given;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.filter.log.LogDetail;
|
||||
import io.restassured.http.ContentType;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import lombok.Getter;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
@ -15,36 +15,81 @@ import org.springframework.http.HttpStatus;
|
||||
|
||||
public abstract class IntegrationTest {
|
||||
|
||||
private static String webGoatPort = Objects.requireNonNull(System.getProperty("webgoatport"));
|
||||
private static String webGoatPort = System.getenv().getOrDefault("WEBGOAT_PORT", "8080");
|
||||
@Getter private static String webWolfPort = System.getenv().getOrDefault("WEBWOLF_PORT", "9090");
|
||||
|
||||
@Getter
|
||||
private static String webWolfPort = Objects.requireNonNull(System.getProperty("webwolfport"));
|
||||
private static String webWolfHost = System.getenv().getOrDefault("WEBWOLF_HOST", "127.0.0.1");
|
||||
|
||||
private static String webGoatContext =
|
||||
System.getenv().getOrDefault("WEBGOAT_CONTEXT", "/WebGoat/");
|
||||
private static String webWolfContext =
|
||||
System.getenv().getOrDefault("WEBWOLF_CONTEXT", "/WebWolf/");
|
||||
|
||||
private static boolean useSSL = false;
|
||||
private static String webgoatUrl =
|
||||
(useSSL ? "https:" : "http:") + "//localhost:" + webGoatPort + "/WebGoat/";
|
||||
private static String webWolfUrl =
|
||||
(useSSL ? "https:" : "http:") + "//localhost:" + webWolfPort + "/";
|
||||
@Getter private String webGoatCookie;
|
||||
@Getter private String webWolfCookie;
|
||||
@Getter private final String user = "webgoat";
|
||||
|
||||
protected String url(String url) {
|
||||
url = url.replaceFirst("/WebGoat/", "");
|
||||
url = url.replaceFirst("/WebGoat", "");
|
||||
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
|
||||
return webgoatUrl + url;
|
||||
return "http://localhost:%s%s%s".formatted(webGoatPort, webGoatContext, url);
|
||||
}
|
||||
|
||||
protected String webWolfUrl(String url) {
|
||||
url = url.replaceFirst("/WebWolf/", "");
|
||||
url = url.replaceFirst("/WebWolf", "");
|
||||
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
|
||||
return webWolfUrl + url;
|
||||
protected class WebWolfUrlBuilder {
|
||||
|
||||
private boolean attackMode = false;
|
||||
private String path = null;
|
||||
|
||||
protected String build() {
|
||||
return "http://localhost:%s%s%s"
|
||||
.formatted(webWolfPort, webWolfContext, path != null ? path : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* In attack mode it means WebGoat calls WebWolf to perform an attack. In this case we need to
|
||||
* use port 9090 in a Docker environment.
|
||||
*/
|
||||
protected WebWolfUrlBuilder attackMode() {
|
||||
attackMode = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected WebWolfUrlBuilder path(String path) {
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected WebWolfUrlBuilder path(String path, String... uriVariables) {
|
||||
this.path = path.formatted(uriVariables);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugging options: install TestContainers Desktop and map port 5005 to the host machine with
|
||||
* https://newsletter.testcontainers.com/announcements/set-fixed-ports-to-easily-debug-development-services
|
||||
*
|
||||
* <p>Start the test and connect a remote debugger in IntelliJ to localhost:5005 and attach it.
|
||||
*/
|
||||
// private static GenericContainer<?> webGoatContainer =
|
||||
// new GenericContainer(new ImageFromDockerfile("webgoat").withFileFromPath("/",
|
||||
// Paths.get(".")))
|
||||
// .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("webgoat")))
|
||||
// .withExposedPorts(8080, 9090, 5005)
|
||||
// .withEnv(
|
||||
// "_JAVA_OPTIONS",
|
||||
// "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:5005")
|
||||
// .waitingFor(Wait.forHealthcheck());
|
||||
//
|
||||
// static {
|
||||
// webGoatContainer.start();
|
||||
// }
|
||||
|
||||
@BeforeEach
|
||||
public void login() {
|
||||
login("webgoat");
|
||||
}
|
||||
|
||||
protected void login(String user) {
|
||||
String location =
|
||||
given()
|
||||
.when()
|
||||
@ -53,6 +98,8 @@ public abstract class IntegrationTest {
|
||||
.formParam("password", "password")
|
||||
.post(url("login"))
|
||||
.then()
|
||||
.log()
|
||||
.ifValidationFails(LogDetail.ALL) // Log the response details if validation fails
|
||||
.cookie("JSESSIONID")
|
||||
.statusCode(302)
|
||||
.extract()
|
||||
@ -93,7 +140,7 @@ public abstract class IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.formParam("username", user)
|
||||
.formParam("password", "password")
|
||||
.post(webWolfUrl("login"))
|
||||
.post(new WebWolfUrlBuilder().path("login").build())
|
||||
.then()
|
||||
.statusCode(302)
|
||||
.cookie("WEBWOLFSESSION")
|
||||
@ -124,7 +171,7 @@ public abstract class IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("service/restartlesson.mvc"))
|
||||
.get(url("service/restartlesson.mvc/%s.lesson".formatted(lessonName)))
|
||||
.then()
|
||||
.statusCode(200);
|
||||
}
|
||||
@ -160,23 +207,18 @@ public abstract class IntegrationTest {
|
||||
CoreMatchers.is(expectedResult));
|
||||
}
|
||||
|
||||
// TODO is prefix useful? not every lesson endpoint needs to start with a certain prefix (they are
|
||||
// only required to be in the same package)
|
||||
public void checkResults(String prefix) {
|
||||
checkResults();
|
||||
|
||||
MatcherAssert.assertThat(
|
||||
public void checkResults(String lesson) {
|
||||
var result =
|
||||
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)));
|
||||
.get(url("service/lessonoverview.mvc/%s.lesson".formatted(lesson)))
|
||||
.andReturn();
|
||||
|
||||
MatcherAssert.assertThat(
|
||||
result.then().statusCode(200).extract().jsonPath().getList("solved"),
|
||||
CoreMatchers.everyItem(CoreMatchers.is(true)));
|
||||
}
|
||||
|
||||
public void checkResults() {
|
||||
@ -231,7 +273,7 @@ public abstract class IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.get(webWolfUrl("/file-server-location"))
|
||||
.get(new WebWolfUrlBuilder().path("file-server-location").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -246,7 +288,7 @@ public abstract class IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/server-directory"))
|
||||
.get(url("server-directory"))
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -259,7 +301,7 @@ public abstract class IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.delete(webWolfUrl("/mail"))
|
||||
.delete(new WebWolfUrlBuilder().path("mail").build())
|
||||
.then()
|
||||
.statusCode(HttpStatus.ACCEPTED.value());
|
||||
}
|
||||
|
@ -13,8 +13,10 @@ import io.jsonwebtoken.impl.TextCodec;
|
||||
import io.restassured.RestAssured;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.time.Instant;
|
||||
import java.util.Base64;
|
||||
import java.util.Calendar;
|
||||
@ -23,13 +25,15 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.jose4j.jwk.JsonWebKeySet;
|
||||
import org.jose4j.jwk.RsaJsonWebKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint;
|
||||
|
||||
public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void solveAssignment() throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
||||
public void solveAssignment() throws IOException, NoSuchAlgorithmException {
|
||||
startLesson("JWT");
|
||||
|
||||
decodingToken();
|
||||
@ -40,15 +44,16 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
|
||||
buyAsTom();
|
||||
|
||||
deleteTom();
|
||||
deleteTomThroughKidClaim();
|
||||
|
||||
deleteTomThroughJkuClaim();
|
||||
|
||||
quiz();
|
||||
|
||||
checkResults("/JWT/");
|
||||
checkResults("JWT");
|
||||
}
|
||||
|
||||
private String generateToken(String key) {
|
||||
|
||||
return Jwts.builder()
|
||||
.setIssuer("WebGoat Token Builder")
|
||||
.setAudience("webgoat.org")
|
||||
@ -81,7 +86,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.formParam("jwt-encode-user", "user")
|
||||
.post(url("/WebGoat/JWT/decode"))
|
||||
.post(url("JWT/decode"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -89,14 +94,14 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
CoreMatchers.is(true));
|
||||
}
|
||||
|
||||
private void findPassword() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
|
||||
private void findPassword() {
|
||||
|
||||
String accessToken =
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/WebGoat/JWT/secret/gettoken"))
|
||||
.get(url("JWT/secret/gettoken"))
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -110,7 +115,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.formParam("token", generateToken(secret))
|
||||
.post(url("/WebGoat/JWT/secret"))
|
||||
.post(url("JWT/secret"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -124,7 +129,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("/WebGoat/JWT/votings/login?user=Tom"))
|
||||
.get(url("JWT/votings/login?user=Tom"))
|
||||
.then()
|
||||
.extract()
|
||||
.cookie("access_token");
|
||||
@ -157,7 +162,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.cookie("access_token", replacedToken)
|
||||
.post(url("/WebGoat/JWT/votings"))
|
||||
.post(url("JWT/votings"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -198,7 +203,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.header("Authorization", "Bearer " + replacedToken)
|
||||
.post(url("/WebGoat/JWT/refresh/checkout"))
|
||||
.post(url("JWT/refresh/checkout"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -206,8 +211,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
CoreMatchers.is(true));
|
||||
}
|
||||
|
||||
private void deleteTom() {
|
||||
|
||||
private void deleteTomThroughKidClaim() {
|
||||
Map<String, Object> header = new HashMap();
|
||||
header.put(Header.TYPE, Header.JWT_TYPE);
|
||||
header.put(
|
||||
@ -232,7 +236,57 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.post(url("/WebGoat/JWT/final/delete?token=" + token))
|
||||
.post(url("JWT/kid/delete?token=" + token))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.path("lessonCompleted"),
|
||||
CoreMatchers.is(true));
|
||||
}
|
||||
|
||||
private void deleteTomThroughJkuClaim() throws NoSuchAlgorithmException {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(2048);
|
||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||
var jwks = new JsonWebKeySet(new RsaJsonWebKey((RSAPublicKey) keyPair.getPublic()));
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.multiPart("file", "jwks.json", jwks.toJson().getBytes())
|
||||
.post(new WebWolfUrlBuilder().path("fileupload").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
.getBody()
|
||||
.asString();
|
||||
|
||||
Map<String, Object> header = new HashMap();
|
||||
header.put(Header.TYPE, Header.JWT_TYPE);
|
||||
header.put(
|
||||
JwsHeader.JWK_SET_URL,
|
||||
new WebWolfUrlBuilder().attackMode().path("files/%s/jwks.json", getUser()).build());
|
||||
|
||||
String token =
|
||||
Jwts.builder()
|
||||
.setHeader(header)
|
||||
.setIssuer("WebGoat Token Builder")
|
||||
.setAudience("webgoat.org")
|
||||
.setIssuedAt(Calendar.getInstance().getTime())
|
||||
.setExpiration(Date.from(Instant.now().plusSeconds(60)))
|
||||
.setSubject("tom@webgoat.org")
|
||||
.claim("username", "Tom")
|
||||
.claim("Email", "tom@webgoat.org")
|
||||
.claim("Role", new String[] {"Manager", "Project Administrator"})
|
||||
.signWith(SignatureAlgorithm.RS256, keyPair.getPrivate())
|
||||
.compact();
|
||||
|
||||
MatcherAssert.assertThat(
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.post(url("JWT/jku/delete?token=" + token))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -245,6 +299,6 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||
params.put("question_0_solution", "Solution 1");
|
||||
params.put("question_1_solution", "Solution 2");
|
||||
|
||||
checkAssignment(url("/WebGoat/JWT/quiz"), params, true);
|
||||
checkAssignment(url("JWT/quiz"), params, true);
|
||||
}
|
||||
}
|
||||
|
@ -151,7 +151,6 @@ public class LabelAndHintIntegrationTest extends IntegrationTest {
|
||||
checkLang(propsDefault, "nl");
|
||||
checkLang(propsDefault, "de");
|
||||
checkLang(propsDefault, "fr");
|
||||
checkLang(propsDefault, "ru");
|
||||
}
|
||||
|
||||
private Properties getProperties(String lang) {
|
||||
|
@ -11,12 +11,13 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DynamicTest;
|
||||
import org.junit.jupiter.api.TestFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
||||
public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
||||
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
startLesson("/PasswordReset");
|
||||
startLesson("PasswordReset");
|
||||
}
|
||||
|
||||
@TestFactory
|
||||
@ -68,7 +69,6 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
||||
|
||||
// WebWolf
|
||||
var link = getPasswordResetLinkFromLandingPage();
|
||||
|
||||
// WebGoat
|
||||
changePassword(link);
|
||||
checkAssignment(
|
||||
@ -85,7 +85,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.get(webWolfUrl("/WebWolf/mail"))
|
||||
.get(new WebWolfUrlBuilder().path("mail").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -99,7 +99,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
||||
public void shutdown() {
|
||||
// this will run only once after the list of dynamic tests has run, this is to test if the
|
||||
// lesson is marked complete
|
||||
checkResults("/PasswordReset");
|
||||
checkResults("PasswordReset");
|
||||
}
|
||||
|
||||
private void changePassword(String link) {
|
||||
@ -119,7 +119,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.get(webWolfUrl("/WebWolf/requests"))
|
||||
.get(new WebWolfUrlBuilder().path("requests").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -136,7 +136,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
||||
private void clickForgotEmailLink(String user) {
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.header("host", String.format("%s:%s", "localhost", getWebWolfPort()))
|
||||
.header(HttpHeaders.HOST, String.format("%s:%s", getWebWolfHost(), getWebWolfPort()))
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.formParams("email", user)
|
||||
|
@ -55,7 +55,7 @@ class PathTraversalIT extends IntegrationTest {
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.multiPart("uploadedFile", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
||||
.param("fullName", "../John Doe")
|
||||
.post(url("/WebGoat/PathTraversal/profile-upload"))
|
||||
.post(url("PathTraversal/profile-upload"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -71,7 +71,7 @@ class PathTraversalIT extends IntegrationTest {
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.multiPart("uploadedFileFix", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
||||
.param("fullNameFix", "..././John Doe")
|
||||
.post(url("/WebGoat/PathTraversal/profile-upload-fix"))
|
||||
.post(url("PathTraversal/profile-upload-fix"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -89,7 +89,7 @@ class PathTraversalIT extends IntegrationTest {
|
||||
"uploadedFileRemoveUserInput",
|
||||
"../test.jpg",
|
||||
Files.readAllBytes(fileToUpload.toPath()))
|
||||
.post(url("/WebGoat/PathTraversal/profile-upload-remove-user-input"))
|
||||
.post(url("PathTraversal/profile-upload-remove-user-input"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -98,7 +98,7 @@ class PathTraversalIT extends IntegrationTest {
|
||||
}
|
||||
|
||||
private void assignment4() throws IOException {
|
||||
var uri = "/WebGoat/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret";
|
||||
var uri = "PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret";
|
||||
RestAssured.given()
|
||||
.urlEncodingEnabled(false)
|
||||
.when()
|
||||
@ -110,7 +110,7 @@ class PathTraversalIT extends IntegrationTest {
|
||||
.body(CoreMatchers.is("You found it submit the SHA-512 hash of your username as answer"));
|
||||
|
||||
checkAssignment(
|
||||
url("/WebGoat/PathTraversal/random"),
|
||||
url("PathTraversal/random"),
|
||||
Map.of("secret", Sha512DigestUtils.shaHex(this.getUser())),
|
||||
true);
|
||||
}
|
||||
@ -133,8 +133,10 @@ class PathTraversalIT extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.multiPart("uploadedFileZipSlip", "upload.zip", Files.readAllBytes(zipFile.toPath()))
|
||||
.post(url("/WebGoat/PathTraversal/zip-slip"))
|
||||
.post(url("PathTraversal/zip-slip"))
|
||||
.then()
|
||||
.log()
|
||||
.all()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
.path("lessonCompleted"),
|
||||
@ -145,6 +147,6 @@ class PathTraversalIT extends IntegrationTest {
|
||||
void shutdown() {
|
||||
// this will run only once after the list of dynamic tests has run, this is to test if the
|
||||
// lesson is marked complete
|
||||
checkResults("/PathTraversal");
|
||||
checkResults("PathTraversal");
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class ProgressRaceConditionIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.formParams(Map.of("flag", "test"))
|
||||
.post(url("/challenge/flag"));
|
||||
.post(url("challenge/flag/1"));
|
||||
};
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_PARALLEL_THREADS);
|
||||
List<? extends Callable<Response>> flagCalls =
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.owasp.webgoat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -8,19 +7,19 @@ import org.junit.jupiter.api.Test;
|
||||
public class SSRFIntegrationTest extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void runTests() throws IOException {
|
||||
public void runTests() {
|
||||
startLesson("SSRF");
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("url", "images/jerry.png");
|
||||
|
||||
checkAssignment(url("/WebGoat/SSRF/task1"), params, true);
|
||||
checkAssignment(url("SSRF/task1"), params, true);
|
||||
params.clear();
|
||||
params.put("url", "http://ifconfig.pro");
|
||||
|
||||
checkAssignment(url("/WebGoat/SSRF/task2"), params, true);
|
||||
checkAssignment(url("SSRF/task2"), params, true);
|
||||
|
||||
checkResults("/SSRF/");
|
||||
checkResults("SSRF");
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test;
|
||||
*/
|
||||
class SessionManagementIT extends IntegrationTest {
|
||||
|
||||
private static final String HIJACK_LOGIN_CONTEXT_PATH = "/WebGoat/HijackSession/login";
|
||||
private static final String HIJACK_LOGIN_CONTEXT_PATH = "HijackSession/login";
|
||||
|
||||
@Test
|
||||
void hijackSessionTest() {
|
||||
|
@ -16,27 +16,27 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
|
||||
params.put("password_reg", "password");
|
||||
params.put("email_reg", "someone@microsoft.com");
|
||||
params.put("confirm_password", "password");
|
||||
checkAssignmentWithPUT(url("/WebGoat/SqlInjectionAdvanced/challenge"), params, true);
|
||||
checkAssignmentWithPUT(url("SqlInjectionAdvanced/challenge"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("username_login", "tom");
|
||||
params.put("password_login", "thisisasecretfortomonly");
|
||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/challenge_Login"), params, true);
|
||||
checkAssignment(url("SqlInjectionAdvanced/challenge_Login"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
|
||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
|
||||
checkAssignment(url("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);
|
||||
checkAssignment(url("SqlInjectionAdvanced/attack6a"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("userid_6b", "passW0rD");
|
||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6b"), params, true);
|
||||
checkAssignment(url("SqlInjectionAdvanced/attack6b"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put(
|
||||
@ -54,8 +54,8 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
|
||||
params.put(
|
||||
"question_4_solution",
|
||||
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
|
||||
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/quiz"), params, true);
|
||||
checkAssignment(url("SqlInjectionAdvanced/quiz"), params, true);
|
||||
|
||||
checkResults("/SqlInjectionAdvanced/");
|
||||
checkResults("SqlInjectionAdvanced");
|
||||
}
|
||||
}
|
||||
|
@ -34,45 +34,45 @@ public class SqlInjectionLessonIntegrationTest extends IntegrationTest {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("query", sql_2);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/attack2"), params, true);
|
||||
checkAssignment(url("SqlInjection/attack2"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("query", sql_3);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/attack3"), params, true);
|
||||
checkAssignment(url("SqlInjection/attack3"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("query", sql_4_add);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/attack4"), params, true);
|
||||
checkAssignment(url("SqlInjection/attack4"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("query", sql_5);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/attack5"), params, true);
|
||||
checkAssignment(url("SqlInjection/attack5"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("operator", sql_9_operator);
|
||||
params.put("account", sql_9_account);
|
||||
params.put("injection", sql_9_injection);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/assignment5a"), params, true);
|
||||
checkAssignment(url("SqlInjection/assignment5a"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("login_count", sql_10_login_count);
|
||||
params.put("userid", sql_10_userid);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/assignment5b"), params, true);
|
||||
checkAssignment(url("SqlInjection/assignment5b"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("name", sql_11_a);
|
||||
params.put("auth_tan", sql_11_b);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/attack8"), params, true);
|
||||
checkAssignment(url("SqlInjection/attack8"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("name", sql_12_a);
|
||||
params.put("auth_tan", sql_12_b);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/attack9"), params, true);
|
||||
checkAssignment(url("SqlInjection/attack9"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("action_string", sql_13);
|
||||
checkAssignment(url("/WebGoat/SqlInjection/attack10"), params, true);
|
||||
checkAssignment(url("SqlInjection/attack10"), params, true);
|
||||
|
||||
checkResults("/SqlInjection/");
|
||||
checkResults("SqlInjection");
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
||||
params.put("field5", "?");
|
||||
params.put("field6", "prep.setString(1,\"\")");
|
||||
params.put("field7", "prep.setString(2,\\\"\\\")");
|
||||
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10a"), params, true);
|
||||
checkAssignment(url("SqlInjectionMitigations/attack10a"), params, true);
|
||||
|
||||
params.put(
|
||||
"editor",
|
||||
@ -37,18 +37,18 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
||||
+ "} catch (Exception e) {\r\n"
|
||||
+ " System.out.println(\"Oops. Something went wrong!\");\r\n"
|
||||
+ "}");
|
||||
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10b"), params, true);
|
||||
checkAssignment(url("SqlInjectionMitigations/attack10b"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put(
|
||||
"userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--");
|
||||
checkAssignment(url("/WebGoat/SqlOnlyInputValidation/attack"), params, true);
|
||||
checkAssignment(url("SqlOnlyInputValidation/attack"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put(
|
||||
"userid_sql_only_input_validation_on_keywords",
|
||||
"Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--");
|
||||
checkAssignment(url("/WebGoat/SqlOnlyInputValidationOnKeywords/attack"), params, true);
|
||||
checkAssignment(url("SqlOnlyInputValidationOnKeywords/attack"), params, true);
|
||||
|
||||
RestAssured.given()
|
||||
.when()
|
||||
@ -57,7 +57,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
||||
.contentType(ContentType.JSON)
|
||||
.get(
|
||||
url(
|
||||
"/WebGoat/SqlInjectionMitigations/servers?column=(case when (true) then hostname"
|
||||
"SqlInjectionMitigations/servers?column=(case when (true) then hostname"
|
||||
+ " else id end)"))
|
||||
.then()
|
||||
.statusCode(200);
|
||||
@ -67,7 +67,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.contentType(ContentType.JSON)
|
||||
.get(url("/WebGoat/SqlInjectionMitigations/servers?column=unknown"))
|
||||
.get(url("SqlInjectionMitigations/servers?column=unknown"))
|
||||
.then()
|
||||
.statusCode(500)
|
||||
.body(
|
||||
@ -78,8 +78,8 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
||||
|
||||
params.clear();
|
||||
params.put("ip", "104.130.219.202");
|
||||
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack12a"), params, true);
|
||||
checkAssignment(url("SqlInjectionMitigations/attack12a"), params, true);
|
||||
|
||||
checkResults();
|
||||
checkResults("SqlInjectionMitigations");
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package org.owasp.webgoat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.restassured.RestAssured;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@ -11,21 +10,20 @@ import org.junit.jupiter.api.Test;
|
||||
public class WebWolfIntegrationTest extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
public void runTests() throws IOException {
|
||||
public void runTests() {
|
||||
startLesson("WebWolfIntroduction");
|
||||
|
||||
// Assignment 3
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("email", this.getUser() + "@webgoat.org");
|
||||
checkAssignment(url("/WebGoat/WebWolf/mail/send"), params, false);
|
||||
checkAssignment(url("WebWolf/mail/send"), params, false);
|
||||
|
||||
String responseBody =
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.get(webWolfUrl("/WebWolf/mail"))
|
||||
.get(new WebWolfUrlBuilder().path("mail").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -39,7 +37,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
||||
uniqueCode.lastIndexOf("your unique code is: ") + (21 + this.getUser().length()));
|
||||
params.clear();
|
||||
params.put("uniqueCode", uniqueCode);
|
||||
checkAssignment(url("/WebGoat/WebWolf/mail"), params, true);
|
||||
checkAssignment(url("WebWolf/mail"), params, true);
|
||||
|
||||
// Assignment 4
|
||||
RestAssured.given()
|
||||
@ -47,7 +45,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.queryParams(params)
|
||||
.get(url("/WebGoat/WebWolf/landing/password-reset"))
|
||||
.get(url("WebWolf/landing/password-reset"))
|
||||
.then()
|
||||
.statusCode(200);
|
||||
RestAssured.given()
|
||||
@ -55,7 +53,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.queryParams(params)
|
||||
.get(webWolfUrl("/landing"))
|
||||
.get(new WebWolfUrlBuilder().path("landing").build())
|
||||
.then()
|
||||
.statusCode(200);
|
||||
responseBody =
|
||||
@ -63,7 +61,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.get(webWolfUrl("/WebWolf/requests"))
|
||||
.get(new WebWolfUrlBuilder().path("requests").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -72,8 +70,8 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
||||
assertTrue(responseBody.contains(uniqueCode));
|
||||
params.clear();
|
||||
params.put("uniqueCode", uniqueCode);
|
||||
checkAssignment(url("/WebGoat/WebWolf/landing"), params, true);
|
||||
checkAssignment(url("WebWolf/landing"), params, true);
|
||||
|
||||
checkResults("/WebWolf");
|
||||
checkResults("WebWolfIntroduction");
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.clear();
|
||||
params.put("checkboxAttack1", "value");
|
||||
checkAssignment(url("/CrossSiteScripting/attack1"), params, true);
|
||||
checkAssignment(url("CrossSiteScripting/attack1"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("QTY1", "1");
|
||||
@ -23,11 +23,11 @@ public class XSSIntegrationTest extends IntegrationTest {
|
||||
params.put("QTY4", "1");
|
||||
params.put("field1", "<script>alert('XSS+Test')</script>");
|
||||
params.put("field2", "111");
|
||||
checkAssignmentWithGet(url("/CrossSiteScripting/attack5a"), params, true);
|
||||
checkAssignmentWithGet(url("CrossSiteScripting/attack5a"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("DOMTestRoute", "start.mvc#test");
|
||||
checkAssignment(url("/CrossSiteScripting/attack6a"), params, true);
|
||||
checkAssignment(url("CrossSiteScripting/attack6a"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put("param1", "42");
|
||||
@ -41,7 +41,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
||||
.header("webgoat-requested-by", "dom-xss-vuln")
|
||||
.header("X-Requested-With", "XMLHttpRequest")
|
||||
.formParams(params)
|
||||
.post(url("/CrossSiteScripting/phone-home-xss"))
|
||||
.post(url("CrossSiteScripting/phone-home-xss"))
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.extract()
|
||||
@ -50,7 +50,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
||||
|
||||
params.clear();
|
||||
params.put("successMessage", secretNumber);
|
||||
checkAssignment(url("/CrossSiteScripting/dom-follow-up"), params, true);
|
||||
checkAssignment(url("CrossSiteScripting/dom-follow-up"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put(
|
||||
@ -73,8 +73,44 @@ public class XSSIntegrationTest extends IntegrationTest {
|
||||
"question_4_solution",
|
||||
"Solution 4: No there are many other ways. Like HTML, Flash or any other type of code that"
|
||||
+ " the browser executes.");
|
||||
checkAssignment(url("/CrossSiteScripting/quiz"), params, true);
|
||||
checkAssignment(url("CrossSiteScripting/quiz"), params, true);
|
||||
|
||||
checkResults("/CrossSiteScripting/");
|
||||
params.clear();
|
||||
params.put(
|
||||
"editor",
|
||||
"<%@ taglib uri=\"https://www.owasp.org/index.php/OWASP_Java_Encoder_Project\" %>"
|
||||
+ "<html>"
|
||||
+ "<head>"
|
||||
+ "<title>Using GET and POST Method to Read Form Data</title>"
|
||||
+ "</head>"
|
||||
+ "<body>"
|
||||
+ "<h1>Using POST Method to Read Form Data</h1>"
|
||||
+ "<table>"
|
||||
+ "<tbody>"
|
||||
+ "<tr>"
|
||||
+ "<td><b>First Name:</b></td>"
|
||||
+ "<td>${e:forHtml(param.first_name)}</td>"
|
||||
+ "</tr>"
|
||||
+ "<tr>"
|
||||
+ "<td><b>Last Name:</b></td>"
|
||||
+ "<td>${e:forHtml(param.last_name)}</td>"
|
||||
+ "</tr>"
|
||||
+ "</tbody>"
|
||||
+ "</table>"
|
||||
+ "</body>"
|
||||
+ "</html>");
|
||||
checkAssignment(url("CrossSiteScripting/attack3"), params, true);
|
||||
|
||||
params.clear();
|
||||
params.put(
|
||||
"editor2",
|
||||
"Policy.getInstance(\"antisamy-slashdot.xml\");"
|
||||
+ "Sammy s = new AntiSamy();"
|
||||
+ "s.scan(newComment,\"\");"
|
||||
+ "CleanResults();"
|
||||
+ "MyCommentDAO.addComment(threadID, userID).getCleanHTML());");
|
||||
checkAssignment(url("CrossSiteScripting/attack4"), params, true);
|
||||
|
||||
checkResults("CrossSiteScripting");
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,6 @@ package org.owasp.webgoat;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class XXEIntegrationTest extends IntegrationTest {
|
||||
@ -28,47 +25,40 @@ public class XXEIntegrationTest extends IntegrationTest {
|
||||
""";
|
||||
|
||||
private String webGoatHomeDirectory;
|
||||
private String webWolfFileServerLocation;
|
||||
|
||||
/*
|
||||
* This test is to verify that all is secure when XXE security patch is applied.
|
||||
*/
|
||||
@Test
|
||||
public void xxeSecure() throws IOException {
|
||||
startLesson("XXE");
|
||||
webGoatHomeDirectory = webGoatServerDirectory();
|
||||
webWolfFileServerLocation = getWebWolfFileServerLocation();
|
||||
RestAssured.given()
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("JSESSIONID", getWebGoatCookie())
|
||||
.get(url("service/enable-security.mvc"))
|
||||
.then()
|
||||
.statusCode(200);
|
||||
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, false);
|
||||
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, false);
|
||||
checkAssignment(
|
||||
url("/WebGoat/xxe/blind"),
|
||||
ContentType.XML,
|
||||
"<comment><text>" + getSecret() + "</text></comment>",
|
||||
false);
|
||||
}
|
||||
// TODO fix me
|
||||
// /*
|
||||
// * This test is to verify that all is secure when XXE security patch is applied.
|
||||
// */
|
||||
// @Test
|
||||
// public void xxeSecure() throws IOException {
|
||||
// startLesson("XXE");
|
||||
// webGoatHomeDirectory = webGoatServerDirectory();
|
||||
// RestAssured.given()
|
||||
// .when()
|
||||
// .relaxedHTTPSValidation()
|
||||
// .cookie("JSESSIONID", getWebGoatCookie())
|
||||
// .get(url("service/enable-security.mvc"))
|
||||
// .then()
|
||||
// .statusCode(200);
|
||||
// checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, false);
|
||||
// checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, false);
|
||||
// checkAssignment(
|
||||
// url("xxe/blind"),
|
||||
// ContentType.XML,
|
||||
// "<comment><text>" + getSecret() + "</text></comment>",
|
||||
// false);
|
||||
// }
|
||||
|
||||
/**
|
||||
* This performs the steps of the exercise before the secret can be committed in the final step.
|
||||
*
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private String getSecret() throws IOException {
|
||||
// remove any left over DTD
|
||||
Path webWolfFilePath = Paths.get(webWolfFileServerLocation);
|
||||
if (webWolfFilePath.resolve(Paths.get(this.getUser(), "blind.dtd")).toFile().exists()) {
|
||||
Files.delete(webWolfFilePath.resolve(Paths.get(this.getUser(), "blind.dtd")));
|
||||
}
|
||||
private String getSecret() {
|
||||
String secretFile = webGoatHomeDirectory.concat("/XXE/" + getUser() + "/secret.txt");
|
||||
String dtd7String =
|
||||
dtd7.replace("WEBWOLFURL", webWolfUrl("/landing")).replace("SECRET", secretFile);
|
||||
String webWolfCallback = new WebWolfUrlBuilder().path("landing").attackMode().build();
|
||||
String dtd7String = dtd7.replace("WEBWOLFURL", webWolfCallback).replace("SECRET", secretFile);
|
||||
|
||||
// upload DTD
|
||||
RestAssured.given()
|
||||
@ -76,16 +66,18 @@ public class XXEIntegrationTest extends IntegrationTest {
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.multiPart("file", "blind.dtd", dtd7String.getBytes())
|
||||
.post(webWolfUrl("/fileupload"))
|
||||
.post(new WebWolfUrlBuilder().path("fileupload").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
.getBody()
|
||||
.asString();
|
||||
|
||||
// upload attack
|
||||
String xxe7String =
|
||||
xxe7.replace("WEBWOLFURL", webWolfUrl("/files")).replace("USERNAME", this.getUser());
|
||||
checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, xxe7String, false);
|
||||
xxe7.replace("WEBWOLFURL", new WebWolfUrlBuilder().attackMode().path("files").build())
|
||||
.replace("USERNAME", this.getUser());
|
||||
checkAssignment(url("xxe/blind"), ContentType.XML, xxe7String, false);
|
||||
|
||||
// read results from WebWolf
|
||||
String result =
|
||||
@ -93,7 +85,7 @@ public class XXEIntegrationTest extends IntegrationTest {
|
||||
.when()
|
||||
.relaxedHTTPSValidation()
|
||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||
.get(webWolfUrl("/WebWolf/requests"))
|
||||
.get(new WebWolfUrlBuilder().path("requests").build())
|
||||
.then()
|
||||
.extract()
|
||||
.response()
|
||||
@ -113,14 +105,13 @@ public class XXEIntegrationTest extends IntegrationTest {
|
||||
public void runTests() throws IOException {
|
||||
startLesson("XXE", true);
|
||||
webGoatHomeDirectory = webGoatServerDirectory();
|
||||
webWolfFileServerLocation = getWebWolfFileServerLocation();
|
||||
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, true);
|
||||
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, true);
|
||||
checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, true);
|
||||
checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, true);
|
||||
checkAssignment(
|
||||
url("/WebGoat/xxe/blind"),
|
||||
url("xxe/blind"),
|
||||
ContentType.XML,
|
||||
"<comment><text>" + getSecret() + "</text></comment>",
|
||||
true);
|
||||
checkResults("xxe/");
|
||||
checkResults("XXE");
|
||||
}
|
||||
}
|
||||
|
@ -32,22 +32,23 @@ package org.owasp.webgoat.container;
|
||||
|
||||
import static org.asciidoctor.Asciidoctor.Factory.create;
|
||||
|
||||
import io.undertow.util.Headers;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.asciidoctor.Asciidoctor;
|
||||
import org.asciidoctor.Attributes;
|
||||
import org.asciidoctor.Options;
|
||||
import org.asciidoctor.extension.JavaExtensionRegistry;
|
||||
import org.owasp.webgoat.container.asciidoc.*;
|
||||
import org.owasp.webgoat.container.i18n.Language;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||
@ -135,17 +136,17 @@ public class AsciiDoctorTemplateResolver extends FileTemplateResolver {
|
||||
return computedResourceName;
|
||||
}
|
||||
|
||||
private Map<String, Object> createAttributes() {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
attributes.put("source-highlighter", "coderay");
|
||||
attributes.put("backend", "xhtml");
|
||||
attributes.put("lang", determineLanguage());
|
||||
attributes.put("icons", org.asciidoctor.Attributes.FONT_ICONS);
|
||||
private Options createAttributes() {
|
||||
|
||||
Map<String, Object> options = new HashMap<>();
|
||||
options.put("attributes", attributes);
|
||||
|
||||
return options;
|
||||
return Options.builder()
|
||||
.attributes(
|
||||
Attributes.builder()
|
||||
.attribute("source-highlighter", "coderay")
|
||||
.attribute("backend", "xhtml")
|
||||
.attribute("lang", determineLanguage())
|
||||
.attribute("icons", org.asciidoctor.Attributes.FONT_ICONS)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
private String determineLanguage() {
|
||||
@ -159,7 +160,7 @@ public class AsciiDoctorTemplateResolver extends FileTemplateResolver {
|
||||
log.debug("browser locale {}", browserLocale);
|
||||
return browserLocale.getLanguage();
|
||||
} else {
|
||||
String langHeader = request.getHeader(Headers.ACCEPT_LANGUAGE_STRING);
|
||||
String langHeader = request.getHeader(HttpHeaders.ACCEPT_LANGUAGE);
|
||||
if (null != langHeader) {
|
||||
log.debug("browser locale {}", langHeader);
|
||||
return langHeader.substring(0, 2);
|
||||
|
14
src/main/java/org/owasp/webgoat/container/CurrentUser.java
Normal file
14
src/main/java/org/owasp/webgoat/container/CurrentUser.java
Normal file
@ -0,0 +1,14 @@
|
||||
package org.owasp.webgoat.container;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
|
||||
@Target({ElementType.PARAMETER, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@AuthenticationPrincipal
|
||||
public @interface CurrentUser {}
|
@ -0,0 +1,14 @@
|
||||
package org.owasp.webgoat.container;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
|
||||
@Target({ElementType.PARAMETER, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@AuthenticationPrincipal(expression = "#this.getUsername()")
|
||||
public @interface CurrentUsername {}
|
@ -6,8 +6,8 @@ import javax.sql.DataSource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.owasp.webgoat.container.lessons.LessonScanner;
|
||||
import org.owasp.webgoat.container.service.RestartLessonService;
|
||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -20,7 +20,6 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
public class DatabaseConfiguration {
|
||||
|
||||
private final DataSourceProperties properties;
|
||||
private final LessonScanner lessonScanner;
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ -36,8 +35,8 @@ public class DatabaseConfiguration {
|
||||
/**
|
||||
* 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.
|
||||
* quite easily see {@link RestartLessonService#restartLesson(String, WebGoatUser)} for how we
|
||||
* clean the lesson related tables.
|
||||
*/
|
||||
@Bean(initMethod = "migrate")
|
||||
public Flyway flyWayContainer() {
|
||||
@ -62,7 +61,7 @@ public class DatabaseConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LessonDataSource lessonDataSource() {
|
||||
return new LessonDataSource(dataSource());
|
||||
public LessonDataSource lessonDataSource(DataSource dataSource) {
|
||||
return new LessonDataSource(dataSource);
|
||||
}
|
||||
}
|
||||
|
@ -242,6 +242,7 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(localeChangeInterceptor());
|
||||
registry.addInterceptor(new UserInterceptor());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -0,0 +1,53 @@
|
||||
package org.owasp.webgoat.container;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.owasp.webgoat.container.asciidoc.EnvironmentExposure;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
public class UserInterceptor implements HandlerInterceptor {
|
||||
|
||||
private Environment env = EnvironmentExposure.getEnv();
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
// Do nothing
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
Object handler,
|
||||
ModelAndView modelAndView)
|
||||
throws Exception {
|
||||
if (null != modelAndView) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (null != authentication) {
|
||||
modelAndView.getModel().put("username", authentication.getName());
|
||||
}
|
||||
if (null != env) {
|
||||
String githubClientId =
|
||||
env.getProperty("spring.security.oauth2.client.registration.github.client-id");
|
||||
if (null != githubClientId && !githubClientId.equals("dummy")) {
|
||||
modelAndView.getModel().put("oauth", Boolean.TRUE);
|
||||
}
|
||||
} else {
|
||||
modelAndView.getModel().put("oauth", Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
|
||||
throws Exception {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
@ -32,24 +32,34 @@
|
||||
package org.owasp.webgoat.container;
|
||||
|
||||
import java.io.File;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.session.LessonSession;
|
||||
import org.owasp.webgoat.container.users.UserRepository;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackages = {"org.owasp.webgoat.container", "org.owasp.webgoat.lessons"})
|
||||
@PropertySource("classpath:application-webgoat.properties")
|
||||
@EnableAutoConfiguration
|
||||
@EnableJpaRepositories(basePackages = {"org.owasp.webgoat.container"})
|
||||
@EntityScan(basePackages = "org.owasp.webgoat.container")
|
||||
public class WebGoat {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
public WebGoat(UserRepository userRepository) {
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@Bean(name = "pluginTargetDirectory")
|
||||
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
|
||||
return new File(webgoatHome);
|
||||
@ -57,14 +67,8 @@ public class WebGoat {
|
||||
|
||||
@Bean
|
||||
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public WebSession webSession() {
|
||||
return new WebSession();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public UserSessionData userSessionData() {
|
||||
return new UserSessionData("test", "data");
|
||||
public LessonSession userSessionData() {
|
||||
return new LessonSession();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -35,6 +35,7 @@ import org.owasp.webgoat.container.users.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
@ -54,32 +55,41 @@ public class WebSecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(
|
||||
auth ->
|
||||
auth.requestMatchers(
|
||||
"/css/**",
|
||||
"/images/**",
|
||||
"/js/**",
|
||||
"fonts/**",
|
||||
"/plugins/**",
|
||||
"/registration",
|
||||
"/register.mvc",
|
||||
"/actuator/**")
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated());
|
||||
http.formLogin()
|
||||
.loginPage("/login")
|
||||
.defaultSuccessUrl("/welcome.mvc", true)
|
||||
.usernameParameter("username")
|
||||
.passwordParameter("password")
|
||||
.permitAll();
|
||||
http.logout().deleteCookies("JSESSIONID").invalidateHttpSession(true);
|
||||
http.csrf().disable();
|
||||
|
||||
http.headers().cacheControl().disable();
|
||||
http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login"));
|
||||
return http.build();
|
||||
return http.authorizeHttpRequests(
|
||||
auth ->
|
||||
auth.requestMatchers(
|
||||
"/favicon.ico",
|
||||
"/css/**",
|
||||
"/images/**",
|
||||
"/js/**",
|
||||
"fonts/**",
|
||||
"/plugins/**",
|
||||
"/registration",
|
||||
"/register.mvc",
|
||||
"/actuator/**")
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated())
|
||||
.formLogin(
|
||||
login ->
|
||||
login
|
||||
.loginPage("/login")
|
||||
.defaultSuccessUrl("/welcome.mvc", true)
|
||||
.usernameParameter("username")
|
||||
.passwordParameter("password")
|
||||
.permitAll())
|
||||
.oauth2Login(
|
||||
oidc -> {
|
||||
oidc.defaultSuccessUrl("/login-oauth.mvc");
|
||||
oidc.loginPage("/login");
|
||||
})
|
||||
.logout(logout -> logout.deleteCookies("JSESSIONID").invalidateHttpSession(true))
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.headers(headers -> headers.disable())
|
||||
.exceptionHandling(
|
||||
handling ->
|
||||
handling.authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@ -88,6 +98,7 @@ public class WebSecurityConfig {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public UserDetailsService userDetailsServiceBean() {
|
||||
return userDetailsService;
|
||||
}
|
||||
@ -98,7 +109,6 @@ public class WebSecurityConfig {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Bean
|
||||
public NoOpPasswordEncoder passwordEncoder() {
|
||||
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
|
||||
|
@ -16,7 +16,7 @@ public class EnvironmentExposure implements ApplicationContextAware {
|
||||
private static ApplicationContext context;
|
||||
|
||||
public static Environment getEnv() {
|
||||
return context.getEnvironment();
|
||||
return null != context ? context.getEnvironment() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,8 @@
|
||||
package org.owasp.webgoat.container.asciidoc;
|
||||
|
||||
import java.util.Map;
|
||||
import org.asciidoctor.ast.ContentNode;
|
||||
import org.asciidoctor.ast.PhraseNode;
|
||||
import org.asciidoctor.ast.StructuralNode;
|
||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||
|
||||
public class OperatingSystemMacro extends InlineMacroProcessor {
|
||||
@ -15,7 +16,8 @@ public class OperatingSystemMacro extends InlineMacroProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
|
||||
public PhraseNode process(
|
||||
StructuralNode contentNode, String target, Map<String, Object> attributes) {
|
||||
var osName = System.getProperty("os.name");
|
||||
|
||||
// see
|
||||
|
@ -1,7 +1,8 @@
|
||||
package org.owasp.webgoat.container.asciidoc;
|
||||
|
||||
import java.util.Map;
|
||||
import org.asciidoctor.ast.ContentNode;
|
||||
import org.asciidoctor.ast.PhraseNode;
|
||||
import org.asciidoctor.ast.StructuralNode;
|
||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@ -17,7 +18,8 @@ public class UsernameMacro extends InlineMacroProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
|
||||
public PhraseNode process(
|
||||
StructuralNode contentNode, String target, Map<String, Object> attributes) {
|
||||
var auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
var username = "unknown";
|
||||
if (auth.getPrincipal() instanceof WebGoatUser webGoatUser) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
package org.owasp.webgoat.container.asciidoc;
|
||||
|
||||
import java.util.Map;
|
||||
import org.asciidoctor.ast.ContentNode;
|
||||
import org.asciidoctor.ast.PhraseNode;
|
||||
import org.asciidoctor.ast.StructuralNode;
|
||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||
|
||||
public class WebGoatTmpDirMacro extends InlineMacroProcessor {
|
||||
@ -15,11 +16,12 @@ public class WebGoatTmpDirMacro extends InlineMacroProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
|
||||
public PhraseNode process(
|
||||
StructuralNode structuralNode, String target, Map<String, Object> attributes) {
|
||||
var env = EnvironmentExposure.getEnv().getProperty("webgoat.server.directory");
|
||||
|
||||
// see
|
||||
// https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
|
||||
return createPhraseNode(contentNode, "quoted", env);
|
||||
return createPhraseNode(structuralNode, "quoted", env);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
package org.owasp.webgoat.container.asciidoc;
|
||||
|
||||
import java.util.Map;
|
||||
import org.asciidoctor.ast.ContentNode;
|
||||
import org.asciidoctor.ast.PhraseNode;
|
||||
import org.asciidoctor.ast.StructuralNode;
|
||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||
|
||||
public class WebGoatVersionMacro extends InlineMacroProcessor {
|
||||
@ -15,7 +16,8 @@ public class WebGoatVersionMacro extends InlineMacroProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
|
||||
public PhraseNode process(
|
||||
StructuralNode contentNode, String target, Map<String, Object> attributes) {
|
||||
var webgoatVersion = EnvironmentExposure.getEnv().getProperty("webgoat.build.version");
|
||||
|
||||
// see
|
||||
|
@ -1,12 +1,10 @@
|
||||
package org.owasp.webgoat.container.asciidoc;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.asciidoctor.ast.ContentNode;
|
||||
import org.asciidoctor.ast.PhraseNode;
|
||||
import org.asciidoctor.ast.StructuralNode;
|
||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* Usage in asciidoc:
|
||||
@ -24,9 +22,10 @@ public class WebWolfMacro extends InlineMacroProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object process(ContentNode contentNode, String linkText, Map<String, Object> attributes) {
|
||||
public PhraseNode process(
|
||||
StructuralNode contentNode, String linkText, Map<String, Object> attributes) {
|
||||
var env = EnvironmentExposure.getEnv();
|
||||
var hostname = determineHost(env.getProperty("webwolf.port"));
|
||||
var hostname = env.getProperty("webwolf.url");
|
||||
var target = (String) attributes.getOrDefault("target", "home");
|
||||
var href = hostname + "/" + target;
|
||||
|
||||
@ -39,35 +38,10 @@ public class WebWolfMacro extends InlineMacroProcessor {
|
||||
options.put("type", ":link");
|
||||
options.put("target", href);
|
||||
attributes.put("window", "_blank");
|
||||
return createPhraseNode(contentNode, "anchor", linkText, attributes, options).convert();
|
||||
return createPhraseNode(contentNode, "anchor", linkText, attributes, options);
|
||||
}
|
||||
|
||||
private boolean displayCompleteLinkNoFormatting(Map<String, Object> attributes) {
|
||||
return attributes.values().stream().anyMatch(a -> a.equals("noLink"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the host from the hostname and ports that were used. The purpose is to make it
|
||||
* possible to use the application behind a reverse proxy. For instance in the docker
|
||||
* compose/stack version with webgoat webwolf and nginx proxy. You do not have to use the
|
||||
* indicated hostname, but if you do, you should define two hosts aliases 127.0.0.1
|
||||
* www.webgoat.local www.webwolf.local
|
||||
*/
|
||||
private String determineHost(String port) {
|
||||
HttpServletRequest request =
|
||||
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
|
||||
String host = request.getHeader("Host");
|
||||
int semicolonIndex = host.indexOf(":");
|
||||
if (semicolonIndex == -1 || host.endsWith(":80")) {
|
||||
host = host.replace(":80", "").replace("www.webgoat.local", "www.webwolf.local");
|
||||
} else {
|
||||
host = host.substring(0, semicolonIndex);
|
||||
host = host.concat(":").concat(port);
|
||||
}
|
||||
return "http://" + host + (includeWebWolfContext() ? "/WebWolf" : "");
|
||||
}
|
||||
|
||||
protected boolean includeWebWolfContext() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,4 @@ public class WebWolfRootMacro extends WebWolfMacro {
|
||||
public WebWolfRootMacro(String macroName, Map<String, Object> config) {
|
||||
super(macroName, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean includeWebWolfContext() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -25,27 +25,13 @@
|
||||
|
||||
package org.owasp.webgoat.container.assignments;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.container.lessons.Initializeable;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
public abstract class AssignmentEndpoint implements Initializeable {
|
||||
public abstract class AssignmentEndpoint {
|
||||
|
||||
@Autowired private WebSession webSession;
|
||||
@Autowired private UserSessionData userSessionData;
|
||||
@Getter @Autowired private PluginMessages messages;
|
||||
|
||||
protected WebSession getWebSession() {
|
||||
return webSession;
|
||||
}
|
||||
|
||||
protected UserSessionData getUserSessionData() {
|
||||
return userSessionData;
|
||||
}
|
||||
// TODO: move this to different bean.
|
||||
@Autowired private PluginMessages messages;
|
||||
|
||||
/**
|
||||
* Convenience method for create a successful result:
|
||||
@ -86,7 +72,4 @@ public abstract class AssignmentEndpoint implements Initializeable {
|
||||
protected AttackResult.AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
|
||||
return AttackResult.builder(messages).lessonCompleted(false).assignment(assignment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(WebGoatUser user) {}
|
||||
}
|
||||
|
@ -22,27 +22,30 @@
|
||||
|
||||
package org.owasp.webgoat.container.assignments;
|
||||
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.users.UserTracker;
|
||||
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.owasp.webgoat.container.users.UserProgress;
|
||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> {
|
||||
|
||||
private UserTrackerRepository userTrackerRepository;
|
||||
private WebSession webSession;
|
||||
private final Course course;
|
||||
private final UserProgressRepository userProgressRepository;
|
||||
|
||||
public LessonTrackerInterceptor(
|
||||
UserTrackerRepository userTrackerRepository, WebSession webSession) {
|
||||
this.userTrackerRepository = userTrackerRepository;
|
||||
this.webSession = webSession;
|
||||
public LessonTrackerInterceptor(Course course, UserProgressRepository userProgressRepository) {
|
||||
this.course = course;
|
||||
this.userProgressRepository = userProgressRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,18 +68,30 @@ public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> {
|
||||
return o;
|
||||
}
|
||||
|
||||
protected AttackResult trackProgress(AttackResult attackResult) {
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
if (userTracker == null) {
|
||||
userTracker = new UserTracker(webSession.getUserName());
|
||||
}
|
||||
if (attackResult.assignmentSolved()) {
|
||||
userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment());
|
||||
} else {
|
||||
userTracker.assignmentFailed(webSession.getCurrentLesson());
|
||||
}
|
||||
userTrackerRepository.save(userTracker);
|
||||
private void trackProgress(AttackResult attackResult) {
|
||||
var user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
Assert.notNull(user, "User not found in SecurityContext");
|
||||
var username = realUsername(user);
|
||||
|
||||
return attackResult;
|
||||
var userProgress = userProgressRepository.findByUser(username);
|
||||
if (userProgress == null) {
|
||||
userProgress = new UserProgress(username);
|
||||
}
|
||||
Lesson lesson = course.getLessonByAssignment(attackResult.getAssignment());
|
||||
Assert.notNull(lesson, "Lesson not found for assignment " + attackResult.getAssignment());
|
||||
|
||||
if (attackResult.assignmentSolved()) {
|
||||
userProgress.assignmentSolved(lesson, attackResult.getAssignment());
|
||||
} else {
|
||||
userProgress.assignmentFailed(lesson);
|
||||
}
|
||||
userProgressRepository.save(userProgress);
|
||||
}
|
||||
|
||||
private String realUsername(WebGoatUser user) {
|
||||
// maybe we shouldn't hard code this with just csrf- prefix for now it works
|
||||
return user.getUsername().startsWith("csrf-")
|
||||
? user.getUsername().substring("csrf-".length())
|
||||
: user.getUsername();
|
||||
}
|
||||
}
|
||||
|
@ -33,42 +33,20 @@ package org.owasp.webgoat.container.controller;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@Controller
|
||||
public class StartLesson {
|
||||
|
||||
private final WebSession ws;
|
||||
private final Course course;
|
||||
|
||||
public StartLesson(WebSession ws, Course course) {
|
||||
this.ws = ws;
|
||||
public StartLesson(Course course) {
|
||||
this.course = course;
|
||||
}
|
||||
|
||||
/**
|
||||
* start.
|
||||
*
|
||||
* @return a {@link ModelAndView} object.
|
||||
*/
|
||||
@RequestMapping(
|
||||
path = "startlesson.mvc",
|
||||
method = {RequestMethod.GET, RequestMethod.POST})
|
||||
public ModelAndView start() {
|
||||
var model = new ModelAndView();
|
||||
|
||||
model.addObject("course", course);
|
||||
model.addObject("lesson", ws.getCurrentLesson());
|
||||
model.setViewName("lesson_content");
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
@GetMapping(
|
||||
value = {"*.lesson"},
|
||||
produces = "text/html")
|
||||
public ModelAndView lessonPage(HttpServletRequest request) {
|
||||
@ -81,8 +59,7 @@ public class StartLesson {
|
||||
.findFirst()
|
||||
.ifPresent(
|
||||
lesson -> {
|
||||
ws.setCurrentLesson(lesson);
|
||||
model.addObject("lesson", lesson);
|
||||
request.setAttribute("lesson", lesson);
|
||||
});
|
||||
|
||||
return model;
|
||||
|
@ -51,10 +51,11 @@ public class Assignment {
|
||||
|
||||
private String name;
|
||||
private String path;
|
||||
private boolean solved = false;
|
||||
|
||||
@Transient private List<String> hints;
|
||||
|
||||
private Assignment() {
|
||||
protected Assignment() {
|
||||
// Hibernate
|
||||
}
|
||||
|
||||
@ -74,4 +75,8 @@ public class Assignment {
|
||||
this.path = path;
|
||||
this.hints = hints;
|
||||
}
|
||||
|
||||
public void solved() {
|
||||
this.solved = true;
|
||||
}
|
||||
}
|
||||
|
@ -34,30 +34,28 @@ import lombok.Getter;
|
||||
* @since October 28, 2003
|
||||
*/
|
||||
public enum Category {
|
||||
INTRODUCTION("Introduction", 5),
|
||||
GENERAL("General", 100),
|
||||
INTRODUCTION("Introduction"),
|
||||
GENERAL("General"),
|
||||
|
||||
A1("(A1) Broken Access Control", 301),
|
||||
A2("(A2) Cryptographic Failures", 302),
|
||||
A3("(A3) Injection", 303),
|
||||
A1("(A1) Broken Access Control"),
|
||||
A2("(A2) Cryptographic Failures"),
|
||||
A3("(A3) Injection"),
|
||||
|
||||
A5("(A5) Security Misconfiguration", 305),
|
||||
A6("(A6) Vuln & Outdated Components", 306),
|
||||
A7("(A7) Identity & Auth Failure", 307),
|
||||
A8("(A8) Software & Data Integrity", 308),
|
||||
A9("(A9) Security Logging Failures", 309),
|
||||
A10("(A10) Server-side Request Forgery", 310),
|
||||
A5("(A5) Security Misconfiguration"),
|
||||
A6("(A6) Vuln & Outdated Components"),
|
||||
A7("(A7) Identity & Auth Failure"),
|
||||
A8("(A8) Software & Data Integrity"),
|
||||
A9("(A9) Security Logging Failures"),
|
||||
A10("(A10) Server-side Request Forgery"),
|
||||
|
||||
CLIENT_SIDE("Client side", 1700),
|
||||
CLIENT_SIDE("Client side"),
|
||||
|
||||
CHALLENGE("Challenges", 3000);
|
||||
CHALLENGE("Challenges");
|
||||
|
||||
@Getter private String name;
|
||||
@Getter private Integer ranking;
|
||||
|
||||
Category(String name, Integer ranking) {
|
||||
Category(String name) {
|
||||
this.name = name;
|
||||
this.ranking = ranking;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,12 +22,9 @@
|
||||
|
||||
package org.owasp.webgoat.container.lessons;
|
||||
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
@ -35,45 +32,91 @@ import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
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;
|
||||
|
||||
@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()));
|
||||
}
|
||||
|
||||
private void attachToLessonInParentPackage(
|
||||
AssignmentEndpoint assignmentEndpoint, String packageName) {
|
||||
if (packageName.equals("org.owasp.webgoat.lessons")) {
|
||||
throw new IllegalStateException(
|
||||
"No lesson found for assignment: '%s'"
|
||||
.formatted(assignmentEndpoint.getClass().getSimpleName()));
|
||||
}
|
||||
lessons.stream()
|
||||
.filter(l -> l.getClass().getPackageName().equals(packageName))
|
||||
.findFirst()
|
||||
.ifPresentOrElse(
|
||||
l -> l.addAssignment(toAssignment(assignmentEndpoint)),
|
||||
() ->
|
||||
attachToLessonInParentPackage(
|
||||
assignmentEndpoint, packageName.substring(0, packageName.lastIndexOf("."))));
|
||||
}
|
||||
|
||||
/**
|
||||
* For each assignment endpoint, find the lesson in the same package or if not found, find the
|
||||
* lesson in the parent package
|
||||
*/
|
||||
private void attachToLesson(AssignmentEndpoint assignmentEndpoint) {
|
||||
lessons.stream()
|
||||
.filter(
|
||||
l ->
|
||||
l.getClass()
|
||||
.getPackageName()
|
||||
.equals(assignmentEndpoint.getClass().getPackageName()))
|
||||
.findFirst()
|
||||
.ifPresentOrElse(
|
||||
l -> l.addAssignment(toAssignment(assignmentEndpoint)),
|
||||
() -> {
|
||||
var assignmentPackageName = assignmentEndpoint.getClass().getPackageName();
|
||||
attachToLessonInParentPackage(
|
||||
assignmentEndpoint,
|
||||
assignmentPackageName.substring(0, assignmentPackageName.lastIndexOf(".")));
|
||||
});
|
||||
}
|
||||
|
||||
private Assignment toAssignment(AssignmentEndpoint endpoint) {
|
||||
return new Assignment(
|
||||
endpoint.getClass().getSimpleName(),
|
||||
getPath(endpoint.getClass()),
|
||||
getHints(endpoint.getClass()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Course course() {
|
||||
lessons.stream().forEach(l -> l.setAssignments(createAssignment(l)));
|
||||
assignments.stream().forEach(this::attachToLesson);
|
||||
|
||||
// Check if all assignments are attached to a lesson
|
||||
var assignmentsAttachedToLessons =
|
||||
lessons.stream().mapToInt(l -> l.getAssignments().size()).sum();
|
||||
Assert.isTrue(
|
||||
assignmentsAttachedToLessons == assignments.size(),
|
||||
"Not all assignments are attached to a lesson, please check the configuration. The"
|
||||
+ " following assignments are not attached to any lesson: "
|
||||
+ findDiff());
|
||||
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())))
|
||||
.toList();
|
||||
private List<String> findDiff() {
|
||||
var matchedToLessons =
|
||||
lessons.stream().flatMap(l -> l.getAssignments().stream()).map(a -> a.getName()).toList();
|
||||
var allAssignments = assignments.stream().map(a -> a.getClass().getSimpleName()).toList();
|
||||
|
||||
var diff = new ArrayList<>(allAssignments);
|
||||
diff.removeAll(matchedToLessons);
|
||||
return diff;
|
||||
}
|
||||
|
||||
private String getPath(Class<? extends AssignmentEndpoint> e) {
|
||||
|
@ -6,7 +6,7 @@ import org.owasp.webgoat.container.users.WebGoatUser;
|
||||
* Interface for initialization of a lesson. It is called when a new user is added to WebGoat and
|
||||
* when a users reset a lesson. Make sure to clean beforehand and then re-initialize the lesson.
|
||||
*/
|
||||
public interface Initializeable {
|
||||
public interface Initializable {
|
||||
|
||||
void initialize(WebGoatUser webGoatUser);
|
||||
default void initialize(WebGoatUser webGoatUser) {}
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
|
||||
package org.owasp.webgoat.container.lessons;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -30,13 +31,10 @@ import lombok.Setter;
|
||||
@Setter
|
||||
public abstract class Lesson {
|
||||
|
||||
private static int count = 1;
|
||||
private Integer id = null;
|
||||
private List<Assignment> assignments;
|
||||
private List<Assignment> assignments = new ArrayList<>();
|
||||
|
||||
/** Constructor for the Lesson object */
|
||||
protected Lesson() {
|
||||
id = ++count;
|
||||
public void addAssignment(Assignment assignment) {
|
||||
this.assignments.add(assignment);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,9 +42,9 @@ public abstract class Lesson {
|
||||
*
|
||||
* @return a {@link java.lang.String} object.
|
||||
*/
|
||||
public String getName() {
|
||||
public LessonName getName() {
|
||||
String className = getClass().getName();
|
||||
return className.substring(className.lastIndexOf('.') + 1);
|
||||
return new LessonName(className.substring(className.lastIndexOf('.') + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,6 +114,10 @@ public abstract class Lesson {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used in Thymeleaf to construct the HTML to load the lesson content from. See
|
||||
* lesson_content.html
|
||||
*/
|
||||
public final String getPackage() {
|
||||
var packageName = this.getClass().getPackageName();
|
||||
// package name is the direct package name below lessons (any subpackage will be removed)
|
||||
|
@ -0,0 +1,21 @@
|
||||
package org.owasp.webgoat.container.lessons;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Wrapper class for the name of a lesson. This class is used to ensure that the lesson name is not
|
||||
* null and does not contain the ".lesson" suffix. The front-end passes the lesson name as a string
|
||||
* to the back-end, which then creates a new LessonName object with the lesson name as a parameter.
|
||||
* The constructor of the LessonName class checks if the lesson name is null and removes the
|
||||
* ".lesson" suffix if it is present.
|
||||
*
|
||||
* @param lessonName
|
||||
*/
|
||||
public record LessonName(String lessonName) {
|
||||
public LessonName {
|
||||
Assert.notNull(lessonName, "Lesson name cannot be null");
|
||||
if (lessonName.contains(".lesson")) {
|
||||
lessonName = lessonName.substring(0, lessonName.indexOf(".lesson"));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package org.owasp.webgoat.container.report;
|
||||
|
||||
record LessonStatistics(String name, boolean solved, int numberOfAttempts) {}
|
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
*
|
||||
* <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 - 2014 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.container.report;
|
||||
|
||||
import java.util.List;
|
||||
import org.owasp.webgoat.container.CurrentUsername;
|
||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class ReportCardController {
|
||||
|
||||
private final UserProgressRepository userProgressRepository;
|
||||
private final Course course;
|
||||
private final PluginMessages pluginMessages;
|
||||
|
||||
public ReportCardController(
|
||||
UserProgressRepository userProgressRepository, Course course, PluginMessages pluginMessages) {
|
||||
this.userProgressRepository = userProgressRepository;
|
||||
this.course = course;
|
||||
this.pluginMessages = pluginMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint which generates the report card for the current use to show the stats on the solved
|
||||
* lessons
|
||||
*/
|
||||
@GetMapping(path = "/service/reportcard.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public ReportCard reportCard(@CurrentUsername String username) {
|
||||
var userProgress = userProgressRepository.findByUser(username);
|
||||
var lessonStatistics =
|
||||
course.getLessons().stream()
|
||||
.map(
|
||||
lesson -> {
|
||||
var lessonTracker = userProgress.getLessonProgress(lesson);
|
||||
return new LessonStatistics(
|
||||
pluginMessages.getMessage(lesson.getTitle()),
|
||||
lessonTracker.isLessonSolved(),
|
||||
lessonTracker.getNumberOfAttempts());
|
||||
})
|
||||
.toList();
|
||||
return new ReportCard(
|
||||
course.getTotalOfLessons(),
|
||||
course.getTotalOfAssignments(),
|
||||
userProgress.numberOfAssignmentsSolved(),
|
||||
userProgress.numberOfLessonsSolved(),
|
||||
lessonStatistics);
|
||||
}
|
||||
|
||||
private record ReportCard(
|
||||
int totalNumberOfLessons,
|
||||
int totalNumberOfAssignments,
|
||||
long numberOfAssignmentsSolved,
|
||||
long numberOfLessonsSolved,
|
||||
List<LessonStatistics> lessonStatistics) {}
|
||||
|
||||
private record LessonStatistics(String name, boolean solved, int numberOfAttempts) {}
|
||||
}
|
@ -10,26 +10,24 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.owasp.webgoat.container.lessons.Assignment;
|
||||
import org.owasp.webgoat.container.lessons.Hint;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* HintService class.
|
||||
*
|
||||
* @author rlawson
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@RestController
|
||||
public class HintService {
|
||||
|
||||
public static final String URL_HINTS_MVC = "/service/hint.mvc";
|
||||
private final WebSession webSession;
|
||||
private final List<Hint> allHints;
|
||||
|
||||
public HintService(WebSession webSession) {
|
||||
this.webSession = webSession;
|
||||
public HintService(Course course) {
|
||||
this.allHints =
|
||||
course.getLessons().stream()
|
||||
.flatMap(lesson -> lesson.getAssignments().stream())
|
||||
.map(this::createHint)
|
||||
.flatMap(Collection::stream)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -40,15 +38,7 @@ public class HintService {
|
||||
@GetMapping(path = URL_HINTS_MVC, produces = "application/json")
|
||||
@ResponseBody
|
||||
public List<Hint> getHints() {
|
||||
Lesson l = webSession.getCurrentLesson();
|
||||
return createAssignmentHints(l);
|
||||
}
|
||||
|
||||
private List<Hint> createAssignmentHints(Lesson l) {
|
||||
if (l != null) {
|
||||
return l.getAssignments().stream().map(this::createHint).flatMap(Collection::stream).toList();
|
||||
}
|
||||
return List.of();
|
||||
return allHints;
|
||||
}
|
||||
|
||||
private List<Hint> createHint(Assignment a) {
|
||||
|
@ -1,33 +1,24 @@
|
||||
package org.owasp.webgoat.container.service;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.owasp.webgoat.container.lessons.LessonInfoModel;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.owasp.webgoat.container.lessons.LessonName;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* LessonInfoService class.
|
||||
*
|
||||
* @author dm
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
public class LessonInfoService {
|
||||
|
||||
private final WebSession webSession;
|
||||
private final Course course;
|
||||
|
||||
/**
|
||||
* getLessonInfo.
|
||||
*
|
||||
* @return a {@link LessonInfoModel} object.
|
||||
*/
|
||||
@RequestMapping(path = "/service/lessoninfo.mvc", produces = "application/json")
|
||||
public @ResponseBody LessonInfoModel getLessonInfo() {
|
||||
Lesson lesson = webSession.getCurrentLesson();
|
||||
@GetMapping(path = "/service/lessoninfo.mvc/{lesson}")
|
||||
public @ResponseBody LessonInfoModel getLessonInfo(
|
||||
@PathVariable("lesson") LessonName lessonName) {
|
||||
var lesson = course.getLessonByName(lessonName);
|
||||
return new LessonInfoModel(lesson.getTitle(), false, false, false);
|
||||
}
|
||||
}
|
||||
|
@ -32,16 +32,16 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webgoat.container.CurrentUsername;
|
||||
import org.owasp.webgoat.container.lessons.Assignment;
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.owasp.webgoat.container.lessons.LessonMenuItem;
|
||||
import org.owasp.webgoat.container.lessons.LessonMenuItemType;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.users.LessonTracker;
|
||||
import org.owasp.webgoat.container.users.UserTracker;
|
||||
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||
import org.owasp.webgoat.container.users.LessonProgress;
|
||||
import org.owasp.webgoat.container.users.UserProgress;
|
||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -59,8 +59,7 @@ public class LessonMenuService {
|
||||
|
||||
public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc";
|
||||
private final Course course;
|
||||
private final WebSession webSession;
|
||||
private UserTrackerRepository userTrackerRepository;
|
||||
private UserProgressRepository userTrackerRepository;
|
||||
|
||||
@Value("#{'${exclude.categories}'.split(',')}")
|
||||
private List<String> excludeCategories;
|
||||
@ -74,10 +73,13 @@ public class LessonMenuService {
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
@RequestMapping(path = URL_LESSONMENU_MVC, produces = "application/json")
|
||||
public @ResponseBody List<LessonMenuItem> showLeftNav() {
|
||||
public @ResponseBody List<LessonMenuItem> showLeftNav(@CurrentUsername String username) {
|
||||
// TODO: this looks way too complicated. Either we save it incorrectly or we miss something to
|
||||
// easily find out
|
||||
// if a lesson if solved or not.
|
||||
List<LessonMenuItem> menu = new ArrayList<>();
|
||||
List<Category> categories = course.getCategories();
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
UserProgress userTracker = userTrackerRepository.findByUser(username);
|
||||
|
||||
for (Category category : categories) {
|
||||
if (excludeCategories.contains(category.name())) {
|
||||
@ -97,12 +99,12 @@ public class LessonMenuService {
|
||||
lessonItem.setName(lesson.getTitle());
|
||||
lessonItem.setLink(lesson.getLink());
|
||||
lessonItem.setType(LessonMenuItemType.LESSON);
|
||||
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
|
||||
LessonProgress lessonTracker = userTracker.getLessonProgress(lesson);
|
||||
boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson);
|
||||
lessonItem.setComplete(lessonSolved);
|
||||
categoryItem.addChild(lessonItem);
|
||||
}
|
||||
categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking());
|
||||
categoryItem.getChildren().sort(Comparator.comparingInt(LessonMenuItem::getRanking));
|
||||
menu.add(categoryItem);
|
||||
}
|
||||
return menu;
|
||||
|
@ -4,11 +4,15 @@ import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.owasp.webgoat.container.CurrentUsername;
|
||||
import org.owasp.webgoat.container.lessons.Assignment;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||
import org.owasp.webgoat.container.lessons.LessonName;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
@ -20,8 +24,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@RequiredArgsConstructor
|
||||
public class LessonProgressService {
|
||||
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
private final WebSession webSession;
|
||||
private final UserProgressRepository userProgressRepository;
|
||||
private final Course course;
|
||||
|
||||
/**
|
||||
* Endpoint for fetching the complete lesson overview which informs the user about whether all the
|
||||
@ -29,19 +33,19 @@ public class LessonProgressService {
|
||||
*
|
||||
* @return list of assignments
|
||||
*/
|
||||
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
|
||||
@GetMapping(value = "/service/lessonoverview.mvc/{lesson}")
|
||||
@ResponseBody
|
||||
public List<LessonOverview> lessonOverview() {
|
||||
var userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
var currentLesson = webSession.getCurrentLesson();
|
||||
public List<LessonOverview> lessonOverview(
|
||||
@PathVariable("lesson") LessonName lessonName, @CurrentUsername String username) {
|
||||
var userProgress = userProgressRepository.findByUser(username);
|
||||
var lesson = course.getLessonByName(lessonName);
|
||||
|
||||
if (currentLesson != null) {
|
||||
var lessonTracker = userTracker.getLessonTracker(currentLesson);
|
||||
return lessonTracker.getLessonOverview().entrySet().stream()
|
||||
.map(entry -> new LessonOverview(entry.getKey(), entry.getValue()))
|
||||
.toList();
|
||||
}
|
||||
return List.of();
|
||||
Assert.isTrue(lesson != null, "Lesson not found: " + lessonName);
|
||||
|
||||
var lessonProgress = userProgress.getLessonProgress(lesson);
|
||||
return lessonProgress.getLessonOverview().entrySet().stream()
|
||||
.map(entry -> new LessonOverview(entry.getKey(), entry.getValue()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
|
@ -1,34 +0,0 @@
|
||||
package org.owasp.webgoat.container.service;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* LessonTitleService class.
|
||||
*
|
||||
* @author dm
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@Controller
|
||||
public class LessonTitleService {
|
||||
|
||||
private final WebSession webSession;
|
||||
|
||||
public LessonTitleService(final WebSession webSession) {
|
||||
this.webSession = webSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title for the current attack
|
||||
*
|
||||
* @return a {@link java.lang.String} object.
|
||||
*/
|
||||
@RequestMapping(path = "/service/lessontitle.mvc", produces = "application/html")
|
||||
public @ResponseBody String showPlan() {
|
||||
Lesson lesson = webSession.getCurrentLesson();
|
||||
return lesson != null ? lesson.getTitle() : "";
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
*
|
||||
* <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 - 2014 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.container.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.users.LessonTracker;
|
||||
import org.owasp.webgoat.container.users.UserTracker;
|
||||
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
/**
|
||||
* ReportCardService
|
||||
*
|
||||
* @author nbaars
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@Controller
|
||||
@AllArgsConstructor
|
||||
public class ReportCardService {
|
||||
|
||||
private final WebSession webSession;
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
private final Course course;
|
||||
private final PluginMessages pluginMessages;
|
||||
|
||||
/**
|
||||
* Endpoint which generates the report card for the current use to show the stats on the solved
|
||||
* lessons
|
||||
*/
|
||||
@GetMapping(path = "/service/reportcard.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public ReportCard reportCard() {
|
||||
final 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 (Lesson lesson : course.getLessons()) {
|
||||
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
|
||||
final LessonStatistics lessonStatistics = new LessonStatistics();
|
||||
lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle()));
|
||||
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
|
||||
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
|
||||
reportCard.lessonStatistics.add(lessonStatistics);
|
||||
}
|
||||
return reportCard;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private final class ReportCard {
|
||||
|
||||
private int totalNumberOfLessons;
|
||||
private int totalNumberOfAssignments;
|
||||
private int solvedLessons;
|
||||
private int numberOfAssignmentsSolved;
|
||||
private int numberOfLessonsSolved;
|
||||
private List<LessonStatistics> lessonStatistics = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
private final class LessonStatistics {
|
||||
private String name;
|
||||
private boolean solved;
|
||||
private int numberOfAttempts;
|
||||
}
|
||||
}
|
@ -29,14 +29,17 @@ import java.util.function.Function;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.owasp.webgoat.container.lessons.Initializeable;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.users.UserTracker;
|
||||
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||
import org.owasp.webgoat.container.CurrentUser;
|
||||
import org.owasp.webgoat.container.lessons.Initializable;
|
||||
import org.owasp.webgoat.container.lessons.LessonName;
|
||||
import org.owasp.webgoat.container.session.Course;
|
||||
import org.owasp.webgoat.container.users.UserProgress;
|
||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@Controller
|
||||
@ -44,25 +47,25 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
@Slf4j
|
||||
public class RestartLessonService {
|
||||
|
||||
private final WebSession webSession;
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
private final Course course;
|
||||
private final UserProgressRepository userTrackerRepository;
|
||||
private final Function<String, Flyway> flywayLessons;
|
||||
private final List<Initializeable> lessonsToInitialize;
|
||||
private final List<Initializable> lessonsToInitialize;
|
||||
|
||||
@RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text")
|
||||
@GetMapping(path = "/service/restartlesson.mvc/{lesson}")
|
||||
@ResponseStatus(value = HttpStatus.OK)
|
||||
public void restartLesson() {
|
||||
Lesson al = webSession.getCurrentLesson();
|
||||
log.debug("Restarting lesson: " + al);
|
||||
public void restartLesson(
|
||||
@PathVariable("lesson") LessonName lessonName, @CurrentUser WebGoatUser user) {
|
||||
var lesson = course.getLessonByName(lessonName);
|
||||
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||
userTracker.reset(al);
|
||||
UserProgress userTracker = userTrackerRepository.findByUser(user.getUsername());
|
||||
userTracker.reset(lesson);
|
||||
userTrackerRepository.save(userTracker);
|
||||
|
||||
var flyway = flywayLessons.apply(webSession.getUserName());
|
||||
var flyway = flywayLessons.apply(user.getUsername());
|
||||
flyway.clean();
|
||||
flyway.migrate();
|
||||
|
||||
lessonsToInitialize.forEach(i -> i.initialize(webSession.getUser()));
|
||||
lessonsToInitialize.forEach(i -> i.initialize(user));
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,9 @@
|
||||
package org.owasp.webgoat.container.service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.owasp.webgoat.container.CurrentUser;
|
||||
import org.owasp.webgoat.container.i18n.Messages;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -17,17 +18,17 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@RequiredArgsConstructor
|
||||
public class SessionService {
|
||||
|
||||
private final WebSession webSession;
|
||||
private final RestartLessonService restartLessonService;
|
||||
private final Messages messages;
|
||||
|
||||
@RequestMapping(path = "/service/enable-security.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public String applySecurity() {
|
||||
webSession.toggleSecurity();
|
||||
restartLessonService.restartLesson();
|
||||
public String applySecurity(@CurrentUser WebGoatUser user) {
|
||||
// webSession.toggleSecurity();
|
||||
// restartLessonService.restartLesson(user);
|
||||
|
||||
var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled";
|
||||
return messages.getMessage(msg);
|
||||
// TODO disabled for now
|
||||
// var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled";
|
||||
return messages.getMessage("Not working...");
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.owasp.webgoat.container.lessons.LessonName;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
@ -96,4 +97,21 @@ public class Course {
|
||||
return this.lessons.stream()
|
||||
.reduce(0, (total, lesson) -> lesson.getAssignments().size() + total, Integer::sum);
|
||||
}
|
||||
|
||||
public Lesson getLessonByName(LessonName lessonName) {
|
||||
return lessons.stream()
|
||||
.filter(lesson -> lesson.getName().equals(lessonName))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public Lesson getLessonByAssignment(String assignmentName) {
|
||||
return lessons.stream()
|
||||
.filter(
|
||||
lesson ->
|
||||
lesson.getAssignments().stream()
|
||||
.anyMatch(assignment -> assignment.getName().equals(assignmentName)))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
package org.owasp.webgoat.container.session;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class is responsible for managing user session data within a lesson. It uses a HashMap to
|
||||
* store key-value pairs representing session data.
|
||||
*/
|
||||
public class LessonSession {
|
||||
|
||||
private Map<String, Object> userSessionData = new HashMap<>();
|
||||
|
||||
/** Default constructor initializing an empty session. */
|
||||
public LessonSession() {}
|
||||
|
||||
/**
|
||||
* Retrieves the value associated with the given key.
|
||||
*
|
||||
* @param key the key for the session data
|
||||
* @return the value associated with the key, or null if the key does not exist
|
||||
*/
|
||||
public Object getValue(String key) {
|
||||
if (!userSessionData.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
// else
|
||||
return userSessionData.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value for the given key. If the key already exists, its value is updated.
|
||||
*
|
||||
* @param key the key for the session data
|
||||
* @param value the value to be associated with the key
|
||||
*/
|
||||
public void setValue(String key, Object value) {
|
||||
if (userSessionData.containsKey(key)) {
|
||||
userSessionData.replace(key, value);
|
||||
} else {
|
||||
userSessionData.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package org.owasp.webgoat.container.session;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/** Created by jason on 1/4/17. */
|
||||
public class UserSessionData {
|
||||
|
||||
private HashMap<String, Object> userSessionData = new HashMap<>();
|
||||
|
||||
public UserSessionData() {}
|
||||
|
||||
public UserSessionData(String key, String value) {
|
||||
setValue(key, value);
|
||||
}
|
||||
|
||||
// GETTERS & SETTERS
|
||||
public Object getValue(String key) {
|
||||
if (!userSessionData.containsKey(key)) {
|
||||
return null;
|
||||
}
|
||||
// else
|
||||
return userSessionData.get(key);
|
||||
}
|
||||
|
||||
public void setValue(String key, Object value) {
|
||||
if (userSessionData.containsKey(key)) {
|
||||
userSessionData.replace(key, value);
|
||||
} else {
|
||||
userSessionData.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
package org.owasp.webgoat.container.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
*
|
||||
* <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 - 2014 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 Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @version $Id: $Id
|
||||
* @since October 28, 2003
|
||||
*/
|
||||
public class WebSession implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -4270066103101711560L;
|
||||
private final WebGoatUser currentUser;
|
||||
private transient Lesson currentLesson;
|
||||
private boolean securityEnabled;
|
||||
|
||||
public WebSession() {
|
||||
this.currentUser =
|
||||
(WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the field <code>currentScreen</code>.
|
||||
*
|
||||
* @param lesson current lesson
|
||||
*/
|
||||
public void setCurrentLesson(Lesson lesson) {
|
||||
this.currentLesson = lesson;
|
||||
}
|
||||
|
||||
/**
|
||||
* getCurrentLesson.
|
||||
*
|
||||
* @return a {@link Lesson} object.
|
||||
*/
|
||||
public Lesson getCurrentLesson() {
|
||||
return this.currentLesson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the userName attribute of the WebSession object
|
||||
*
|
||||
* @return The userName value
|
||||
*/
|
||||
public String getUserName() {
|
||||
return currentUser.getUsername();
|
||||
}
|
||||
|
||||
public WebGoatUser getUser() {
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
public void toggleSecurity() {
|
||||
this.securityEnabled = !this.securityEnabled;
|
||||
}
|
||||
|
||||
public boolean isSecurityEnabled() {
|
||||
return securityEnabled;
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ import org.owasp.webgoat.container.lessons.Lesson;
|
||||
*/
|
||||
@Entity
|
||||
@EqualsAndHashCode
|
||||
public class LessonTracker {
|
||||
public class LessonProgress {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@ -61,25 +61,22 @@ public class LessonTracker {
|
||||
@Getter private String lessonName;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
private final Set<Assignment> solvedAssignments = new HashSet<>();
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
private final Set<Assignment> allAssignments = new HashSet<>();
|
||||
private final Set<Assignment> assignments = new HashSet<>();
|
||||
|
||||
@Getter private int numberOfAttempts = 0;
|
||||
@Version private Integer version;
|
||||
|
||||
private LessonTracker() {
|
||||
protected LessonProgress() {
|
||||
// JPA
|
||||
}
|
||||
|
||||
public LessonTracker(Lesson lesson) {
|
||||
public LessonProgress(Lesson lesson) {
|
||||
lessonName = lesson.getId();
|
||||
allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments());
|
||||
assignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments());
|
||||
}
|
||||
|
||||
public Optional<Assignment> getAssignment(String name) {
|
||||
return allAssignments.stream().filter(a -> a.getName().equals(name)).findFirst();
|
||||
return assignments.stream().filter(a -> a.getName().equals(name)).findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,14 +85,14 @@ public class LessonTracker {
|
||||
* @param solvedAssignment the assignment which the user solved
|
||||
*/
|
||||
public void assignmentSolved(String solvedAssignment) {
|
||||
getAssignment(solvedAssignment).ifPresent(solvedAssignments::add);
|
||||
getAssignment(solvedAssignment).ifPresent(Assignment::solved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return did they user solved all solvedAssignments for the lesson?
|
||||
*/
|
||||
public boolean isLessonSolved() {
|
||||
return allAssignments.size() == solvedAssignments.size();
|
||||
return assignments.stream().allMatch(Assignment::isSolved);
|
||||
}
|
||||
|
||||
/** Increase the number attempts to solve the lesson */
|
||||
@ -105,18 +102,17 @@ public class LessonTracker {
|
||||
|
||||
/** Reset the tracker. We do not reset the number of attempts here! */
|
||||
void reset() {
|
||||
solvedAssignments.clear();
|
||||
assignments.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list containing all the assignments solved or not
|
||||
*/
|
||||
public Map<Assignment, Boolean> getLessonOverview() {
|
||||
List<Assignment> notSolved =
|
||||
allAssignments.stream().filter(i -> !solvedAssignments.contains(i)).toList();
|
||||
Map<Assignment, Boolean> overview =
|
||||
notSolved.stream().collect(Collectors.toMap(a -> a, b -> false));
|
||||
overview.putAll(solvedAssignments.stream().collect(Collectors.toMap(a -> a, b -> true)));
|
||||
return overview;
|
||||
return assignments.stream().collect(Collectors.toMap(a -> a, Assignment::isSolved));
|
||||
}
|
||||
|
||||
long numberOfSolvedAssignments() {
|
||||
return assignments.size();
|
||||
}
|
||||
}
|
@ -3,8 +3,10 @@ package org.owasp.webgoat.container.users;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.UUID;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -44,4 +46,12 @@ public class RegistrationController {
|
||||
|
||||
return "redirect:/attack";
|
||||
}
|
||||
|
||||
@GetMapping("/login-oauth.mvc")
|
||||
public String registrationOAUTH(Authentication authentication, HttpServletRequest request)
|
||||
throws ServletException {
|
||||
log.info("register oauth user in database");
|
||||
userService.addUser(authentication.getName(), UUID.randomUUID().toString());
|
||||
return "redirect:/welcome.mvc";
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@AllArgsConstructor
|
||||
public class Scoreboard {
|
||||
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
private final UserProgressRepository userTrackerRepository;
|
||||
private final UserRepository userRepository;
|
||||
private final Course course;
|
||||
private final PluginMessages pluginMessages;
|
||||
@ -46,7 +46,7 @@ public class Scoreboard {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<String> challengesSolved(UserTracker userTracker) {
|
||||
private List<String> challengesSolved(UserProgress userTracker) {
|
||||
List<String> challenges =
|
||||
List.of(
|
||||
"Challenge1",
|
||||
@ -59,10 +59,10 @@ public class Scoreboard {
|
||||
"Challenge8",
|
||||
"Challenge9");
|
||||
return challenges.stream()
|
||||
.map(userTracker::getLessonTracker)
|
||||
.map(userTracker::getLessonProgress)
|
||||
.flatMap(Optional::stream)
|
||||
.filter(LessonTracker::isLessonSolved)
|
||||
.map(LessonTracker::getLessonName)
|
||||
.filter(LessonProgress::isLessonSolved)
|
||||
.map(LessonProgress::getLessonName)
|
||||
.map(this::toLessonTitle)
|
||||
.toList();
|
||||
}
|
||||
|
@ -9,13 +9,10 @@ import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.container.lessons.Assignment;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
|
||||
/**
|
||||
@ -52,7 +49,7 @@ import org.owasp.webgoat.container.lessons.Lesson;
|
||||
@Slf4j
|
||||
@Entity
|
||||
@EqualsAndHashCode
|
||||
public class UserTracker {
|
||||
public class UserProgress {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@ -62,11 +59,11 @@ public class UserTracker {
|
||||
private String user;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
private Set<LessonTracker> lessonTrackers = new HashSet<>();
|
||||
private Set<LessonProgress> lessonProgress = new HashSet<>();
|
||||
|
||||
private UserTracker() {}
|
||||
protected UserProgress() {}
|
||||
|
||||
public UserTracker(final String user) {
|
||||
public UserProgress(final String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@ -76,15 +73,15 @@ public class UserTracker {
|
||||
* @param lesson the lesson
|
||||
* @return a lesson tracker created if not already present
|
||||
*/
|
||||
public LessonTracker getLessonTracker(Lesson lesson) {
|
||||
Optional<LessonTracker> lessonTracker =
|
||||
lessonTrackers.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst();
|
||||
if (!lessonTracker.isPresent()) {
|
||||
LessonTracker newLessonTracker = new LessonTracker(lesson);
|
||||
lessonTrackers.add(newLessonTracker);
|
||||
public LessonProgress getLessonProgress(Lesson lesson) {
|
||||
Optional<LessonProgress> progress =
|
||||
lessonProgress.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst();
|
||||
if (!progress.isPresent()) {
|
||||
LessonProgress newLessonTracker = new LessonProgress(lesson);
|
||||
lessonProgress.add(newLessonTracker);
|
||||
return newLessonTracker;
|
||||
} else {
|
||||
return lessonTracker.get();
|
||||
return progress.get();
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,43 +91,34 @@ public class UserTracker {
|
||||
* @param id the id of the lesson
|
||||
* @return optional due to the fact we can only create a lesson tracker based on a lesson
|
||||
*/
|
||||
public Optional<LessonTracker> getLessonTracker(String id) {
|
||||
return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst();
|
||||
public Optional<LessonProgress> getLessonProgress(String id) {
|
||||
return lessonProgress.stream().filter(l -> l.getLessonName().equals(id)).findFirst();
|
||||
}
|
||||
|
||||
public void assignmentSolved(Lesson lesson, String assignmentName) {
|
||||
LessonTracker lessonTracker = getLessonTracker(lesson);
|
||||
lessonTracker.incrementAttempts();
|
||||
lessonTracker.assignmentSolved(assignmentName);
|
||||
LessonProgress progress = getLessonProgress(lesson);
|
||||
progress.incrementAttempts();
|
||||
progress.assignmentSolved(assignmentName);
|
||||
}
|
||||
|
||||
public void assignmentFailed(Lesson lesson) {
|
||||
LessonTracker lessonTracker = getLessonTracker(lesson);
|
||||
lessonTracker.incrementAttempts();
|
||||
LessonProgress progress = getLessonProgress(lesson);
|
||||
progress.incrementAttempts();
|
||||
}
|
||||
|
||||
public void reset(Lesson al) {
|
||||
LessonTracker lessonTracker = getLessonTracker(al);
|
||||
lessonTracker.reset();
|
||||
LessonProgress progress = getLessonProgress(al);
|
||||
progress.reset();
|
||||
}
|
||||
|
||||
public int numberOfLessonsSolved() {
|
||||
int numberOfLessonsSolved = 0;
|
||||
for (LessonTracker lessonTracker : lessonTrackers) {
|
||||
if (lessonTracker.isLessonSolved()) {
|
||||
numberOfLessonsSolved = numberOfLessonsSolved + 1;
|
||||
}
|
||||
}
|
||||
return numberOfLessonsSolved;
|
||||
public long numberOfLessonsSolved() {
|
||||
return lessonProgress.stream().filter(LessonProgress::isLessonSolved).count();
|
||||
}
|
||||
|
||||
public int numberOfAssignmentsSolved() {
|
||||
int numberOfAssignmentsSolved = 0;
|
||||
for (LessonTracker lessonTracker : lessonTrackers) {
|
||||
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
|
||||
numberOfAssignmentsSolved =
|
||||
lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue();
|
||||
}
|
||||
return numberOfAssignmentsSolved;
|
||||
public long numberOfAssignmentsSolved() {
|
||||
return lessonProgress.stream()
|
||||
.map(LessonProgress::numberOfSolvedAssignments)
|
||||
.mapToLong(Long::valueOf)
|
||||
.sum();
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.owasp.webgoat.container.users;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface UserProgressRepository extends JpaRepository<UserProgress, String> {
|
||||
|
||||
// TODO: make optional
|
||||
UserProgress findByUser(String user);
|
||||
}
|
@ -4,7 +4,7 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.flywaydb.core.Flyway;
|
||||
import org.owasp.webgoat.container.lessons.Initializeable;
|
||||
import org.owasp.webgoat.container.lessons.Initializable;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
@ -19,10 +19,10 @@ import org.springframework.stereotype.Service;
|
||||
public class UserService implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
private final UserProgressRepository userTrackerRepository;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final Function<String, Flyway> flywayLessons;
|
||||
private final List<Initializeable> lessonInitializables;
|
||||
private final List<Initializable> lessonInitializables;
|
||||
|
||||
@Override
|
||||
public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
@ -43,7 +43,7 @@ public class UserService implements UserDetailsService {
|
||||
|
||||
if (!userAlreadyExists) {
|
||||
userTrackerRepository.save(
|
||||
new UserTracker(username)); // if user previously existed it will not get another tracker
|
||||
new UserProgress(username)); // if user previously existed it will not get another tracker
|
||||
createLessonsForUser(webGoatUser);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
package org.owasp.webgoat.container.users;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/30/17.
|
||||
*/
|
||||
public interface UserTrackerRepository extends JpaRepository<UserTracker, String> {
|
||||
|
||||
UserTracker findByUser(String user);
|
||||
}
|
@ -32,9 +32,7 @@ import java.util.Map;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.owasp.webgoat.container.session.LessonSession;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -50,9 +48,11 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
})
|
||||
public class VerifyAccount extends AssignmentEndpoint {
|
||||
|
||||
@Autowired private WebSession webSession;
|
||||
private final LessonSession userSessionData;
|
||||
|
||||
@Autowired UserSessionData userSessionData;
|
||||
public VerifyAccount(LessonSession userSessionData) {
|
||||
this.userSessionData = userSessionData;
|
||||
}
|
||||
|
||||
@PostMapping(
|
||||
path = "/auth-bypass/verify-account",
|
||||
|
@ -2,11 +2,13 @@ package org.owasp.webgoat.lessons.challenges;
|
||||
|
||||
import org.owasp.webgoat.container.lessons.Category;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
@Component
|
||||
public class ChallengeIntro extends Lesson {
|
||||
|
||||
@Override
|
||||
|
@ -25,8 +25,7 @@ package org.owasp.webgoat.lessons.challenges;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -36,13 +35,12 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@AllArgsConstructor
|
||||
public class FlagController extends AssignmentEndpoint {
|
||||
|
||||
private final WebSession webSession;
|
||||
private final Flags flags;
|
||||
|
||||
@PostMapping(path = "/challenge/flag", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@PostMapping(path = "/challenge/flag/{flagNumber}")
|
||||
@ResponseBody
|
||||
public AttackResult postFlag(@RequestParam String flag) {
|
||||
Flag expectedFlag = flags.getFlag(webSession.getCurrentLesson());
|
||||
public AttackResult postFlag(@PathVariable int flagNumber, @RequestParam String flag) {
|
||||
var expectedFlag = flags.getFlag(flagNumber);
|
||||
if (expectedFlag.isCorrect(flag)) {
|
||||
return success(this).feedback("challenge.flag.correct").build();
|
||||
} else {
|
||||
|
@ -4,7 +4,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.IntStream;
|
||||
import org.owasp.webgoat.container.lessons.Lesson;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@ -15,12 +14,6 @@ public class Flags {
|
||||
IntStream.range(1, 10).forEach(i -> FLAGS.put(i, new Flag(i, UUID.randomUUID().toString())));
|
||||
}
|
||||
|
||||
public Flag getFlag(Lesson forLesson) {
|
||||
String lessonName = forLesson.getName();
|
||||
int challengeNumber = Integer.valueOf(lessonName.substring(lessonName.length() - 1));
|
||||
return FLAGS.get(challengeNumber);
|
||||
}
|
||||
|
||||
public Flag getFlag(int flagNumber) {
|
||||
return FLAGS.get(flagNumber);
|
||||
}
|
||||
|
@ -24,14 +24,14 @@ package org.owasp.webgoat.lessons.chromedevtools;
|
||||
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.LessonSession;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* This is just a class used to make the the HTTP request.
|
||||
* This is just a class used to make the HTTP request.
|
||||
*
|
||||
* @author TMelzer
|
||||
* @since 30.11.18
|
||||
@ -39,11 +39,16 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
public class NetworkDummy extends AssignmentEndpoint {
|
||||
|
||||
private final LessonSession lessonSession;
|
||||
|
||||
public NetworkDummy(LessonSession lessonSession) {
|
||||
this.lessonSession = lessonSession;
|
||||
}
|
||||
|
||||
@PostMapping("/ChromeDevTools/dummy")
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String successMessage) {
|
||||
UserSessionData userSessionData = getUserSessionData();
|
||||
String answer = (String) userSessionData.getValue("randValue");
|
||||
String answer = (String) lessonSession.getValue("randValue");
|
||||
|
||||
if (successMessage != null && successMessage.equals(answer)) {
|
||||
return success(this).feedback("xss-dom-message-success").build();
|
||||
|
@ -31,7 +31,7 @@ import org.springframework.stereotype.Component;
|
||||
public class CSRF extends Lesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.A10;
|
||||
return Category.A5;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,7 +25,7 @@ package org.owasp.webgoat.lessons.csrf;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.LessonSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -36,7 +36,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@AssignmentHints({"csrf-get.hint1", "csrf-get.hint2", "csrf-get.hint3", "csrf-get.hint4"})
|
||||
public class CSRFConfirmFlag1 extends AssignmentEndpoint {
|
||||
|
||||
@Autowired UserSessionData userSessionData;
|
||||
@Autowired LessonSession userSessionData;
|
||||
|
||||
@PostMapping(
|
||||
path = "/csrf/confirm-flag-1",
|
||||
|
@ -33,7 +33,7 @@ import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.LessonSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -42,15 +42,11 @@ import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 11/17/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"csrf-feedback-hint1", "csrf-feedback-hint2", "csrf-feedback-hint3"})
|
||||
public class CSRFFeedback extends AssignmentEndpoint {
|
||||
|
||||
@Autowired private UserSessionData userSessionData;
|
||||
@Autowired private LessonSession userSessionData;
|
||||
@Autowired private ObjectMapper objectMapper;
|
||||
|
||||
@PostMapping(
|
||||
|
@ -27,10 +27,9 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.LessonSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@ -38,13 +37,12 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
public class CSRFGetFlag {
|
||||
|
||||
@Autowired UserSessionData userSessionData;
|
||||
@Autowired LessonSession userSessionData;
|
||||
@Autowired private PluginMessages pluginMessages;
|
||||
|
||||
@RequestMapping(
|
||||
@PostMapping(
|
||||
path = "/csrf/basic-get-flag",
|
||||
produces = {"application/json"},
|
||||
method = RequestMethod.POST)
|
||||
produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public Map<String, Object> invoke(HttpServletRequest req) {
|
||||
|
||||
|
@ -22,47 +22,26 @@
|
||||
|
||||
package org.owasp.webgoat.lessons.csrf;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.owasp.webgoat.container.CurrentUsername;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.users.UserTracker;
|
||||
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 11/17/17.
|
||||
*/
|
||||
@RestController
|
||||
@AssignmentHints({"csrf-login-hint1", "csrf-login-hint2", "csrf-login-hint3"})
|
||||
public class CSRFLogin extends AssignmentEndpoint {
|
||||
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
|
||||
public CSRFLogin(UserTrackerRepository userTrackerRepository) {
|
||||
this.userTrackerRepository = userTrackerRepository;
|
||||
}
|
||||
|
||||
@PostMapping(
|
||||
path = "/csrf/login",
|
||||
produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public AttackResult completed(HttpServletRequest request) {
|
||||
String userName = request.getUserPrincipal().getName();
|
||||
if (userName.startsWith("csrf")) {
|
||||
markAssignmentSolvedWithRealUser(userName.substring("csrf-".length()));
|
||||
public AttackResult completed(@CurrentUsername String username) {
|
||||
if (username.startsWith("csrf")) {
|
||||
return success(this).feedback("csrf-login-success").build();
|
||||
}
|
||||
return failed(this).feedback("csrf-login-failed").feedbackArgs(userName).build();
|
||||
}
|
||||
|
||||
private void markAssignmentSolvedWithRealUser(String username) {
|
||||
UserTracker userTracker = userTrackerRepository.findByUser(username);
|
||||
userTracker.assignmentSolved(
|
||||
getWebSession().getCurrentLesson(), this.getClass().getSimpleName());
|
||||
userTrackerRepository.save(userTracker);
|
||||
return failed(this).feedback("csrf-login-failed").feedbackArgs(username).build();
|
||||
}
|
||||
}
|
||||
|
@ -33,11 +33,10 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.owasp.webgoat.container.CurrentUsername;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -48,7 +47,6 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@AssignmentHints({"csrf-review-hint1", "csrf-review-hint2", "csrf-review-hint3"})
|
||||
public class ForgedReviews extends AssignmentEndpoint {
|
||||
|
||||
@Autowired private WebSession webSession;
|
||||
private static DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd, HH:mm:ss");
|
||||
|
||||
private static final Map<String, List<Review>> userReviews = new HashMap<>();
|
||||
@ -73,9 +71,9 @@ public class ForgedReviews extends AssignmentEndpoint {
|
||||
produces = MediaType.APPLICATION_JSON_VALUE,
|
||||
consumes = ALL_VALUE)
|
||||
@ResponseBody
|
||||
public Collection<Review> retrieveReviews() {
|
||||
public Collection<Review> retrieveReviews(@CurrentUsername String username) {
|
||||
Collection<Review> allReviews = Lists.newArrayList();
|
||||
Collection<Review> newReviews = userReviews.get(webSession.getUserName());
|
||||
Collection<Review> newReviews = userReviews.get(username);
|
||||
if (newReviews != null) {
|
||||
allReviews.addAll(newReviews);
|
||||
}
|
||||
@ -88,7 +86,11 @@ public class ForgedReviews extends AssignmentEndpoint {
|
||||
@PostMapping("/csrf/review")
|
||||
@ResponseBody
|
||||
public AttackResult createNewReview(
|
||||
String reviewText, Integer stars, String validateReq, HttpServletRequest request) {
|
||||
String reviewText,
|
||||
Integer stars,
|
||||
String validateReq,
|
||||
HttpServletRequest request,
|
||||
@CurrentUsername String username) {
|
||||
final String host = (request.getHeader("host") == null) ? "NULL" : request.getHeader("host");
|
||||
final String referer =
|
||||
(request.getHeader("referer") == null) ? "NULL" : request.getHeader("referer");
|
||||
@ -97,11 +99,11 @@ public class ForgedReviews extends AssignmentEndpoint {
|
||||
Review review = new Review();
|
||||
review.setText(reviewText);
|
||||
review.setDateTime(LocalDateTime.now().format(fmt));
|
||||
review.setUser(webSession.getUserName());
|
||||
review.setUser(username);
|
||||
review.setStars(stars);
|
||||
var reviews = userReviews.getOrDefault(webSession.getUserName(), new ArrayList<>());
|
||||
var reviews = userReviews.getOrDefault(username, new ArrayList<>());
|
||||
reviews.add(review);
|
||||
userReviews.put(webSession.getUserName(), reviews);
|
||||
userReviews.put(username, reviews);
|
||||
// short-circuit
|
||||
if (validateReq == null || !validateReq.equals(weakAntiCSRF)) {
|
||||
return failed(this).feedback("csrf-you-forgot-something").build();
|
||||
|
@ -26,7 +26,7 @@ package org.owasp.webgoat.lessons.idor;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.LessonSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
@ -48,7 +48,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
})
|
||||
public class IDOREditOtherProfile extends AssignmentEndpoint {
|
||||
|
||||
@Autowired private UserSessionData userSessionData;
|
||||
@Autowired private LessonSession userSessionData;
|
||||
|
||||
@PutMapping(path = "/IDOR/profile/{userId}", consumes = "application/json")
|
||||
@ResponseBody
|
||||
|
@ -28,7 +28,7 @@ import java.util.Map;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||
import org.owasp.webgoat.container.session.UserSessionData;
|
||||
import org.owasp.webgoat.container.session.LessonSession;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -38,6 +38,12 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@AssignmentHints({"idor.hints.idor_login"})
|
||||
public class IDORLogin extends AssignmentEndpoint {
|
||||
|
||||
private final LessonSession lessonSession;
|
||||
|
||||
public IDORLogin(LessonSession lessonSession) {
|
||||
this.lessonSession = lessonSession;
|
||||
}
|
||||
|
||||
private Map<String, Map<String, String>> idorUserInfo = new HashMap<>();
|
||||
|
||||
public void initIDORInfo() {
|
||||
@ -59,13 +65,11 @@ public class IDORLogin extends AssignmentEndpoint {
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String username, @RequestParam String password) {
|
||||
initIDORInfo();
|
||||
UserSessionData userSessionData = getUserSessionData();
|
||||
|
||||
if (idorUserInfo.containsKey(username)) {
|
||||
if ("tom".equals(username) && idorUserInfo.get("tom").get("password").equals(password)) {
|
||||
userSessionData.setValue("idor-authenticated-as", username);
|
||||
userSessionData.setValue(
|
||||
"idor-authenticated-user-id", idorUserInfo.get(username).get("id"));
|
||||
lessonSession.setValue("idor-authenticated-as", username);
|
||||
lessonSession.setValue("idor-authenticated-user-id", idorUserInfo.get(username).get("id"));
|
||||
return success(this).feedback("idor.login.success").feedbackArgs(username).build();
|
||||
} else {
|
||||
return failed(this).feedback("idor.login.failure").build();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user