Compare commits
1 Commits
nbaars/ref
...
gh-1165
Author | SHA1 | Date | |
---|---|---|---|
46f0411678 |
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
@ -12,3 +12,4 @@ updates:
|
|||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
|
|
||||||
|
54
.github/workflows/branchbuild.txt
vendored
54
.github/workflows/branchbuild.txt
vendored
@ -1,54 +0,0 @@
|
|||||||
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 }}
|
|
77
.github/workflows/build.yml
vendored
77
.github/workflows/build.yml
vendored
@ -1,51 +1,60 @@
|
|||||||
name: "Main / Pull requests build"
|
name: "Pull requests build"
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.txt'
|
- '.txt'
|
||||||
- 'LICENSE'
|
- 'LICENSE'
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
branches: [ main ]
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pre-commit:
|
pr-build:
|
||||||
name: Pre-commit check
|
if: >
|
||||||
runs-on: ubuntu-latest
|
github.event_name == 'pull_request' && !github.event.pull_request.draft && (
|
||||||
steps:
|
github.event.action == 'opened' ||
|
||||||
- name: Checkout git repository
|
github.event.action == 'reopened' ||
|
||||||
uses: actions/checkout@v4.1.6
|
github.event.action == 'synchronize'
|
||||||
- name: Setup python
|
)
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: "3.9"
|
|
||||||
- uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
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 }}
|
runs-on: ${{ matrix.os }}
|
||||||
needs: [ pre-commit ]
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
|
||||||
matrix:
|
matrix:
|
||||||
os: [ windows-latest, ubuntu-latest, macos-13 ]
|
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||||
max-parallel: 1
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v3
|
||||||
- name: Set up JDK 21
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v4.2.1
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 21
|
java-version: 17
|
||||||
architecture: x64
|
architecture: x64
|
||||||
cache: 'maven'
|
- 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
|
- name: Build with Maven
|
||||||
run: mvn --no-transfer-progress verify
|
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,20 +8,24 @@ jobs:
|
|||||||
if: github.repository == 'WebGoat/WebGoat'
|
if: github.repository == 'WebGoat/WebGoat'
|
||||||
name: Release WebGoat
|
name: Release WebGoat
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
environment:
|
environment:
|
||||||
name: release
|
name: release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up JDK 21
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 21
|
java-version: 17
|
||||||
architecture: x64
|
architecture: x64
|
||||||
cache: 'maven'
|
|
||||||
|
- 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: "Set labels for ${{ github.ref }}"
|
- name: "Set labels for ${{ github.ref }}"
|
||||||
run: |
|
run: |
|
||||||
@ -68,26 +72,26 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: "Set up QEMU"
|
- name: "Set up QEMU"
|
||||||
uses: docker/setup-qemu-action@v3.1.0
|
uses: docker/setup-qemu-action@v2.2.0
|
||||||
with:
|
with:
|
||||||
platforms: all
|
platforms: all
|
||||||
|
|
||||||
- name: "Set up Docker Buildx"
|
- name: "Set up Docker Buildx"
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
- name: "Login to dockerhub"
|
- name: "Login to dockerhub"
|
||||||
uses: docker/login-action@v3.3.0
|
uses: docker/login-action@v2.2.0
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: "Build and push WebGoat"
|
- name: "Build and push WebGoat"
|
||||||
uses: docker/build-push-action@v6.9.0
|
uses: docker/build-push-action@v4.1.1
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64, linux/arm64
|
platforms: linux/amd64, linux/arm64, linux/arm/v7
|
||||||
tags: |
|
tags: |
|
||||||
webgoat/webgoat:${{ env.WEBGOAT_TAG_VERSION }}
|
webgoat/webgoat:${{ env.WEBGOAT_TAG_VERSION }}
|
||||||
webgoat/webgoat:latest
|
webgoat/webgoat:latest
|
||||||
@ -95,7 +99,7 @@ jobs:
|
|||||||
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
webgoat_version=${{ env.WEBGOAT_MAVEN_VERSION }}
|
||||||
|
|
||||||
- name: "Build and push WebGoat desktop"
|
- name: "Build and push WebGoat desktop"
|
||||||
uses: docker/build-push-action@v6.9.0
|
uses: docker/build-push-action@v4.1.1
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile_desktop
|
file: ./Dockerfile_desktop
|
||||||
@ -112,15 +116,15 @@ jobs:
|
|||||||
needs: [ release ]
|
needs: [ release ]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up JDK 21
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 21
|
java-version: 17
|
||||||
architecture: x64
|
architecture: x64
|
||||||
|
|
||||||
- name: Set version to next snapshot
|
- name: Set version to next snapshot
|
||||||
@ -141,3 +145,4 @@ jobs:
|
|||||||
github_token: "${{ secrets.GITHUB_TOKEN }}"
|
github_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
title: ${{ github.event.commits[0].message }}
|
title: ${{ github.event.commits[0].message }}
|
||||||
target_branch: main
|
target_branch: main
|
||||||
|
|
||||||
|
22
.github/workflows/test.yml
vendored
22
.github/workflows/test.yml
vendored
@ -21,21 +21,27 @@ jobs:
|
|||||||
name: "Robot framework test"
|
name: "Robot framework test"
|
||||||
steps:
|
steps:
|
||||||
# Uses an default action to checkout the code
|
# Uses an default action to checkout the code
|
||||||
- uses: actions/checkout@v4.1.6
|
- uses: actions/checkout@v3
|
||||||
# Uses an action to add Python to the VM
|
# Uses an action to add Python to the VM
|
||||||
- name: Setup Python
|
- name: Setup Pyton
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.7'
|
python-version: '3.7'
|
||||||
architecture: x64
|
architecture: x64
|
||||||
# Uses an action to add JDK 21 to the VM (and mvn?)
|
# Uses an action to add JDK 17 to the VM (and mvn?)
|
||||||
- name: set up JDK 21
|
- name: set up JDK 17
|
||||||
uses: actions/setup-java@v4.2.1
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 21
|
java-version: 17
|
||||||
architecture: x64
|
architecture: x64
|
||||||
cache: 'maven'
|
#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-
|
||||||
- uses: BSFishy/pip-action@v1
|
- uses: BSFishy/pip-action@v1
|
||||||
with:
|
with:
|
||||||
packages: |
|
packages: |
|
||||||
|
2
.github/workflows/welcome.yml
vendored
2
.github/workflows/welcome.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
if: github.repository == 'WebGoat/WebGoat'
|
if: github.repository == 'WebGoat/WebGoat'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/first-interaction@v1.3.0
|
- uses: actions/first-interaction@v1.1.1
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
issue-message: 'Thanks for submitting your first issue, we will have a look as quickly as possible.'
|
issue-message: 'Thanks for submitting your first issue, we will have a look as quickly as possible.'
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
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:
|
### Release notes:
|
||||||
|
|
||||||
Update the release notes with the correct version. Use `git shortlog -s -n --since "JAN 06 2023"` for the list of
|
Update the release notes with the correct version. Use `git shortlog -s -n --since "JAN 06 2023"` for the list of
|
||||||
committers. In order to fetch the list of issues included use: `git log --graph --pretty='%C(auto)%d%Creset%s' v2023.4..origin/main`
|
committers.
|
||||||
|
|
||||||
```
|
```
|
||||||
mvn versions:set
|
mvn versions:set
|
||||||
|
19
Dockerfile
19
Dockerfile
@ -1,8 +1,6 @@
|
|||||||
# We need JDK as some of the lessons needs to be able to compile Java code
|
FROM docker.io/eclipse-temurin:19-jre-focal
|
||||||
FROM docker.io/eclipse-temurin:21-jdk-jammy
|
LABEL NAME = "WebGoat: A deliberately insecure Web Application"
|
||||||
|
MAINTAINER "WebGoat team"
|
||||||
LABEL name="WebGoat: A deliberately insecure Web Application"
|
|
||||||
LABEL maintainer="WebGoat team"
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
useradd -ms /bin/bash webgoat && \
|
useradd -ms /bin/bash webgoat && \
|
||||||
@ -16,8 +14,6 @@ COPY --chown=webgoat target/webgoat-*.jar /home/webgoat/webgoat.jar
|
|||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
EXPOSE 9090
|
EXPOSE 9090
|
||||||
|
|
||||||
ENV TZ=Europe/Amsterdam
|
|
||||||
|
|
||||||
WORKDIR /home/webgoat
|
WORKDIR /home/webgoat
|
||||||
ENTRYPOINT [ "java", \
|
ENTRYPOINT [ "java", \
|
||||||
"-Duser.home=/home/webgoat", \
|
"-Duser.home=/home/webgoat", \
|
||||||
@ -34,7 +30,8 @@ ENTRYPOINT [ "java", \
|
|||||||
"--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", \
|
"--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", \
|
||||||
"--add-opens", "java.base/java.io=ALL-UNNAMED", \
|
"--add-opens", "java.base/java.io=ALL-UNNAMED", \
|
||||||
"-Drunning.in.docker=true", \
|
"-Drunning.in.docker=true", \
|
||||||
"-jar", "webgoat.jar", "--server.address", "0.0.0.0" ]
|
"-Dwebgoat.host=0.0.0.0", \
|
||||||
|
"-Dwebwolf.host=0.0.0.0", \
|
||||||
HEALTHCHECK --interval=5s --timeout=3s \
|
"-Dwebgoat.port=8080", \
|
||||||
CMD curl --fail http://localhost:8080/WebGoat/actuator/health || exit 1
|
"-Dwebwolf.port=9090", \
|
||||||
|
"-jar", "webgoat.jar" ]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
FROM lscr.io/linuxserver/webtop:ubuntu-xfce
|
FROM lscr.io/linuxserver/webtop:ubuntu-xfce
|
||||||
LABEL NAME = "WebGoat: A deliberately insecure Web Application"
|
LABEL NAME = "WebGoat: A deliberately insecure Web Application"
|
||||||
LABEL maintainer = "WebGoat team"
|
MAINTAINER "WebGoat team"
|
||||||
|
|
||||||
WORKDIR /config
|
WORKDIR /config
|
||||||
|
|
||||||
@ -9,38 +9,26 @@ COPY config/desktop/start_webgoat.sh /config/start_webgoat.sh
|
|||||||
COPY config/desktop/start_zap.sh /config/start_zap.sh
|
COPY config/desktop/start_zap.sh /config/start_zap.sh
|
||||||
COPY config/desktop/WebGoat.txt /config/Desktop/
|
COPY config/desktop/WebGoat.txt /config/Desktop/
|
||||||
|
|
||||||
RUN \
|
|
||||||
apt-get update && \
|
|
||||||
apt-get --yes install vim nano gzip
|
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
case $(uname -m) in \
|
case $(uname -m) in \
|
||||||
x86_64) ARCH=x64;; \
|
x86_64) ARCH=x64;; \
|
||||||
aarch64) ARCH=aarch64;; \
|
aarch64) ARCH=aarch64;; \
|
||||||
*) ARCH=unknown;; \
|
*) ARCH=unknown;; \
|
||||||
esac && \
|
esac && \
|
||||||
echo ${ARCH}
|
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 && \
|
||||||
RUN \
|
rm -rf ZAP_2.12.0_Linux.tar.gz && \
|
||||||
curl -LO https://github.com/zaproxy/zaproxy/releases/download/v2.15.0/ZAP_2.15.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 ZAP_2.15.0_Linux.tar.gz && \
|
tar zfxv OpenJDK17U-jre_${ARCH}_linux_hotspot_17.0.6_10.tar.gz && \
|
||||||
rm -rf ZAP_2.15.0_Linux.tar.gz
|
rm -rf OpenJDK17U-jre_${ARCH}_linux_hotspot_17.0.6_10.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_webgoat.sh && \
|
||||||
chmod +x /config/start_zap.sh && \
|
chmod +x /config/start_zap.sh && \
|
||||||
echo "JAVA_HOME=/config/jdk-21.0.3+9-jre/" >> .bash_aliases && \
|
apt-get update && \
|
||||||
|
apt-get --yes install vim nano && \
|
||||||
|
echo "JAVA_HOME=/config/jdk-17.0.6+10-jre/" >> .bash_aliases && \
|
||||||
echo "PATH=$PATH:$JAVA_HOME/bin" >> .bash_aliases
|
echo "PATH=$PATH:$JAVA_HOME/bin" >> .bash_aliases
|
||||||
|
|
||||||
ENV JAVA_HOME=/config/jdk-21.0.3+9-jre
|
|
||||||
|
ENV JAVA_HOME=/home/webgoat/jdk-17.0.6+10-jre
|
||||||
|
|
||||||
WORKDIR /config/Desktop
|
WORKDIR /config/Desktop
|
||||||
|
1
FAQ.md
1
FAQ.md
@ -5,3 +5,4 @@
|
|||||||
### Integration tests fail
|
### Integration tests fail
|
||||||
|
|
||||||
Try to run the command in the console `java -jar ...` and remove `-Dlogging.pattern.console=` from the command line.
|
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: A deliberately insecure Web Application
|
# WebGoat 8: A deliberately insecure Web Application
|
||||||
|
|
||||||
[](https://github.com/WebGoat/WebGoat/actions/workflows/build.yml)
|
[](https://github.com/WebGoat/WebGoat/actions/workflows/build.yml)
|
||||||
[](https://jdk.java.net/)
|
[](https://jdk.java.net/)
|
||||||
[](https://owasp.org/projects/)
|
[](https://owasp.org/projects/)
|
||||||
[](https://github.com/WebGoat/WebGoat/releases/latest)
|
[](https://github.com/WebGoat/WebGoat/releases/latest)
|
||||||
[](https://gitter.im/OWASPWebGoat/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
[](https://gitter.im/OWASPWebGoat/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
@ -44,27 +44,19 @@ 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
|
docker run -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 webgoat/webgoat
|
||||||
```
|
```
|
||||||
|
|
||||||
For some lessons you need the container run in the same timezone. For this you can set the TZ environment variable.
|
If you want to reuse the container, give it a name:
|
||||||
E.g.
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
docker run -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 -e TZ=America/Boise webgoat/webgoat
|
docker run --name webgoat -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 webgoat/webgoat
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want to use OWASP ZAP or another proxy, you can no longer use 127.0.0.1 or localhost. but
|
As long as you don't remove the container you can use:
|
||||||
you can use custom host entries. For example:
|
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
127.0.0.1 www.webgoat.local www.webwolf.local
|
docker start webgoat
|
||||||
```
|
```
|
||||||
|
|
||||||
Then you can run the container with:
|
This way, you can start where you left off. If you remove the container, you need to use `docker run` again.
|
||||||
|
|
||||||
```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
|
## 2. Run using Docker with complete Linux Desktop
|
||||||
|
|
||||||
@ -79,27 +71,16 @@ 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)
|
Download the latest WebGoat release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases)
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
export TZ=Europe/Amsterdam # or your timezone
|
java -Dfile.encoding=UTF-8 -Dwebgoat.port=8080 -Dwebwolf.port=9090 -jar webgoat-2023.3.jar
|
||||||
java -Dfile.encoding=UTF-8 -jar webgoat-2023.8.jar
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Click the link in the log to start WebGoat.
|
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
|
## 4. Run from the sources
|
||||||
|
|
||||||
### Prerequisites:
|
### Prerequisites:
|
||||||
|
|
||||||
* Java 17 or 21
|
* Java 17
|
||||||
* Your favorite IDE
|
* Your favorite IDE
|
||||||
* Git, or Git support in your IDE
|
* Git, or Git support in your IDE
|
||||||
|
|
||||||
@ -151,10 +132,9 @@ 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:
|
For instance running as a jar on a Linux/macOS it will look like this:
|
||||||
|
|
||||||
```Shell
|
```Shell
|
||||||
export TZ=Europe/Amsterdam # or your timezone
|
|
||||||
export EXCLUDE_CATEGORIES="CLIENT_SIDE,GENERAL,CHALLENGE"
|
export EXCLUDE_CATEGORIES="CLIENT_SIDE,GENERAL,CHALLENGE"
|
||||||
export EXCLUDE_LESSONS="SqlInjectionAdvanced,SqlInjectionMitigations"
|
export EXCLUDE_LESSONS="SqlInjectionAdvanced,SqlInjectionMitigations"
|
||||||
java -jar target/webgoat-2023.8-SNAPSHOT.jar
|
java -jar target/webgoat-2023.3-SNAPSHOT.jar
|
||||||
```
|
```
|
||||||
|
|
||||||
Or in a docker run it would (once this version is pushed into docker hub) look like this:
|
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. 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
|
1. Add the parts for showing the flag and providing the correct value for the flag= parameter
|
||||||
2.
|
2.
|
||||||
2. Add a flag image to src/main/resources/webgoat/static/css/img
|
3. 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
|
1. See the main_new.html for a link to download flag resources
|
||||||
3. Add a welcome page to the introduction lesson
|
4. 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)
|
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
|
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
|
||||||
4. Translate the main labels
|
5. Translate the main labels
|
||||||
1. Copy messages.properties to messages_es.properties (if in this case you want to add Spanish)
|
1. Copy messages.properties to messages_es.properties (if in this case you want to add Spanish)
|
||||||
2. Translate the label values
|
2. Translate the label values
|
||||||
5. Optionally translate lessons by
|
6. Optionally translate lessons by
|
||||||
1. Adding lang specifc adoc files in documentation folder of the lesson
|
1. Adding lang specifc adoc files in documentation folder of the lesson
|
||||||
2. Adding WebGoatLabels.properties of a specific language if you want to
|
2. Adding WebGoatLabels.properties of a specific language if you want to
|
||||||
6. Run mvn clean to see if the LabelAndHintIntegration test passes
|
7. 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
|
8. 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
|
If you only want to translate more for a certain language, you only need to do step 4-8
|
||||||
|
@ -1,60 +1,5 @@
|
|||||||
# WebGoat release notes
|
# 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
|
## Version 2023.4
|
||||||
|
|
||||||
### New functionality
|
### New functionality
|
||||||
@ -215,3 +160,4 @@ Special thanks to the following contributors providing us with a pull request:
|
|||||||
And everyone who provided feedback through Github.
|
And everyone who provided feedback through Github.
|
||||||
|
|
||||||
Team WebGoat
|
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.
|
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:
|
You can start WebGoat and ZAP by opening a terminal and type:
|
||||||
|
|
||||||
./start_webgoat.sh
|
./start-webgoat.sh
|
||||||
./start_zap.sh
|
./start_zap.sh
|
||||||
|
|
||||||
Happy hacking,
|
Happy hacking,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
/config/jdk-21.0.3+9-jre/bin/java \
|
/config/jdk-17.0.6+10-jre/bin/java \
|
||||||
-Duser.home=/config \
|
-Duser.home=/config \
|
||||||
-Dfile.encoding=UTF-8 \
|
-Dfile.encoding=UTF-8 \
|
||||||
-DTZ=Europe/Amsterdam \
|
-DTZ=Europe/Amsterdam \
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
/config/jdk-21.0.3+9-jre/bin/java -jar /config/ZAP_2.15.0/zap-2.15.0.jar
|
/config/jdk-17.0.6+10-jre/bin/java -jar /config/ZAP_2.12.0/zap-2.12.0.jar
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
# WebGoat landing page
|
# WebGoat landing page
|
||||||
|
|
||||||
Old GitHub page which now redirects to OWASP website.
|
Old GitHub page which now redirects to OWASP website.
|
||||||
|
|
||||||
|
238
pom.xml
238
pom.xml
@ -5,12 +5,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>3.3.5</version>
|
<version>3.1.0</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>org.owasp.webgoat</groupId>
|
<groupId>org.owasp.webgoat</groupId>
|
||||||
<artifactId>webgoat</artifactId>
|
<artifactId>webgoat</artifactId>
|
||||||
<version>2024.2-SNAPSHOT</version>
|
<version>2023.5-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>WebGoat</name>
|
<name>WebGoat</name>
|
||||||
@ -29,6 +29,13 @@
|
|||||||
</licenses>
|
</licenses>
|
||||||
|
|
||||||
<developers>
|
<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>
|
<developer>
|
||||||
<id>nbaars</id>
|
<id>nbaars</id>
|
||||||
<name>Nanne Baars</name>
|
<name>Nanne Baars</name>
|
||||||
@ -36,6 +43,11 @@
|
|||||||
<organizationUrl>https://github.com/nbaars</organizationUrl>
|
<organizationUrl>https://github.com/nbaars</organizationUrl>
|
||||||
<timezone>Europe/Amsterdam</timezone>
|
<timezone>Europe/Amsterdam</timezone>
|
||||||
</developer>
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<id>misfir3</id>
|
||||||
|
<name>Jason White</name>
|
||||||
|
<email>jason.white@owasp.org</email>
|
||||||
|
</developer>
|
||||||
<developer>
|
<developer>
|
||||||
<id>zubcevic</id>
|
<id>zubcevic</id>
|
||||||
<name>René Zubcevic</name>
|
<name>René Zubcevic</name>
|
||||||
@ -46,8 +58,43 @@
|
|||||||
<name>Àngel Ollé Blázquez</name>
|
<name>Àngel Ollé Blázquez</name>
|
||||||
<email>angel@olleb.com</email>
|
<email>angel@olleb.com</email>
|
||||||
</developer>
|
</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>
|
</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>
|
<scm>
|
||||||
<connection>scm:git:git@github.com:WebGoat/WebGoat.git</connection>
|
<connection>scm:git:git@github.com:WebGoat/WebGoat.git</connection>
|
||||||
<developerConnection>scm:git:git@github.com:WebGoat/WebGoat.git</developerConnection>
|
<developerConnection>scm:git:git@github.com:WebGoat/WebGoat.git</developerConnection>
|
||||||
@ -62,56 +109,60 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<!-- Shared properties with plugins and version numbers across submodules-->
|
<!-- Shared properties with plugins and version numbers across submodules-->
|
||||||
<asciidoctorj.version>3.0.0</asciidoctorj.version>
|
<asciidoctorj.version>2.5.10</asciidoctorj.version>
|
||||||
<bootstrap.version>5.3.3</bootstrap.version>
|
<!-- Upgrading needs UI work in WebWolf -->
|
||||||
|
<bootstrap.version>3.3.7</bootstrap.version>
|
||||||
<cglib.version>3.3.0</cglib.version>
|
<cglib.version>3.3.0</cglib.version>
|
||||||
<!-- do not update necessary for lesson -->
|
<!-- do not update necessary for lesson -->
|
||||||
<checkstyle.version>3.6.0</checkstyle.version>
|
<checkstyle.version>3.3.0</checkstyle.version>
|
||||||
<commons-collections.version>3.2.1</commons-collections.version>
|
<commons-collections.version>3.2.1</commons-collections.version>
|
||||||
<commons-compress.version>1.27.1</commons-compress.version>
|
<commons-io.version>2.11.0</commons-io.version>
|
||||||
<commons-io.version>2.17.0</commons-io.version>
|
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||||
<commons-lang3.version>3.14.0</commons-lang3.version>
|
<commons-text.version>1.10.0</commons-text.version>
|
||||||
<commons-text.version>1.12.0</commons-text.version>
|
<guava.version>32.1.1-jre</guava.version>
|
||||||
<guava.version>33.3.1-jre</guava.version>
|
<jacoco.version>0.8.10</jacoco.version>
|
||||||
<jacoco.version>0.8.11</jacoco.version>
|
<java.version>17</java.version>
|
||||||
<java.version>21</java.version>
|
|
||||||
<jaxb.version>2.3.1</jaxb.version>
|
<jaxb.version>2.3.1</jaxb.version>
|
||||||
<jjwt.version>0.9.1</jjwt.version>
|
<jjwt.version>0.9.1</jjwt.version>
|
||||||
<jose4j.version>0.9.3</jose4j.version>
|
<jose4j.version>0.9.3</jose4j.version>
|
||||||
<jquery.version>3.7.1</jquery.version>
|
<jquery.version>3.6.4</jquery.version>
|
||||||
<jsoup.version>1.18.1</jsoup.version>
|
<jsoup.version>1.16.1</jsoup.version>
|
||||||
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
|
||||||
<maven-failsafe-plugin.version>2.22.0</maven-failsafe-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-jar-plugin.version>3.1.2</maven-jar-plugin.version>
|
||||||
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-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-source-plugin.version>3.1.0</maven-source-plugin.version>
|
||||||
<maven-surefire-plugin.version>3.5.2</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
<maven.compiler.target>21</maven.compiler.target>
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
<pmd.version>3.15.0</pmd.version>
|
<pmd.version>3.15.0</pmd.version>
|
||||||
<!-- Use UTF-8 Encoding -->
|
<!-- Use UTF-8 Encoding -->
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<thymeleaf.version>3.1.2.RELEASE</thymeleaf.version>
|
<thymeleaf.version>3.1.1.RELEASE</thymeleaf.version>
|
||||||
<waittimeForServerStart>60</waittimeForServerStart>
|
<webdriver.version>5.3.2</webdriver.version>
|
||||||
<webdriver.version>5.9.2</webdriver.version>
|
<webgoat.port>8080</webgoat.port>
|
||||||
<webgoat.context>/</webgoat.context>
|
<webwolf.port>9090</webwolf.port>
|
||||||
<webgoat.sslenabled>false</webgoat.sslenabled>
|
<wiremock.version>2.27.2</wiremock.version>
|
||||||
<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>
|
<xml-resolver.version>1.2</xml-resolver.version>
|
||||||
<xstream.version>1.4.5</xstream.version>
|
<xstream.version>1.4.5</xstream.version>
|
||||||
<!-- do not update necessary for lesson -->
|
<!-- do not update necessary for lesson -->
|
||||||
<zxcvbn.version>1.9.0</zxcvbn.version>
|
<zxcvbn.version>1.8.0</zxcvbn.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<version>9.5</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-exec</artifactId>
|
<artifactId>commons-exec</artifactId>
|
||||||
<version>1.4.0</version>
|
<version>1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.asciidoctor</groupId>
|
<groupId>org.asciidoctor</groupId>
|
||||||
@ -149,17 +200,6 @@
|
|||||||
<artifactId>jjwt</artifactId>
|
<artifactId>jjwt</artifactId>
|
||||||
<version>${jjwt.version}</version>
|
<version>${jjwt.version}</version>
|
||||||
</dependency>
|
</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>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
@ -191,13 +231,8 @@
|
|||||||
<version>${jquery.version}</version>
|
<version>${jquery.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.webjars</groupId>
|
<groupId>com.github.tomakehurst</groupId>
|
||||||
<artifactId>webjars-locator-core</artifactId>
|
<artifactId>wiremock</artifactId>
|
||||||
<version>${webjars-locator-core.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.wiremock</groupId>
|
|
||||||
<artifactId>wiremock-standalone</artifactId>
|
|
||||||
<version>${wiremock.version}</version>
|
<version>${wiremock.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -208,12 +243,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-compress</artifactId>
|
<artifactId>commons-compress</artifactId>
|
||||||
<version>${commons-compress.version}</version>
|
<version>1.23.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jruby</groupId>
|
<groupId>org.jruby</groupId>
|
||||||
<artifactId>jruby</artifactId>
|
<artifactId>jruby</artifactId>
|
||||||
<version>9.4.9.0</version>
|
<version>9.4.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
@ -232,26 +267,24 @@
|
|||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</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.3</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.xml.bind</groupId>
|
<groupId>javax.xml.bind</groupId>
|
||||||
<artifactId>jaxb-api</artifactId>
|
<artifactId>jaxb-api</artifactId>
|
||||||
<version>${jaxb.version}</version>
|
<version>${jaxb.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@ -261,10 +294,6 @@
|
|||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-core</artifactId>
|
<artifactId>flyway-core</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-database-hsqldb</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.asciidoctor</groupId>
|
<groupId>org.asciidoctor</groupId>
|
||||||
<artifactId>asciidoctorj</artifactId>
|
<artifactId>asciidoctorj</artifactId>
|
||||||
@ -281,10 +310,6 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-oauth2-client</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.thymeleaf.extras</groupId>
|
<groupId>org.thymeleaf.extras</groupId>
|
||||||
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
|
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
|
||||||
@ -321,15 +346,6 @@
|
|||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt</artifactId>
|
<artifactId>jjwt</artifactId>
|
||||||
</dependency>
|
</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>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
@ -358,10 +374,6 @@
|
|||||||
<groupId>org.webjars</groupId>
|
<groupId>org.webjars</groupId>
|
||||||
<artifactId>jquery</artifactId>
|
<artifactId>jquery</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.webjars</groupId>
|
|
||||||
<artifactId>webjars-locator-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.xml.bind</groupId>
|
<groupId>jakarta.xml.bind</groupId>
|
||||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||||
@ -371,12 +383,6 @@
|
|||||||
<artifactId>jaxb-impl</artifactId>
|
<artifactId>jaxb-impl</artifactId>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.terma</groupId>
|
|
||||||
<artifactId>javaniotcpproxy</artifactId>
|
|
||||||
<version>1.6</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@ -389,8 +395,10 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.wiremock</groupId>
|
<groupId>com.github.tomakehurst</groupId>
|
||||||
<artifactId>wiremock-standalone</artifactId>
|
<artifactId>wiremock</artifactId>
|
||||||
|
<version>3.0.0-beta-2</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.rest-assured</groupId>
|
<groupId>io.rest-assured</groupId>
|
||||||
@ -470,19 +478,10 @@
|
|||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<configuration>
|
<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>
|
<systemPropertyVariables>
|
||||||
<logback.configurationFile>${basedir}/src/test/resources/logback-test.xml</logback.configurationFile>
|
<logback.configurationFile>${basedir}/src/test/resources/logback-test.xml</logback.configurationFile>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
<argLine>-Xmx512m</argLine>
|
<argLine>-Xmx512m -Dwebgoatport=${webgoat.port} -Dwebwolfport=${webwolf.port}</argLine>
|
||||||
<includes>org/owasp/webgoat/*Test</includes>
|
<includes>org/owasp/webgoat/*Test</includes>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
@ -505,8 +504,6 @@
|
|||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>${maven-surefire-plugin.version}</version>
|
<version>${maven-surefire-plugin.version}</version>
|
||||||
<configuration>
|
<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
|
<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/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
|
--add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED
|
||||||
@ -514,6 +511,8 @@
|
|||||||
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED</argLine>
|
--add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED</argLine>
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>**/*IntegrationTest.java</exclude>
|
<exclude>**/*IntegrationTest.java</exclude>
|
||||||
|
<exclude>src/it/java</exclude>
|
||||||
|
<exclude>org/owasp/webgoat/*Test</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
@ -522,6 +521,7 @@
|
|||||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||||
<version>${checkstyle.version}</version>
|
<version>${checkstyle.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<encoding>UTF-8</encoding>
|
||||||
<consoleOutput>true</consoleOutput>
|
<consoleOutput>true</consoleOutput>
|
||||||
<failsOnError>true</failsOnError>
|
<failsOnError>true</failsOnError>
|
||||||
<configLocation>config/checkstyle/checkstyle.xml</configLocation>
|
<configLocation>config/checkstyle/checkstyle.xml</configLocation>
|
||||||
@ -532,7 +532,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.diffplug.spotless</groupId>
|
<groupId>com.diffplug.spotless</groupId>
|
||||||
<artifactId>spotless-maven-plugin</artifactId>
|
<artifactId>spotless-maven-plugin</artifactId>
|
||||||
<version>2.41.1</version>
|
<version>2.38.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<formats>
|
<formats>
|
||||||
<format>
|
<format>
|
||||||
@ -593,7 +593,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-enforcer-plugin</artifactId>
|
<artifactId>maven-enforcer-plugin</artifactId>
|
||||||
<version>3.5.0</version>
|
<version>3.3.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>restrict-log4j-versions</id>
|
<id>restrict-log4j-versions</id>
|
||||||
@ -617,6 +617,10 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>17</source>
|
||||||
|
<target>17</target>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
@ -646,15 +650,16 @@
|
|||||||
<portNames>
|
<portNames>
|
||||||
<portName>webgoat.port</portName>
|
<portName>webgoat.port</portName>
|
||||||
<portName>webwolf.port</portName>
|
<portName>webwolf.port</portName>
|
||||||
|
<portName>jmxPort</portName>
|
||||||
</portNames>
|
</portNames>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.honton.chas</groupId>
|
<groupId>com.bazaarvoice.maven.plugins</groupId>
|
||||||
<artifactId>process-exec-maven-plugin</artifactId>
|
<artifactId>process-exec-maven-plugin</artifactId>
|
||||||
<version>0.9.2</version>
|
<version>0.9</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>start-jar</id>
|
<id>start-jar</id>
|
||||||
@ -662,18 +667,8 @@
|
|||||||
<goal>start</goal>
|
<goal>start</goal>
|
||||||
</goals>
|
</goals>
|
||||||
<phase>pre-integration-test</phase>
|
<phase>pre-integration-test</phase>
|
||||||
|
|
||||||
<configuration>
|
<configuration>
|
||||||
<workingDir>${project.build.directory}</workingDir>
|
<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>
|
<arguments>
|
||||||
<argument>java</argument>
|
<argument>java</argument>
|
||||||
<argument>-jar</argument>
|
<argument>-jar</argument>
|
||||||
@ -681,6 +676,8 @@
|
|||||||
<argument>-Dwebgoat.server.directory=${java.io.tmpdir}/webgoat_${webgoat.port}</argument>
|
<argument>-Dwebgoat.server.directory=${java.io.tmpdir}/webgoat_${webgoat.port}</argument>
|
||||||
<argument>-Dwebgoat.user.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>-Dspring.main.banner-mode=off</argument>
|
||||||
|
<argument>-Dwebgoat.port=${webgoat.port}</argument>
|
||||||
|
<argument>-Dwebwolf.port=${webwolf.port}</argument>
|
||||||
<argument>--add-opens</argument>
|
<argument>--add-opens</argument>
|
||||||
<argument>java.base/java.lang=ALL-UNNAMED</argument>
|
<argument>java.base/java.lang=ALL-UNNAMED</argument>
|
||||||
<argument>--add-opens</argument>
|
<argument>--add-opens</argument>
|
||||||
@ -688,18 +685,25 @@
|
|||||||
<argument>--add-opens</argument>
|
<argument>--add-opens</argument>
|
||||||
<argument>java.base/java.lang.reflect=ALL-UNNAMED</argument>
|
<argument>java.base/java.lang.reflect=ALL-UNNAMED</argument>
|
||||||
<argument>--add-opens</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>java.desktop/java.beans=ALL-UNNAMED</argument>
|
||||||
<argument>--add-opens</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>java.base/sun.nio.ch=ALL-UNNAMED</argument>
|
||||||
<argument>--add-opens</argument>
|
<argument>--add-opens</argument>
|
||||||
<argument>java.base/java.io=ALL-UNNAMED</argument>
|
<argument>java.base/java.io=ALL-UNNAMED</argument>
|
||||||
<argument>--add-opens</argument>
|
<argument>--add-opens</argument>
|
||||||
<argument>java.base/java.util=ALL-UNNAMED</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>
|
<argument>${project.build.directory}/webgoat-${project.version}.jar</argument>
|
||||||
</arguments>
|
</arguments>
|
||||||
<waitForInterrupt>false</waitForInterrupt>
|
<waitForInterrupt>false</waitForInterrupt>
|
||||||
<waitAfterLaunch>${waittimeForServerStart}</waitAfterLaunch>
|
<healthcheckUrl>http://localhost:${webgoat.port}/WebGoat/actuator/health</healthcheckUrl>
|
||||||
<healthCheckUrl>http://127.0.0.1:${webgoat.port}${webgoat.context}login</healthCheckUrl>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
@ -724,6 +728,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.owasp</groupId>
|
<groupId>org.owasp</groupId>
|
||||||
<artifactId>dependency-check-maven</artifactId>
|
<artifactId>dependency-check-maven</artifactId>
|
||||||
|
<version>6.5.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<failBuildOnCVSS>7</failBuildOnCVSS>
|
<failBuildOnCVSS>7</failBuildOnCVSS>
|
||||||
<skipProvidedScope>false</skipProvidedScope>
|
<skipProvidedScope>false</skipProvidedScope>
|
||||||
@ -772,6 +777,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
|
<version>${jacoco.version}</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>before-unit-test</id>
|
<id>before-unit-test</id>
|
||||||
|
@ -12,10 +12,8 @@ Then see security settings and allow the file to run
|
|||||||
pip3 install virtualenv --user
|
pip3 install virtualenv --user
|
||||||
python3 -m virtualenv .venv
|
python3 -m virtualenv .venv
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
pip install --upgrade robotframework
|
pip install robotframework
|
||||||
pip install --upgrade robotframework-SeleniumLibrary
|
pip install robotframework-SeleniumLibrary
|
||||||
pip install --upgrade webdriver-manager
|
pip install webdriver-manager
|
||||||
brew upgrade
|
|
||||||
robot --variable HEADLESS:"0" --variable ENDPOINT:"http://127.0.0.1:8080/WebGoat" goat.robot
|
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,7 +2,6 @@
|
|||||||
Documentation Setup WebGoat Robotframework tests
|
Documentation Setup WebGoat Robotframework tests
|
||||||
Library SeleniumLibrary timeout=100 run_on_failure=Capture Page Screenshot
|
Library SeleniumLibrary timeout=100 run_on_failure=Capture Page Screenshot
|
||||||
Library String
|
Library String
|
||||||
Library OperatingSystem
|
|
||||||
|
|
||||||
Suite Setup Initial_Page ${ENDPOINT} ${BROWSER}
|
Suite Setup Initial_Page ${ENDPOINT} ${BROWSER}
|
||||||
Suite Teardown Close_Page
|
Suite Teardown Close_Page
|
||||||
@ -12,7 +11,7 @@ ${BROWSER} chrome
|
|||||||
${SLEEP} 100
|
${SLEEP} 100
|
||||||
${DELAY} 0.25
|
${DELAY} 0.25
|
||||||
${ENDPOINT} http://127.0.0.1:8080/WebGoat
|
${ENDPOINT} http://127.0.0.1:8080/WebGoat
|
||||||
${ENDPOINT_WOLF} http://127.0.0.1:9090/WebWolf
|
${ENDPOINT_WOLF} http://127.0.0.1:9090
|
||||||
${USERNAME} robotuser
|
${USERNAME} robotuser
|
||||||
${PASSWORD} password
|
${PASSWORD} password
|
||||||
${HEADLESS} ${FALSE}
|
${HEADLESS} ${FALSE}
|
||||||
@ -23,25 +22,22 @@ Initial_Page
|
|||||||
[Arguments] ${ENDPOINT} ${BROWSER}
|
[Arguments] ${ENDPOINT} ${BROWSER}
|
||||||
Log To Console Start WebGoat UI Testing
|
Log To Console Start WebGoat UI Testing
|
||||||
IF ${HEADLESS}
|
IF ${HEADLESS}
|
||||||
Open Browser ${ENDPOINT} ${BROWSER} options=add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'});add_argument("-headless");add_argument("--start-maximized") alias=webgoat
|
Open Browser ${ENDPOINT} ${BROWSER} options=add_argument("-headless");add_argument("--start-maximized");add_experimental_option('prefs', {'intl.accept_languages': 'en,en_US'}) alias=webgoat
|
||||||
ELSE
|
ELSE
|
||||||
Open Browser ${ENDPOINT} ${BROWSER} options=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'}) alias=webgoat
|
||||||
END
|
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
|
Switch Browser webgoat
|
||||||
Maximize Browser Window
|
Maximize Browser Window
|
||||||
Set Window Size ${1400} ${1000}
|
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
|
Switch Browser webwolf
|
||||||
Maximize Browser Window
|
Maximize Browser Window
|
||||||
Set Window Size ${1400} ${1000}
|
Set Window Size ${1400} ${1000}
|
||||||
Set Window Position ${500} ${0}
|
Set Window Position ${400} ${200}
|
||||||
Set Selenium Speed ${DELAY}
|
Set Selenium Speed ${DELAY}
|
||||||
|
|
||||||
Close_Page
|
Close_Page
|
||||||
@ -57,7 +53,6 @@ Close_Page
|
|||||||
*** Test Cases ***
|
*** Test Cases ***
|
||||||
|
|
||||||
Check_Initial_Page
|
Check_Initial_Page
|
||||||
[Tags] WebGoatTests
|
|
||||||
Switch Browser webgoat
|
Switch Browser webgoat
|
||||||
Page Should Contain Username
|
Page Should Contain Username
|
||||||
Click Button Sign in
|
Click Button Sign in
|
||||||
@ -65,7 +60,6 @@ Check_Initial_Page
|
|||||||
Click Link /WebGoat/registration
|
Click Link /WebGoat/registration
|
||||||
|
|
||||||
Check_Registration_Page
|
Check_Registration_Page
|
||||||
[Tags] WebGoatTests
|
|
||||||
Page Should Contain Username
|
Page Should Contain Username
|
||||||
Input Text username ${USERNAME}
|
Input Text username ${USERNAME}
|
||||||
Input Text password ${PASSWORD}
|
Input Text password ${PASSWORD}
|
||||||
@ -74,7 +68,6 @@ Check_Registration_Page
|
|||||||
Click Button Sign up
|
Click Button Sign up
|
||||||
|
|
||||||
Check_Welcome_Page
|
Check_Welcome_Page
|
||||||
[Tags] WebGoatTests
|
|
||||||
Page Should Contain WebGoat
|
Page Should Contain WebGoat
|
||||||
Go To ${ENDPOINT}/login
|
Go To ${ENDPOINT}/login
|
||||||
Page Should Contain Username
|
Page Should Contain Username
|
||||||
@ -84,7 +77,6 @@ Check_Welcome_Page
|
|||||||
Page Should Contain WebGoat
|
Page Should Contain WebGoat
|
||||||
|
|
||||||
Check_Menu_Page
|
Check_Menu_Page
|
||||||
[Tags] WebGoatTests
|
|
||||||
Click Element css=a[category='Introduction']
|
Click Element css=a[category='Introduction']
|
||||||
Click Element Introduction-WebGoat
|
Click Element Introduction-WebGoat
|
||||||
CLick Element Introduction-WebWolf
|
CLick Element Introduction-WebWolf
|
||||||
@ -101,29 +93,9 @@ Check_Menu_Page
|
|||||||
|
|
||||||
Check_WebWolf
|
Check_WebWolf
|
||||||
Switch Browser webwolf
|
Switch Browser webwolf
|
||||||
location should be ${ENDPOINT_WOLF}/login
|
location should be ${ENDPOINT_WOLF}/WebWolf
|
||||||
|
Go To ${ENDPOINT_WOLF}/mail
|
||||||
Input Text username ${USERNAME}
|
Input Text username ${USERNAME}
|
||||||
Input Text password ${PASSWORD}
|
Input Text password ${PASSWORD}
|
||||||
Click Button Sign In
|
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();
|
assignment2();
|
||||||
assignment3();
|
assignment3();
|
||||||
|
|
||||||
checkResults("MissingFunctionAC");
|
checkResults("/access-control");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignment3() {
|
private void assignment3() {
|
||||||
@ -25,7 +25,7 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("access-control/users-admin-fix"))
|
.get(url("/WebGoat/access-control/users-admin-fix"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(HttpStatus.SC_FORBIDDEN);
|
.statusCode(HttpStatus.SC_FORBIDDEN);
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
|||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body(String.format(userTemplate, this.getUser(), this.getUser()))
|
.body(String.format(userTemplate, this.getUser(), this.getUser()))
|
||||||
.post(url("access-control/users"))
|
.post(url("/WebGoat/access-control/users"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(HttpStatus.SC_OK);
|
.statusCode(HttpStatus.SC_OK);
|
||||||
|
|
||||||
@ -51,14 +51,15 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("access-control/users-admin-fix"))
|
.get(url("/WebGoat/access-control/users-admin-fix"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.jsonPath()
|
.jsonPath()
|
||||||
.get("find { it.username == \"Jerry\" }.userHash");
|
.get("find { it.username == \"Jerry\" }.userHash");
|
||||||
|
|
||||||
checkAssignment(url("access-control/user-hash-fix"), Map.of("userHash", userHash), true);
|
checkAssignment(
|
||||||
|
url("/WebGoat/access-control/user-hash-fix"), Map.of("userHash", userHash), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignment2() {
|
private void assignment2() {
|
||||||
@ -68,18 +69,18 @@ class AccessControlIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("access-control/users"))
|
.get(url("/WebGoat/access-control/users"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.jsonPath()
|
.jsonPath()
|
||||||
.get("find { it.username == \"Jerry\" }.userHash");
|
.get("find { it.username == \"Jerry\" }.userHash");
|
||||||
|
|
||||||
checkAssignment(url("access-control/user-hash"), Map.of("userHash", userHash), true);
|
checkAssignment(url("/WebGoat/access-control/user-hash"), Map.of("userHash", userHash), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignment1() {
|
private void assignment1() {
|
||||||
var params = Map.of("hiddenMenu1", "Users", "hiddenMenu2", "Config");
|
var params = Map.of("hiddenMenu1", "Users", "hiddenMenu2", "Config");
|
||||||
checkAssignment(url("access-control/hidden-menu"), params, true);
|
checkAssignment(url("/WebGoat/access-control/hidden-menu"), params, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,12 +64,12 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
public void init() {
|
public void init() {
|
||||||
startLesson("CSRF");
|
startLesson("CSRF");
|
||||||
webwolfFileDir = getWebWolfFileServerLocation();
|
webwolfFileDir = getWebWolfFileServerLocation();
|
||||||
uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("csrf/basic-get-flag")));
|
uploadTrickHtml("csrf3.html", trickHTML3.replace("WEBGOATURL", url("/csrf/basic-get-flag")));
|
||||||
uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("csrf/review")));
|
uploadTrickHtml("csrf4.html", trickHTML4.replace("WEBGOATURL", url("/csrf/review")));
|
||||||
uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("csrf/feedback/message")));
|
uploadTrickHtml("csrf7.html", trickHTML7.replace("WEBGOATURL", url("/csrf/feedback/message")));
|
||||||
uploadTrickHtml(
|
uploadTrickHtml(
|
||||||
"csrf8.html",
|
"csrf8.html",
|
||||||
trickHTML8.replace("WEBGOATURL", url("login")).replace("USERNAME", this.getUser()));
|
trickHTML8.replace("WEBGOATURL", url("/login")).replace("USERNAME", this.getUser()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
@ -86,7 +86,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
// logout();
|
// logout();
|
||||||
login(); // because old cookie got replaced and invalidated
|
login(); // because old cookie got replaced and invalidated
|
||||||
startLesson("CSRF", false);
|
startLesson("CSRF", false);
|
||||||
checkResults("CSRF");
|
checkResults("/csrf");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadTrickHtml(String htmlName, String htmlContent) throws IOException {
|
private void uploadTrickHtml(String htmlName, String htmlContent) throws IOException {
|
||||||
@ -103,7 +103,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.multiPart("file", htmlName, htmlContent.getBytes())
|
.multiPart("file", htmlName, htmlContent.getBytes())
|
||||||
.post(new WebWolfUrlBuilder().path("fileupload").build())
|
.post(webWolfUrl("/WebWolf/fileupload"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -118,7 +118,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(new WebWolfUrlBuilder().path("files/%s/%s", this.getUser(), htmlName).build())
|
.get(webWolfUrl("/files/" + this.getUser() + "/" + htmlName))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -136,7 +136,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
|
.header("Referer", webWolfUrl("/files/fake.html"))
|
||||||
.post(goatURL)
|
.post(goatURL)
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
@ -146,7 +146,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("confirmFlagVal", flag);
|
params.put("confirmFlagVal", flag);
|
||||||
checkAssignment(url("csrf/confirm-flag-1"), params, true);
|
checkAssignment(url("/WebGoat/csrf/confirm-flag-1"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignment4(String goatURL) {
|
private void checkAssignment4(String goatURL) {
|
||||||
@ -163,7 +163,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
|
.header("Referer", webWolfUrl("/files/fake.html"))
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(goatURL)
|
.post(goatURL)
|
||||||
.then()
|
.then()
|
||||||
@ -184,7 +184,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
|
.header("Referer", webWolfUrl("/files/fake.html"))
|
||||||
.contentType(ContentType.TEXT)
|
.contentType(ContentType.TEXT)
|
||||||
.body(
|
.body(
|
||||||
"{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is"
|
"{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is"
|
||||||
@ -198,7 +198,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("confirmFlagVal", flag);
|
params.put("confirmFlagVal", flag);
|
||||||
checkAssignment(url("csrf/feedback"), params, true);
|
checkAssignment(url("/WebGoat/csrf/feedback"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignment8(String goatURL) {
|
private void checkAssignment8(String goatURL) {
|
||||||
@ -217,7 +217,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
|
.header("Referer", webWolfUrl("/files/fake.html"))
|
||||||
.params(params)
|
.params(params)
|
||||||
.post(goatURL)
|
.post(goatURL)
|
||||||
.then()
|
.then()
|
||||||
@ -239,7 +239,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", newCookie)
|
.cookie("JSESSIONID", newCookie)
|
||||||
.post(url("csrf/login"))
|
.post(url("/csrf/login"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -253,16 +253,15 @@ public class CSRFIntegrationTest extends IntegrationTest {
|
|||||||
Overview[] assignments =
|
Overview[] assignments =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.relaxedHTTPSValidation()
|
.get(url("/service/lessonoverview.mvc"))
|
||||||
.get(url("service/lessonoverview.mvc/CSRF"))
|
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.jsonPath()
|
.jsonPath()
|
||||||
.getObject("$", Overview[].class);
|
.getObject("$", Overview[].class);
|
||||||
assertThat(assignments)
|
// assertThat(assignments)
|
||||||
.filteredOn(a -> a.getAssignment().getName().equals("CSRFLogin"))
|
// .filteredOn(a -> a.getAssignment().getName().equals("CSRFLogin"))
|
||||||
.extracting(o -> o.solved)
|
// .extracting(o -> o.solved)
|
||||||
.containsExactly(true);
|
// .containsExactly(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@ -22,7 +22,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("challenge/logo"))
|
.get(url("/WebGoat/challenge/logo"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -34,14 +34,14 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
params.put("username", "admin");
|
params.put("username", "admin");
|
||||||
params.put("password", "!!webgoat_admin_1234!!".replace("1234", pincode));
|
params.put("password", "!!webgoat_admin_1234!!".replace("1234", pincode));
|
||||||
|
|
||||||
checkAssignment(url("challenge/1"), params, true);
|
checkAssignment(url("/WebGoat/challenge/1"), params, true);
|
||||||
String result =
|
String result =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url("challenge/1"))
|
.post(url("/WebGoat/challenge/1"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -50,16 +50,16 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("flag", flag);
|
params.put("flag", flag);
|
||||||
checkAssignment(url("challenge/flag/1"), params, true);
|
checkAssignment(url("/WebGoat/challenge/flag"), params, true);
|
||||||
|
|
||||||
checkResults("Challenge1");
|
checkResults("/challenge/1");
|
||||||
|
|
||||||
List<String> capturefFlags =
|
List<String> capturefFlags =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("scoreboard-data"))
|
.get(url("/WebGoat/scoreboard-data"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -83,7 +83,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url("challenge/5"))
|
.post(url("/WebGoat/challenge/5"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -92,16 +92,16 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("flag", flag);
|
params.put("flag", flag);
|
||||||
checkAssignment(url("challenge/flag/5"), params, true);
|
checkAssignment(url("/WebGoat/challenge/flag"), params, true);
|
||||||
|
|
||||||
checkResults("Challenge5");
|
checkResults("/challenge/5");
|
||||||
|
|
||||||
List<String> capturefFlags =
|
List<String> capturefFlags =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("scoreboard-data"))
|
.get(url("/WebGoat/scoreboard-data"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -120,19 +120,19 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("challenge/7/.git"))
|
.get(url("/WebGoat/challenge/7/.git"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
|
|
||||||
// Should email WebWolf inbox this should give a hint to the link being static
|
// Should send an email to WebWolf inbox this should give a hint to the link being static
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams("email", getUser() + "@webgoat.org")
|
.formParams("email", getUser() + "@webgoat.org")
|
||||||
.post(url("challenge/7"))
|
.post(url("/WebGoat/challenge/7"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -144,7 +144,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(new WebWolfUrlBuilder().path("mail").build())
|
.get(webWolfUrl("/mail"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -158,13 +158,13 @@ public class ChallengeIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("challenge/7/reset-password/{link}"), "375afe1104f4a487a73823c50a9292a2")
|
.get(url("/challenge/7/reset-password/{link}"), "375afe1104f4a487a73823c50a9292a2")
|
||||||
.then()
|
.then()
|
||||||
.statusCode(HttpStatus.ACCEPTED.value())
|
.statusCode(HttpStatus.ACCEPTED.value())
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
|
|
||||||
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
|
||||||
checkAssignment(url("challenge/flag/7"), Map.of("flag", flag), true);
|
checkAssignment(url("/WebGoat/challenge/flag"), Map.of("flag", flag), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
checkAssignmentDefaults();
|
checkAssignmentDefaults();
|
||||||
|
|
||||||
checkResults("Cryptography");
|
checkResults("/crypto");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignment2() {
|
private void checkAssignment2() {
|
||||||
@ -52,7 +52,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("crypto/encoding/basic"))
|
.get(url("/crypto/encoding/basic"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
@ -64,7 +64,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("answer_user", answer_user);
|
params.put("answer_user", answer_user);
|
||||||
params.put("answer_pwd", answer_pwd);
|
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() {
|
private void checkAssignment3() {
|
||||||
@ -72,7 +72,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("answer_pwd1", answer_1);
|
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 {
|
private void checkAssignment4() throws NoSuchAlgorithmException {
|
||||||
@ -82,7 +82,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("crypto/hashing/md5"))
|
.get(url("/crypto/hashing/md5"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
@ -92,7 +92,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("crypto/hashing/sha256"))
|
.get(url("/crypto/hashing/sha256"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
@ -112,7 +112,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("answer_pwd1", answer_1);
|
params.put("answer_pwd1", answer_1);
|
||||||
params.put("answer_pwd2", answer_2);
|
params.put("answer_pwd2", answer_2);
|
||||||
checkAssignment(url("crypto/hashing"), params, true);
|
checkAssignment(url("/WebGoat/crypto/hashing"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignmentSigning() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
private void checkAssignmentSigning() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||||
@ -122,7 +122,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("crypto/signing/getprivate"))
|
.get(url("/crypto/signing/getprivate"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.asString();
|
.asString();
|
||||||
@ -135,7 +135,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("modulus", modulus);
|
params.put("modulus", modulus);
|
||||||
params.put("signature", signature);
|
params.put("signature", signature);
|
||||||
checkAssignment(url("crypto/signing/verify"), params, true);
|
checkAssignment(url("/crypto/signing/verify"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAssignmentDefaults() {
|
private void checkAssignmentDefaults() {
|
||||||
@ -151,6 +151,6 @@ public class CryptoIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("secretText", text);
|
params.put("secretText", text);
|
||||||
params.put("secretFileName", "default_secret");
|
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(
|
params.put(
|
||||||
"token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")));
|
"token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")));
|
||||||
}
|
}
|
||||||
checkAssignment(url("InsecureDeserialization/task"), params, true);
|
checkAssignment(url("/WebGoat/InsecureDeserialization/task"), params, true);
|
||||||
|
|
||||||
checkResults("InsecureDeserialization");
|
checkResults("/InsecureDeserialization/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,17 +31,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put("magic_num", "33");
|
params.put("magic_num", "33");
|
||||||
checkAssignment(url("HttpBasics/attack2"), params, true);
|
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
|
@Test
|
||||||
@ -61,7 +51,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
.path("lessonCompleted"),
|
.path("lessonCompleted"),
|
||||||
CoreMatchers.is(true));
|
CoreMatchers.is(true));
|
||||||
|
|
||||||
checkResults("HttpProxies");
|
checkResults("/HttpProxies/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -82,8 +72,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put(
|
params.put(
|
||||||
"question_3_solution",
|
"question_3_solution",
|
||||||
"Solution 2: The systems security is compromised even if only one goal is harmed.");
|
"Solution 2: The systems security is compromised even if only one goal is harmed.");
|
||||||
checkAssignment(url("cia/quiz"), params, true);
|
checkAssignment(url("/WebGoat/cia/quiz"), params, true);
|
||||||
checkResults("CIA");
|
checkResults("/cia/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -105,8 +95,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("payload", solution);
|
params.put("payload", solution);
|
||||||
checkAssignment(url("VulnerableComponents/attack1"), params, true);
|
checkAssignment(url("/WebGoat/VulnerableComponents/attack1"), params, true);
|
||||||
checkResults("VulnerableComponents");
|
checkResults("/VulnerableComponents/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,8 +107,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("username", "CaptainJack");
|
params.put("username", "CaptainJack");
|
||||||
params.put("password", "BlackPearl");
|
params.put("password", "BlackPearl");
|
||||||
checkAssignment(url("InsecureLogin/task"), params, true);
|
checkAssignment(url("/WebGoat/InsecureLogin/task"), params, true);
|
||||||
checkResults("InsecureLogin");
|
checkResults("/InsecureLogin/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -127,8 +117,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("password", "ajnaeliclm^&&@kjn.");
|
params.put("password", "ajnaeliclm^&&@kjn.");
|
||||||
checkAssignment(url("SecurePasswords/assignment"), params, true);
|
checkAssignment(url("/WebGoat/SecurePasswords/assignment"), params, true);
|
||||||
checkResults("SecurePasswords");
|
checkResults("SecurePasswords/");
|
||||||
|
|
||||||
startLesson("AuthBypass");
|
startLesson("AuthBypass");
|
||||||
params.clear();
|
params.clear();
|
||||||
@ -137,8 +127,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put("jsEnabled", "1");
|
params.put("jsEnabled", "1");
|
||||||
params.put("verifyMethod", "SEC_QUESTIONS");
|
params.put("verifyMethod", "SEC_QUESTIONS");
|
||||||
params.put("userId", "12309746");
|
params.put("userId", "12309746");
|
||||||
checkAssignment(url("auth-bypass/verify-account"), params, true);
|
checkAssignment(url("/WebGoat/auth-bypass/verify-account"), params, true);
|
||||||
checkResults("AuthBypass");
|
checkResults("/auth-bypass/");
|
||||||
|
|
||||||
startLesson("HttpProxies");
|
startLesson("HttpProxies");
|
||||||
MatcherAssert.assertThat(
|
MatcherAssert.assertThat(
|
||||||
@ -148,13 +138,14 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("x-request-intercepted", "true")
|
.header("x-request-intercepted", "true")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
|
.get(
|
||||||
|
url("/WebGoat/HttpProxies/intercept-request?changeMe=Requests are tampered easily"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.path("lessonCompleted"),
|
.path("lessonCompleted"),
|
||||||
CoreMatchers.is(true));
|
CoreMatchers.is(true));
|
||||||
checkResults("HttpProxies");
|
checkResults("/HttpProxies/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -174,7 +165,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
.header("webgoat-requested-by", "dom-xss-vuln")
|
.header("webgoat-requested-by", "dom-xss-vuln")
|
||||||
.header("X-Requested-With", "XMLHttpRequest")
|
.header("X-Requested-With", "XMLHttpRequest")
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url("CrossSiteScripting/phone-home-xss"))
|
.post(url("/WebGoat/CrossSiteScripting/phone-home-xss"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -183,14 +174,14 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("successMessage", secretNumber);
|
params.put("successMessage", secretNumber);
|
||||||
checkAssignment(url("ChromeDevTools/dummy"), params, true);
|
checkAssignment(url("/WebGoat/ChromeDevTools/dummy"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("number", "24");
|
params.put("number", "24");
|
||||||
params.put("network_num", "24");
|
params.put("network_num", "24");
|
||||||
checkAssignment(url("ChromeDevTools/network"), params, true);
|
checkAssignment(url("/WebGoat/ChromeDevTools/network"), params, true);
|
||||||
|
|
||||||
checkResults("ChromeDevTools");
|
checkResults("/ChromeDevTools/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -203,8 +194,8 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put("jsEnabled", "1");
|
params.put("jsEnabled", "1");
|
||||||
params.put("verifyMethod", "SEC_QUESTIONS");
|
params.put("verifyMethod", "SEC_QUESTIONS");
|
||||||
params.put("userId", "12309746");
|
params.put("userId", "12309746");
|
||||||
checkAssignment(url("auth-bypass/verify-account"), params, true);
|
checkAssignment(url("/auth-bypass/verify-account"), params, true);
|
||||||
checkResults("AuthBypass");
|
checkResults("/auth-bypass/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -214,7 +205,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.clear();
|
params.clear();
|
||||||
params.put("param1", "secr37Value");
|
params.put("param1", "secr37Value");
|
||||||
params.put("param2", "Main");
|
params.put("param2", "Main");
|
||||||
checkAssignment(url("lesson-template/sample-attack"), params, true);
|
checkAssignment(url("/lesson-template/sample-attack"), params, true);
|
||||||
checkResults("LessonTemplate");
|
checkResults("/lesson-template/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,11 @@ import static org.junit.jupiter.api.DynamicTest.dynamicTest;
|
|||||||
|
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.hamcrest.CoreMatchers;
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
@ -17,6 +19,7 @@ import org.junit.jupiter.api.TestFactory;
|
|||||||
public class IDORIntegrationTest extends IntegrationTest {
|
public class IDORIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
@SneakyThrows
|
||||||
public void init() {
|
public void init() {
|
||||||
startLesson("IDOR");
|
startLesson("IDOR");
|
||||||
}
|
}
|
||||||
@ -24,63 +27,56 @@ public class IDORIntegrationTest extends IntegrationTest {
|
|||||||
@TestFactory
|
@TestFactory
|
||||||
Iterable<DynamicTest> testIDORLesson() {
|
Iterable<DynamicTest> testIDORLesson() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
dynamicTest("assignment 2 - login", this::loginIDOR),
|
dynamicTest("login", () -> loginIDOR()), dynamicTest("profile", () -> profile()));
|
||||||
dynamicTest("profile", this::profile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void shutdown() {
|
public void shutdown() throws IOException {
|
||||||
checkResults("IDOR");
|
checkResults("/IDOR");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginIDOR() {
|
private void loginIDOR() throws IOException {
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.clear();
|
||||||
params.put("username", "tom");
|
params.put("username", "tom");
|
||||||
params.put("password", "cat");
|
params.put("password", "cat");
|
||||||
|
|
||||||
checkAssignment(url("IDOR/login"), params, true);
|
checkAssignment(url("/WebGoat/IDOR/login"), params, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void profile() {
|
private void profile() {
|
||||||
|
|
||||||
// View profile - assignment 3a
|
|
||||||
MatcherAssert.assertThat(
|
MatcherAssert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("IDOR/profile"))
|
.get(url("/WebGoat/IDOR/profile"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.path("userId"),
|
.path("userId"),
|
||||||
CoreMatchers.is("2342384"));
|
CoreMatchers.is("2342384"));
|
||||||
|
|
||||||
// Show difference - assignment 3b
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.clear();
|
||||||
params.put("attributes", "userId,role");
|
params.put("attributes", "userId,role");
|
||||||
checkAssignment(url("IDOR/diff-attributes"), params, true);
|
checkAssignment(url("/WebGoat/IDOR/diff-attributes"), params, true);
|
||||||
|
|
||||||
// View profile another way - assignment 4
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("url", "WebGoat/IDOR/profile/2342384");
|
params.put("url", "WebGoat/IDOR/profile/2342384");
|
||||||
checkAssignment(url("IDOR/profile/alt-path"), params, true);
|
checkAssignment(url("/WebGoat/IDOR/profile/alt-path"), params, true);
|
||||||
|
|
||||||
// assignment 5a
|
|
||||||
MatcherAssert.assertThat(
|
MatcherAssert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("IDOR/profile/2342388"))
|
.get(url("/WebGoat/IDOR/profile/2342388"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.path("lessonCompleted"),
|
.path("lessonCompleted"),
|
||||||
CoreMatchers.is(true));
|
CoreMatchers.is(true));
|
||||||
|
|
||||||
// assignment 5b
|
|
||||||
MatcherAssert.assertThat(
|
MatcherAssert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
@ -90,7 +86,7 @@ public class IDORIntegrationTest extends IntegrationTest {
|
|||||||
.body(
|
.body(
|
||||||
"{\"role\":\"1\", \"color\":\"red\", \"size\":\"large\", \"name\":\"Buffalo Bill\","
|
"{\"role\":\"1\", \"color\":\"red\", \"size\":\"large\", \"name\":\"Buffalo Bill\","
|
||||||
+ " \"userId\":\"2342388\"}")
|
+ " \"userId\":\"2342388\"}")
|
||||||
.put(url("IDOR/profile/2342388"))
|
.put(url("/WebGoat/IDOR/profile/2342388"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
|
@ -3,9 +3,9 @@ package org.owasp.webgoat;
|
|||||||
import static io.restassured.RestAssured.given;
|
import static io.restassured.RestAssured.given;
|
||||||
|
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import io.restassured.filter.log.LogDetail;
|
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.hamcrest.CoreMatchers;
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
@ -15,81 +15,36 @@ import org.springframework.http.HttpStatus;
|
|||||||
|
|
||||||
public abstract class IntegrationTest {
|
public abstract class IntegrationTest {
|
||||||
|
|
||||||
private static String webGoatPort = System.getenv().getOrDefault("WEBGOAT_PORT", "8080");
|
private static String webGoatPort = Objects.requireNonNull(System.getProperty("webgoatport"));
|
||||||
@Getter private static String webWolfPort = System.getenv().getOrDefault("WEBWOLF_PORT", "9090");
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static String webWolfHost = System.getenv().getOrDefault("WEBWOLF_HOST", "127.0.0.1");
|
private static String webWolfPort = Objects.requireNonNull(System.getProperty("webwolfport"));
|
||||||
|
|
||||||
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 webGoatCookie;
|
||||||
@Getter private String webWolfCookie;
|
@Getter private String webWolfCookie;
|
||||||
@Getter private final String user = "webgoat";
|
@Getter private final String user = "webgoat";
|
||||||
|
|
||||||
protected String url(String url) {
|
protected String url(String url) {
|
||||||
return "http://localhost:%s%s%s".formatted(webGoatPort, webGoatContext, url);
|
url = url.replaceFirst("/WebGoat/", "");
|
||||||
|
url = url.replaceFirst("/WebGoat", "");
|
||||||
|
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
|
||||||
|
return webgoatUrl + url;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class WebWolfUrlBuilder {
|
protected String webWolfUrl(String url) {
|
||||||
|
url = url.replaceFirst("/WebWolf/", "");
|
||||||
private boolean attackMode = false;
|
url = url.replaceFirst("/WebWolf", "");
|
||||||
private String path = null;
|
url = url.startsWith("/") ? url.replaceFirst("/", "") : url;
|
||||||
|
return webWolfUrl + url;
|
||||||
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
|
@BeforeEach
|
||||||
public void login() {
|
public void login() {
|
||||||
login("webgoat");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void login(String user) {
|
|
||||||
String location =
|
String location =
|
||||||
given()
|
given()
|
||||||
.when()
|
.when()
|
||||||
@ -98,8 +53,6 @@ public abstract class IntegrationTest {
|
|||||||
.formParam("password", "password")
|
.formParam("password", "password")
|
||||||
.post(url("login"))
|
.post(url("login"))
|
||||||
.then()
|
.then()
|
||||||
.log()
|
|
||||||
.ifValidationFails(LogDetail.ALL) // Log the response details if validation fails
|
|
||||||
.cookie("JSESSIONID")
|
.cookie("JSESSIONID")
|
||||||
.statusCode(302)
|
.statusCode(302)
|
||||||
.extract()
|
.extract()
|
||||||
@ -140,7 +93,7 @@ public abstract class IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.formParam("username", user)
|
.formParam("username", user)
|
||||||
.formParam("password", "password")
|
.formParam("password", "password")
|
||||||
.post(new WebWolfUrlBuilder().path("login").build())
|
.post(webWolfUrl("login"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(302)
|
.statusCode(302)
|
||||||
.cookie("WEBWOLFSESSION")
|
.cookie("WEBWOLFSESSION")
|
||||||
@ -171,7 +124,7 @@ public abstract class IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("service/restartlesson.mvc/%s.lesson".formatted(lessonName)))
|
.get(url("service/restartlesson.mvc"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
}
|
}
|
||||||
@ -207,18 +160,23 @@ public abstract class IntegrationTest {
|
|||||||
CoreMatchers.is(expectedResult));
|
CoreMatchers.is(expectedResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkResults(String lesson) {
|
// TODO is prefix useful? not every lesson endpoint needs to start with a certain prefix (they are
|
||||||
var result =
|
// only required to be in the same package)
|
||||||
|
public void checkResults(String prefix) {
|
||||||
|
checkResults();
|
||||||
|
|
||||||
|
MatcherAssert.assertThat(
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("service/lessonoverview.mvc/%s.lesson".formatted(lesson)))
|
.get(url("service/lessonoverview.mvc"))
|
||||||
.andReturn();
|
.then()
|
||||||
|
.statusCode(200)
|
||||||
MatcherAssert.assertThat(
|
.extract()
|
||||||
result.then().statusCode(200).extract().jsonPath().getList("solved"),
|
.jsonPath()
|
||||||
CoreMatchers.everyItem(CoreMatchers.is(true)));
|
.getList("assignment.path"),
|
||||||
|
CoreMatchers.everyItem(CoreMatchers.startsWith(prefix)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkResults() {
|
public void checkResults() {
|
||||||
@ -273,7 +231,7 @@ public abstract class IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(new WebWolfUrlBuilder().path("file-server-location").build())
|
.get(webWolfUrl("/file-server-location"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -288,7 +246,7 @@ public abstract class IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("server-directory"))
|
.get(url("/server-directory"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -301,7 +259,7 @@ public abstract class IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.delete(new WebWolfUrlBuilder().path("mail").build())
|
.delete(webWolfUrl("/mail"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(HttpStatus.ACCEPTED.value());
|
.statusCode(HttpStatus.ACCEPTED.value());
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,8 @@ import io.jsonwebtoken.impl.TextCodec;
|
|||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.security.KeyPair;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.interfaces.RSAPublicKey;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
@ -25,15 +23,13 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.hamcrest.CoreMatchers;
|
||||||
import org.hamcrest.MatcherAssert;
|
import org.hamcrest.MatcherAssert;
|
||||||
import org.jose4j.jwk.JsonWebKeySet;
|
|
||||||
import org.jose4j.jwk.RsaJsonWebKey;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint;
|
import org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint;
|
||||||
|
|
||||||
public class JWTLessonIntegrationTest extends IntegrationTest {
|
public class JWTLessonIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void solveAssignment() throws IOException, NoSuchAlgorithmException {
|
public void solveAssignment() throws IOException, InvalidKeyException, NoSuchAlgorithmException {
|
||||||
startLesson("JWT");
|
startLesson("JWT");
|
||||||
|
|
||||||
decodingToken();
|
decodingToken();
|
||||||
@ -44,16 +40,15 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
buyAsTom();
|
buyAsTom();
|
||||||
|
|
||||||
deleteTomThroughKidClaim();
|
deleteTom();
|
||||||
|
|
||||||
deleteTomThroughJkuClaim();
|
|
||||||
|
|
||||||
quiz();
|
quiz();
|
||||||
|
|
||||||
checkResults("JWT");
|
checkResults("/JWT/");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateToken(String key) {
|
private String generateToken(String key) {
|
||||||
|
|
||||||
return Jwts.builder()
|
return Jwts.builder()
|
||||||
.setIssuer("WebGoat Token Builder")
|
.setIssuer("WebGoat Token Builder")
|
||||||
.setAudience("webgoat.org")
|
.setAudience("webgoat.org")
|
||||||
@ -86,7 +81,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParam("jwt-encode-user", "user")
|
.formParam("jwt-encode-user", "user")
|
||||||
.post(url("JWT/decode"))
|
.post(url("/WebGoat/JWT/decode"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -94,14 +89,14 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
CoreMatchers.is(true));
|
CoreMatchers.is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findPassword() {
|
private void findPassword() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
|
||||||
|
|
||||||
String accessToken =
|
String accessToken =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("JWT/secret/gettoken"))
|
.get(url("/WebGoat/JWT/secret/gettoken"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -115,7 +110,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParam("token", generateToken(secret))
|
.formParam("token", generateToken(secret))
|
||||||
.post(url("JWT/secret"))
|
.post(url("/WebGoat/JWT/secret"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -129,7 +124,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.get(url("JWT/votings/login?user=Tom"))
|
.get(url("/WebGoat/JWT/votings/login?user=Tom"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.cookie("access_token");
|
.cookie("access_token");
|
||||||
@ -162,7 +157,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.cookie("access_token", replacedToken)
|
.cookie("access_token", replacedToken)
|
||||||
.post(url("JWT/votings"))
|
.post(url("/WebGoat/JWT/votings"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -203,7 +198,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.header("Authorization", "Bearer " + replacedToken)
|
.header("Authorization", "Bearer " + replacedToken)
|
||||||
.post(url("JWT/refresh/checkout"))
|
.post(url("/WebGoat/JWT/refresh/checkout"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -211,7 +206,8 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
CoreMatchers.is(true));
|
CoreMatchers.is(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteTomThroughKidClaim() {
|
private void deleteTom() {
|
||||||
|
|
||||||
Map<String, Object> header = new HashMap();
|
Map<String, Object> header = new HashMap();
|
||||||
header.put(Header.TYPE, Header.JWT_TYPE);
|
header.put(Header.TYPE, Header.JWT_TYPE);
|
||||||
header.put(
|
header.put(
|
||||||
@ -236,57 +232,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.post(url("JWT/kid/delete?token=" + token))
|
.post(url("/WebGoat/JWT/final/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()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -299,6 +245,6 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
|
|||||||
params.put("question_0_solution", "Solution 1");
|
params.put("question_0_solution", "Solution 1");
|
||||||
params.put("question_1_solution", "Solution 2");
|
params.put("question_1_solution", "Solution 2");
|
||||||
|
|
||||||
checkAssignment(url("JWT/quiz"), params, true);
|
checkAssignment(url("/WebGoat/JWT/quiz"), params, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,7 @@ public class LabelAndHintIntegrationTest extends IntegrationTest {
|
|||||||
checkLang(propsDefault, "nl");
|
checkLang(propsDefault, "nl");
|
||||||
checkLang(propsDefault, "de");
|
checkLang(propsDefault, "de");
|
||||||
checkLang(propsDefault, "fr");
|
checkLang(propsDefault, "fr");
|
||||||
|
checkLang(propsDefault, "ru");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Properties getProperties(String lang) {
|
private Properties getProperties(String lang) {
|
||||||
|
@ -11,13 +11,12 @@ import org.junit.jupiter.api.AfterEach;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DynamicTest;
|
import org.junit.jupiter.api.DynamicTest;
|
||||||
import org.junit.jupiter.api.TestFactory;
|
import org.junit.jupiter.api.TestFactory;
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
|
|
||||||
public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void init() {
|
public void init() {
|
||||||
startLesson("PasswordReset");
|
startLesson("/PasswordReset");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestFactory
|
@TestFactory
|
||||||
@ -69,6 +68,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
// WebWolf
|
// WebWolf
|
||||||
var link = getPasswordResetLinkFromLandingPage();
|
var link = getPasswordResetLinkFromLandingPage();
|
||||||
|
|
||||||
// WebGoat
|
// WebGoat
|
||||||
changePassword(link);
|
changePassword(link);
|
||||||
checkAssignment(
|
checkAssignment(
|
||||||
@ -85,7 +85,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(new WebWolfUrlBuilder().path("mail").build())
|
.get(webWolfUrl("/WebWolf/mail"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -99,7 +99,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
|||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
// this will run only once after the list of dynamic tests has run, this is to test if the
|
// this will run only once after the list of dynamic tests has run, this is to test if the
|
||||||
// lesson is marked complete
|
// lesson is marked complete
|
||||||
checkResults("PasswordReset");
|
checkResults("/PasswordReset");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changePassword(String link) {
|
private void changePassword(String link) {
|
||||||
@ -119,7 +119,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(new WebWolfUrlBuilder().path("requests").build())
|
.get(webWolfUrl("/WebWolf/requests"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -136,7 +136,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
|
|||||||
private void clickForgotEmailLink(String user) {
|
private void clickForgotEmailLink(String user) {
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.header(HttpHeaders.HOST, String.format("%s:%s", getWebWolfHost(), getWebWolfPort()))
|
.header("host", String.format("%s:%s", "localhost", getWebWolfPort()))
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams("email", user)
|
.formParams("email", user)
|
||||||
|
@ -55,7 +55,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.multiPart("uploadedFile", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
.multiPart("uploadedFile", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
||||||
.param("fullName", "../John Doe")
|
.param("fullName", "../John Doe")
|
||||||
.post(url("PathTraversal/profile-upload"))
|
.post(url("/WebGoat/PathTraversal/profile-upload"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -71,7 +71,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.multiPart("uploadedFileFix", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
.multiPart("uploadedFileFix", "test.jpg", Files.readAllBytes(fileToUpload.toPath()))
|
||||||
.param("fullNameFix", "..././John Doe")
|
.param("fullNameFix", "..././John Doe")
|
||||||
.post(url("PathTraversal/profile-upload-fix"))
|
.post(url("/WebGoat/PathTraversal/profile-upload-fix"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -89,7 +89,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
"uploadedFileRemoveUserInput",
|
"uploadedFileRemoveUserInput",
|
||||||
"../test.jpg",
|
"../test.jpg",
|
||||||
Files.readAllBytes(fileToUpload.toPath()))
|
Files.readAllBytes(fileToUpload.toPath()))
|
||||||
.post(url("PathTraversal/profile-upload-remove-user-input"))
|
.post(url("/WebGoat/PathTraversal/profile-upload-remove-user-input"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -98,7 +98,7 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void assignment4() throws IOException {
|
private void assignment4() throws IOException {
|
||||||
var uri = "PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret";
|
var uri = "/WebGoat/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret";
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.urlEncodingEnabled(false)
|
.urlEncodingEnabled(false)
|
||||||
.when()
|
.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"));
|
.body(CoreMatchers.is("You found it submit the SHA-512 hash of your username as answer"));
|
||||||
|
|
||||||
checkAssignment(
|
checkAssignment(
|
||||||
url("PathTraversal/random"),
|
url("/WebGoat/PathTraversal/random"),
|
||||||
Map.of("secret", Sha512DigestUtils.shaHex(this.getUser())),
|
Map.of("secret", Sha512DigestUtils.shaHex(this.getUser())),
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
@ -133,10 +133,8 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.multiPart("uploadedFileZipSlip", "upload.zip", Files.readAllBytes(zipFile.toPath()))
|
.multiPart("uploadedFileZipSlip", "upload.zip", Files.readAllBytes(zipFile.toPath()))
|
||||||
.post(url("PathTraversal/zip-slip"))
|
.post(url("/WebGoat/PathTraversal/zip-slip"))
|
||||||
.then()
|
.then()
|
||||||
.log()
|
|
||||||
.all()
|
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
.path("lessonCompleted"),
|
.path("lessonCompleted"),
|
||||||
@ -147,6 +145,6 @@ class PathTraversalIT extends IntegrationTest {
|
|||||||
void shutdown() {
|
void shutdown() {
|
||||||
// this will run only once after the list of dynamic tests has run, this is to test if the
|
// this will run only once after the list of dynamic tests has run, this is to test if the
|
||||||
// lesson is marked complete
|
// lesson is marked complete
|
||||||
checkResults("PathTraversal");
|
checkResults("/PathTraversal");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ public class ProgressRaceConditionIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.formParams(Map.of("flag", "test"))
|
.formParams(Map.of("flag", "test"))
|
||||||
.post(url("challenge/flag/1"));
|
.post(url("/challenge/flag"));
|
||||||
};
|
};
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_PARALLEL_THREADS);
|
ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_PARALLEL_THREADS);
|
||||||
List<? extends Callable<Response>> flagCalls =
|
List<? extends Callable<Response>> flagCalls =
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.owasp.webgoat;
|
package org.owasp.webgoat;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -7,19 +8,19 @@ import org.junit.jupiter.api.Test;
|
|||||||
public class SSRFIntegrationTest extends IntegrationTest {
|
public class SSRFIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runTests() {
|
public void runTests() throws IOException {
|
||||||
startLesson("SSRF");
|
startLesson("SSRF");
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("url", "images/jerry.png");
|
params.put("url", "images/jerry.png");
|
||||||
|
|
||||||
checkAssignment(url("SSRF/task1"), params, true);
|
checkAssignment(url("/WebGoat/SSRF/task1"), params, true);
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("url", "http://ifconfig.pro");
|
params.put("url", "http://ifconfig.pro");
|
||||||
|
|
||||||
checkAssignment(url("SSRF/task2"), params, true);
|
checkAssignment(url("/WebGoat/SSRF/task2"), params, true);
|
||||||
|
|
||||||
checkResults("SSRF");
|
checkResults("/SSRF/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
*/
|
*/
|
||||||
class SessionManagementIT extends IntegrationTest {
|
class SessionManagementIT extends IntegrationTest {
|
||||||
|
|
||||||
private static final String HIJACK_LOGIN_CONTEXT_PATH = "HijackSession/login";
|
private static final String HIJACK_LOGIN_CONTEXT_PATH = "/WebGoat/HijackSession/login";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void hijackSessionTest() {
|
void hijackSessionTest() {
|
||||||
|
@ -16,27 +16,27 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
|
|||||||
params.put("password_reg", "password");
|
params.put("password_reg", "password");
|
||||||
params.put("email_reg", "someone@microsoft.com");
|
params.put("email_reg", "someone@microsoft.com");
|
||||||
params.put("confirm_password", "password");
|
params.put("confirm_password", "password");
|
||||||
checkAssignmentWithPUT(url("SqlInjectionAdvanced/challenge"), params, true);
|
checkAssignmentWithPUT(url("/WebGoat/SqlInjectionAdvanced/challenge"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("username_login", "tom");
|
params.put("username_login", "tom");
|
||||||
params.put("password_login", "thisisasecretfortomonly");
|
params.put("password_login", "thisisasecretfortomonly");
|
||||||
checkAssignment(url("SqlInjectionAdvanced/challenge_Login"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/challenge_Login"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
|
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
|
||||||
checkAssignment(url("SqlInjectionAdvanced/attack6a"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
"userid_6a",
|
"userid_6a",
|
||||||
"Smith' union select userid,user_name, user_name,user_name,password,cookie,userid from"
|
"Smith' union select userid,user_name, user_name,user_name,password,cookie,userid from"
|
||||||
+ " user_system_data --");
|
+ " user_system_data --");
|
||||||
checkAssignment(url("SqlInjectionAdvanced/attack6a"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("userid_6b", "passW0rD");
|
params.put("userid_6b", "passW0rD");
|
||||||
checkAssignment(url("SqlInjectionAdvanced/attack6b"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/attack6b"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
@ -54,8 +54,8 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
|
|||||||
params.put(
|
params.put(
|
||||||
"question_4_solution",
|
"question_4_solution",
|
||||||
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
|
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
|
||||||
checkAssignment(url("SqlInjectionAdvanced/quiz"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjectionAdvanced/quiz"), params, true);
|
||||||
|
|
||||||
checkResults("SqlInjectionAdvanced");
|
checkResults("/SqlInjectionAdvanced/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,45 +34,45 @@ public class SqlInjectionLessonIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("query", sql_2);
|
params.put("query", sql_2);
|
||||||
checkAssignment(url("SqlInjection/attack2"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/attack2"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("query", sql_3);
|
params.put("query", sql_3);
|
||||||
checkAssignment(url("SqlInjection/attack3"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/attack3"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("query", sql_4_add);
|
params.put("query", sql_4_add);
|
||||||
checkAssignment(url("SqlInjection/attack4"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/attack4"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("query", sql_5);
|
params.put("query", sql_5);
|
||||||
checkAssignment(url("SqlInjection/attack5"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/attack5"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("operator", sql_9_operator);
|
params.put("operator", sql_9_operator);
|
||||||
params.put("account", sql_9_account);
|
params.put("account", sql_9_account);
|
||||||
params.put("injection", sql_9_injection);
|
params.put("injection", sql_9_injection);
|
||||||
checkAssignment(url("SqlInjection/assignment5a"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/assignment5a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("login_count", sql_10_login_count);
|
params.put("login_count", sql_10_login_count);
|
||||||
params.put("userid", sql_10_userid);
|
params.put("userid", sql_10_userid);
|
||||||
checkAssignment(url("SqlInjection/assignment5b"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/assignment5b"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("name", sql_11_a);
|
params.put("name", sql_11_a);
|
||||||
params.put("auth_tan", sql_11_b);
|
params.put("auth_tan", sql_11_b);
|
||||||
checkAssignment(url("SqlInjection/attack8"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/attack8"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("name", sql_12_a);
|
params.put("name", sql_12_a);
|
||||||
params.put("auth_tan", sql_12_b);
|
params.put("auth_tan", sql_12_b);
|
||||||
checkAssignment(url("SqlInjection/attack9"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/attack9"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("action_string", sql_13);
|
params.put("action_string", sql_13);
|
||||||
checkAssignment(url("SqlInjection/attack10"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjection/attack10"), params, true);
|
||||||
|
|
||||||
checkResults("SqlInjection");
|
checkResults("/SqlInjection/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
params.put("field5", "?");
|
params.put("field5", "?");
|
||||||
params.put("field6", "prep.setString(1,\"\")");
|
params.put("field6", "prep.setString(1,\"\")");
|
||||||
params.put("field7", "prep.setString(2,\\\"\\\")");
|
params.put("field7", "prep.setString(2,\\\"\\\")");
|
||||||
checkAssignment(url("SqlInjectionMitigations/attack10a"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10a"), params, true);
|
||||||
|
|
||||||
params.put(
|
params.put(
|
||||||
"editor",
|
"editor",
|
||||||
@ -37,18 +37,18 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
+ "} catch (Exception e) {\r\n"
|
+ "} catch (Exception e) {\r\n"
|
||||||
+ " System.out.println(\"Oops. Something went wrong!\");\r\n"
|
+ " System.out.println(\"Oops. Something went wrong!\");\r\n"
|
||||||
+ "}");
|
+ "}");
|
||||||
checkAssignment(url("SqlInjectionMitigations/attack10b"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack10b"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
"userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--");
|
"userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--");
|
||||||
checkAssignment(url("SqlOnlyInputValidation/attack"), params, true);
|
checkAssignment(url("/WebGoat/SqlOnlyInputValidation/attack"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
"userid_sql_only_input_validation_on_keywords",
|
"userid_sql_only_input_validation_on_keywords",
|
||||||
"Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--");
|
"Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--");
|
||||||
checkAssignment(url("SqlOnlyInputValidationOnKeywords/attack"), params, true);
|
checkAssignment(url("/WebGoat/SqlOnlyInputValidationOnKeywords/attack"), params, true);
|
||||||
|
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
@ -57,7 +57,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(
|
.get(
|
||||||
url(
|
url(
|
||||||
"SqlInjectionMitigations/servers?column=(case when (true) then hostname"
|
"/WebGoat/SqlInjectionMitigations/servers?column=(case when (true) then hostname"
|
||||||
+ " else id end)"))
|
+ " else id end)"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
@ -67,7 +67,7 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.get(url("SqlInjectionMitigations/servers?column=unknown"))
|
.get(url("/WebGoat/SqlInjectionMitigations/servers?column=unknown"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(500)
|
.statusCode(500)
|
||||||
.body(
|
.body(
|
||||||
@ -78,8 +78,8 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("ip", "104.130.219.202");
|
params.put("ip", "104.130.219.202");
|
||||||
checkAssignment(url("SqlInjectionMitigations/attack12a"), params, true);
|
checkAssignment(url("/WebGoat/SqlInjectionMitigations/attack12a"), params, true);
|
||||||
|
|
||||||
checkResults("SqlInjectionMitigations");
|
checkResults();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package org.owasp.webgoat;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -10,20 +11,21 @@ import org.junit.jupiter.api.Test;
|
|||||||
public class WebWolfIntegrationTest extends IntegrationTest {
|
public class WebWolfIntegrationTest extends IntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void runTests() {
|
public void runTests() throws IOException {
|
||||||
startLesson("WebWolfIntroduction");
|
startLesson("WebWolfIntroduction");
|
||||||
|
|
||||||
// Assignment 3
|
// Assignment 3
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
|
params.clear();
|
||||||
params.put("email", this.getUser() + "@webgoat.org");
|
params.put("email", this.getUser() + "@webgoat.org");
|
||||||
checkAssignment(url("WebWolf/mail/send"), params, false);
|
checkAssignment(url("/WebGoat/WebWolf/mail/send"), params, false);
|
||||||
|
|
||||||
String responseBody =
|
String responseBody =
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(new WebWolfUrlBuilder().path("mail").build())
|
.get(webWolfUrl("/WebWolf/mail"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -37,7 +39,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
uniqueCode.lastIndexOf("your unique code is: ") + (21 + this.getUser().length()));
|
uniqueCode.lastIndexOf("your unique code is: ") + (21 + this.getUser().length()));
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("uniqueCode", uniqueCode);
|
params.put("uniqueCode", uniqueCode);
|
||||||
checkAssignment(url("WebWolf/mail"), params, true);
|
checkAssignment(url("/WebGoat/WebWolf/mail"), params, true);
|
||||||
|
|
||||||
// Assignment 4
|
// Assignment 4
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
@ -45,7 +47,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
.queryParams(params)
|
.queryParams(params)
|
||||||
.get(url("WebWolf/landing/password-reset"))
|
.get(url("/WebGoat/WebWolf/landing/password-reset"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
@ -53,7 +55,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.queryParams(params)
|
.queryParams(params)
|
||||||
.get(new WebWolfUrlBuilder().path("landing").build())
|
.get(webWolfUrl("/landing"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
responseBody =
|
responseBody =
|
||||||
@ -61,7 +63,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(new WebWolfUrlBuilder().path("requests").build())
|
.get(webWolfUrl("/WebWolf/requests"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -70,8 +72,8 @@ public class WebWolfIntegrationTest extends IntegrationTest {
|
|||||||
assertTrue(responseBody.contains(uniqueCode));
|
assertTrue(responseBody.contains(uniqueCode));
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("uniqueCode", uniqueCode);
|
params.put("uniqueCode", uniqueCode);
|
||||||
checkAssignment(url("WebWolf/landing"), params, true);
|
checkAssignment(url("/WebGoat/WebWolf/landing"), params, true);
|
||||||
|
|
||||||
checkResults("WebWolfIntroduction");
|
checkResults("/WebWolf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("checkboxAttack1", "value");
|
params.put("checkboxAttack1", "value");
|
||||||
checkAssignment(url("CrossSiteScripting/attack1"), params, true);
|
checkAssignment(url("/CrossSiteScripting/attack1"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("QTY1", "1");
|
params.put("QTY1", "1");
|
||||||
@ -23,11 +23,11 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
params.put("QTY4", "1");
|
params.put("QTY4", "1");
|
||||||
params.put("field1", "<script>alert('XSS+Test')</script>");
|
params.put("field1", "<script>alert('XSS+Test')</script>");
|
||||||
params.put("field2", "111");
|
params.put("field2", "111");
|
||||||
checkAssignmentWithGet(url("CrossSiteScripting/attack5a"), params, true);
|
checkAssignmentWithGet(url("/CrossSiteScripting/attack5a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("DOMTestRoute", "start.mvc#test");
|
params.put("DOMTestRoute", "start.mvc#test");
|
||||||
checkAssignment(url("CrossSiteScripting/attack6a"), params, true);
|
checkAssignment(url("/CrossSiteScripting/attack6a"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("param1", "42");
|
params.put("param1", "42");
|
||||||
@ -41,7 +41,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
.header("webgoat-requested-by", "dom-xss-vuln")
|
.header("webgoat-requested-by", "dom-xss-vuln")
|
||||||
.header("X-Requested-With", "XMLHttpRequest")
|
.header("X-Requested-With", "XMLHttpRequest")
|
||||||
.formParams(params)
|
.formParams(params)
|
||||||
.post(url("CrossSiteScripting/phone-home-xss"))
|
.post(url("/CrossSiteScripting/phone-home-xss"))
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.extract()
|
.extract()
|
||||||
@ -50,7 +50,7 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("successMessage", secretNumber);
|
params.put("successMessage", secretNumber);
|
||||||
checkAssignment(url("CrossSiteScripting/dom-follow-up"), params, true);
|
checkAssignment(url("/CrossSiteScripting/dom-follow-up"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put(
|
params.put(
|
||||||
@ -73,44 +73,8 @@ public class XSSIntegrationTest extends IntegrationTest {
|
|||||||
"question_4_solution",
|
"question_4_solution",
|
||||||
"Solution 4: No there are many other ways. Like HTML, Flash or any other type of code that"
|
"Solution 4: No there are many other ways. Like HTML, Flash or any other type of code that"
|
||||||
+ " the browser executes.");
|
+ " the browser executes.");
|
||||||
checkAssignment(url("CrossSiteScripting/quiz"), params, true);
|
checkAssignment(url("/CrossSiteScripting/quiz"), params, true);
|
||||||
|
|
||||||
params.clear();
|
checkResults("/CrossSiteScripting/");
|
||||||
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,6 +3,9 @@ package org.owasp.webgoat;
|
|||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import java.io.IOException;
|
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;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class XXEIntegrationTest extends IntegrationTest {
|
public class XXEIntegrationTest extends IntegrationTest {
|
||||||
@ -25,40 +28,47 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
""";
|
""";
|
||||||
|
|
||||||
private String webGoatHomeDirectory;
|
private String webGoatHomeDirectory;
|
||||||
|
private String webWolfFileServerLocation;
|
||||||
|
|
||||||
// TODO fix me
|
/*
|
||||||
// /*
|
* This test is to verify that all is secure when XXE security patch is applied.
|
||||||
// * This test is to verify that all is secure when XXE security patch is applied.
|
*/
|
||||||
// */
|
@Test
|
||||||
// @Test
|
public void xxeSecure() throws IOException {
|
||||||
// public void xxeSecure() throws IOException {
|
startLesson("XXE");
|
||||||
// startLesson("XXE");
|
webGoatHomeDirectory = webGoatServerDirectory();
|
||||||
// webGoatHomeDirectory = webGoatServerDirectory();
|
webWolfFileServerLocation = getWebWolfFileServerLocation();
|
||||||
// RestAssured.given()
|
RestAssured.given()
|
||||||
// .when()
|
.when()
|
||||||
// .relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
// .cookie("JSESSIONID", getWebGoatCookie())
|
.cookie("JSESSIONID", getWebGoatCookie())
|
||||||
// .get(url("service/enable-security.mvc"))
|
.get(url("service/enable-security.mvc"))
|
||||||
// .then()
|
.then()
|
||||||
// .statusCode(200);
|
.statusCode(200);
|
||||||
// checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, false);
|
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, false);
|
||||||
// checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, false);
|
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, false);
|
||||||
// checkAssignment(
|
checkAssignment(
|
||||||
// url("xxe/blind"),
|
url("/WebGoat/xxe/blind"),
|
||||||
// ContentType.XML,
|
ContentType.XML,
|
||||||
// "<comment><text>" + getSecret() + "</text></comment>",
|
"<comment><text>" + getSecret() + "</text></comment>",
|
||||||
// false);
|
false);
|
||||||
// }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This performs the steps of the exercise before the secret can be committed in the final step.
|
* This performs the steps of the exercise before the secret can be committed in the final step.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private String getSecret() {
|
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")));
|
||||||
|
}
|
||||||
String secretFile = webGoatHomeDirectory.concat("/XXE/" + getUser() + "/secret.txt");
|
String secretFile = webGoatHomeDirectory.concat("/XXE/" + getUser() + "/secret.txt");
|
||||||
String webWolfCallback = new WebWolfUrlBuilder().path("landing").attackMode().build();
|
String dtd7String =
|
||||||
String dtd7String = dtd7.replace("WEBWOLFURL", webWolfCallback).replace("SECRET", secretFile);
|
dtd7.replace("WEBWOLFURL", webWolfUrl("/landing")).replace("SECRET", secretFile);
|
||||||
|
|
||||||
// upload DTD
|
// upload DTD
|
||||||
RestAssured.given()
|
RestAssured.given()
|
||||||
@ -66,18 +76,16 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.multiPart("file", "blind.dtd", dtd7String.getBytes())
|
.multiPart("file", "blind.dtd", dtd7String.getBytes())
|
||||||
.post(new WebWolfUrlBuilder().path("fileupload").build())
|
.post(webWolfUrl("/fileupload"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
.getBody()
|
.getBody()
|
||||||
.asString();
|
.asString();
|
||||||
|
|
||||||
// upload attack
|
// upload attack
|
||||||
String xxe7String =
|
String xxe7String =
|
||||||
xxe7.replace("WEBWOLFURL", new WebWolfUrlBuilder().attackMode().path("files").build())
|
xxe7.replace("WEBWOLFURL", webWolfUrl("/files")).replace("USERNAME", this.getUser());
|
||||||
.replace("USERNAME", this.getUser());
|
checkAssignment(url("/WebGoat/xxe/blind"), ContentType.XML, xxe7String, false);
|
||||||
checkAssignment(url("xxe/blind"), ContentType.XML, xxe7String, false);
|
|
||||||
|
|
||||||
// read results from WebWolf
|
// read results from WebWolf
|
||||||
String result =
|
String result =
|
||||||
@ -85,7 +93,7 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
.when()
|
.when()
|
||||||
.relaxedHTTPSValidation()
|
.relaxedHTTPSValidation()
|
||||||
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
.cookie("WEBWOLFSESSION", getWebWolfCookie())
|
||||||
.get(new WebWolfUrlBuilder().path("requests").build())
|
.get(webWolfUrl("/WebWolf/requests"))
|
||||||
.then()
|
.then()
|
||||||
.extract()
|
.extract()
|
||||||
.response()
|
.response()
|
||||||
@ -105,13 +113,14 @@ public class XXEIntegrationTest extends IntegrationTest {
|
|||||||
public void runTests() throws IOException {
|
public void runTests() throws IOException {
|
||||||
startLesson("XXE", true);
|
startLesson("XXE", true);
|
||||||
webGoatHomeDirectory = webGoatServerDirectory();
|
webGoatHomeDirectory = webGoatServerDirectory();
|
||||||
checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, true);
|
webWolfFileServerLocation = getWebWolfFileServerLocation();
|
||||||
checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, true);
|
checkAssignment(url("/WebGoat/xxe/simple"), ContentType.XML, xxe3, true);
|
||||||
|
checkAssignment(url("/WebGoat/xxe/content-type"), ContentType.XML, xxe4, true);
|
||||||
checkAssignment(
|
checkAssignment(
|
||||||
url("xxe/blind"),
|
url("/WebGoat/xxe/blind"),
|
||||||
ContentType.XML,
|
ContentType.XML,
|
||||||
"<comment><text>" + getSecret() + "</text></comment>",
|
"<comment><text>" + getSecret() + "</text></comment>",
|
||||||
true);
|
true);
|
||||||
checkResults("XXE");
|
checkResults("xxe/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,23 +32,22 @@ package org.owasp.webgoat.container;
|
|||||||
|
|
||||||
import static org.asciidoctor.Asciidoctor.Factory.create;
|
import static org.asciidoctor.Asciidoctor.Factory.create;
|
||||||
|
|
||||||
|
import io.undertow.util.Headers;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.asciidoctor.Asciidoctor;
|
import org.asciidoctor.Asciidoctor;
|
||||||
import org.asciidoctor.Attributes;
|
|
||||||
import org.asciidoctor.Options;
|
|
||||||
import org.asciidoctor.extension.JavaExtensionRegistry;
|
import org.asciidoctor.extension.JavaExtensionRegistry;
|
||||||
import org.owasp.webgoat.container.asciidoc.*;
|
import org.owasp.webgoat.container.asciidoc.*;
|
||||||
import org.owasp.webgoat.container.i18n.Language;
|
import org.owasp.webgoat.container.i18n.Language;
|
||||||
import org.springframework.core.io.ResourceLoader;
|
import org.springframework.core.io.ResourceLoader;
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
|
||||||
@ -136,17 +135,17 @@ public class AsciiDoctorTemplateResolver extends FileTemplateResolver {
|
|||||||
return computedResourceName;
|
return computedResourceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Options createAttributes() {
|
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);
|
||||||
|
|
||||||
return Options.builder()
|
Map<String, Object> options = new HashMap<>();
|
||||||
.attributes(
|
options.put("attributes", attributes);
|
||||||
Attributes.builder()
|
|
||||||
.attribute("source-highlighter", "coderay")
|
return options;
|
||||||
.attribute("backend", "xhtml")
|
|
||||||
.attribute("lang", determineLanguage())
|
|
||||||
.attribute("icons", org.asciidoctor.Attributes.FONT_ICONS)
|
|
||||||
.build())
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String determineLanguage() {
|
private String determineLanguage() {
|
||||||
@ -160,7 +159,7 @@ public class AsciiDoctorTemplateResolver extends FileTemplateResolver {
|
|||||||
log.debug("browser locale {}", browserLocale);
|
log.debug("browser locale {}", browserLocale);
|
||||||
return browserLocale.getLanguage();
|
return browserLocale.getLanguage();
|
||||||
} else {
|
} else {
|
||||||
String langHeader = request.getHeader(HttpHeaders.ACCEPT_LANGUAGE);
|
String langHeader = request.getHeader(Headers.ACCEPT_LANGUAGE_STRING);
|
||||||
if (null != langHeader) {
|
if (null != langHeader) {
|
||||||
log.debug("browser locale {}", langHeader);
|
log.debug("browser locale {}", langHeader);
|
||||||
return langHeader.substring(0, 2);
|
return langHeader.substring(0, 2);
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
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 {}
|
|
@ -1,14 +0,0 @@
|
|||||||
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.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flywaydb.core.Flyway;
|
import org.flywaydb.core.Flyway;
|
||||||
|
import org.owasp.webgoat.container.lessons.LessonScanner;
|
||||||
import org.owasp.webgoat.container.service.RestartLessonService;
|
import org.owasp.webgoat.container.service.RestartLessonService;
|
||||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -20,6 +20,7 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
|||||||
public class DatabaseConfiguration {
|
public class DatabaseConfiguration {
|
||||||
|
|
||||||
private final DataSourceProperties properties;
|
private final DataSourceProperties properties;
|
||||||
|
private final LessonScanner lessonScanner;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Primary
|
@Primary
|
||||||
@ -35,8 +36,8 @@ public class DatabaseConfiguration {
|
|||||||
/**
|
/**
|
||||||
* Define 2 Flyway instances, 1 for WebGoat itself which it uses for internal storage like users
|
* 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
|
* and 1 for lesson specific tables we use. This way we clean the data in the lesson database
|
||||||
* quite easily see {@link RestartLessonService#restartLesson(String, WebGoatUser)} for how we
|
* quite easily see {@link RestartLessonService#restartLesson()} for how we clean the lesson
|
||||||
* clean the lesson related tables.
|
* related tables.
|
||||||
*/
|
*/
|
||||||
@Bean(initMethod = "migrate")
|
@Bean(initMethod = "migrate")
|
||||||
public Flyway flyWayContainer() {
|
public Flyway flyWayContainer() {
|
||||||
@ -61,7 +62,7 @@ public class DatabaseConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public LessonDataSource lessonDataSource(DataSource dataSource) {
|
public LessonDataSource lessonDataSource() {
|
||||||
return new LessonDataSource(dataSource);
|
return new LessonDataSource(dataSource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,8 @@ import org.thymeleaf.templateresource.StringTemplateResource;
|
|||||||
public class LessonTemplateResolver extends FileTemplateResolver {
|
public class LessonTemplateResolver extends FileTemplateResolver {
|
||||||
|
|
||||||
private static final String PREFIX = "lesson:";
|
private static final String PREFIX = "lesson:";
|
||||||
private final ResourceLoader resourceLoader;
|
private ResourceLoader resourceLoader;
|
||||||
private final Map<String, byte[]> resources = new HashMap<>();
|
private Map<String, byte[]> resources = new HashMap<>();
|
||||||
|
|
||||||
public LessonTemplateResolver(ResourceLoader resourceLoader) {
|
public LessonTemplateResolver(ResourceLoader resourceLoader) {
|
||||||
this.resourceLoader = resourceLoader;
|
this.resourceLoader = resourceLoader;
|
||||||
|
@ -40,6 +40,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.owasp.webgoat.container.i18n.Language;
|
import org.owasp.webgoat.container.i18n.Language;
|
||||||
import org.owasp.webgoat.container.i18n.Messages;
|
import org.owasp.webgoat.container.i18n.Messages;
|
||||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
import org.owasp.webgoat.container.i18n.PluginMessages;
|
||||||
|
import org.owasp.webgoat.container.lessons.LessonScanner;
|
||||||
import org.owasp.webgoat.container.session.LabelDebugger;
|
import org.owasp.webgoat.container.session.LabelDebugger;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -73,6 +74,8 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
|||||||
|
|
||||||
private static final String UTF8 = "UTF-8";
|
private static final String UTF8 = "UTF-8";
|
||||||
|
|
||||||
|
private final LessonScanner lessonScanner;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addViewControllers(ViewControllerRegistry registry) {
|
public void addViewControllers(ViewControllerRegistry registry) {
|
||||||
registry.addViewController("/login").setViewName("login");
|
registry.addViewController("/login").setViewName("login");
|
||||||
@ -184,6 +187,28 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
|||||||
registry
|
registry
|
||||||
.addResourceHandler("/fonts/**")
|
.addResourceHandler("/fonts/**")
|
||||||
.addResourceLocations("classpath:/webgoat/static/fonts/");
|
.addResourceLocations("classpath:/webgoat/static/fonts/");
|
||||||
|
|
||||||
|
// WebGoat lessons
|
||||||
|
registry
|
||||||
|
.addResourceHandler("/images/**")
|
||||||
|
.addResourceLocations(
|
||||||
|
lessonScanner.applyPattern("classpath:/lessons/%s/images/").toArray(String[]::new));
|
||||||
|
registry
|
||||||
|
.addResourceHandler("/lesson_js/**")
|
||||||
|
.addResourceLocations(
|
||||||
|
lessonScanner.applyPattern("classpath:/lessons/%s/js/").toArray(String[]::new));
|
||||||
|
registry
|
||||||
|
.addResourceHandler("/lesson_css/**")
|
||||||
|
.addResourceLocations(
|
||||||
|
lessonScanner.applyPattern("classpath:/lessons/%s/css/").toArray(String[]::new));
|
||||||
|
registry
|
||||||
|
.addResourceHandler("/lesson_templates/**")
|
||||||
|
.addResourceLocations(
|
||||||
|
lessonScanner.applyPattern("classpath:/lessons/%s/templates/").toArray(String[]::new));
|
||||||
|
registry
|
||||||
|
.addResourceHandler("/video/**")
|
||||||
|
.addResourceLocations(
|
||||||
|
lessonScanner.applyPattern("classpath:/lessons/%s/video/").toArray(String[]::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -217,7 +242,6 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(localeChangeInterceptor());
|
registry.addInterceptor(localeChangeInterceptor());
|
||||||
registry.addInterceptor(new UserInterceptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
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,25 +32,22 @@
|
|||||||
package org.owasp.webgoat.container;
|
package org.owasp.webgoat.container;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import org.owasp.webgoat.container.session.LessonSession;
|
import org.owasp.webgoat.container.session.UserSessionData;
|
||||||
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.context.annotation.ScopedProxyMode;
|
import org.springframework.context.annotation.ScopedProxyMode;
|
||||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(basePackages = {"org.owasp.webgoat.container", "org.owasp.webgoat.lessons"})
|
@ComponentScan(basePackages = {"org.owasp.webgoat.container", "org.owasp.webgoat.lessons"})
|
||||||
@PropertySource("classpath:application-webgoat.properties")
|
@PropertySource("classpath:application-webgoat.properties")
|
||||||
@EnableAutoConfiguration
|
@EnableAutoConfiguration
|
||||||
@EnableJpaRepositories(basePackages = {"org.owasp.webgoat.container"})
|
|
||||||
@EntityScan(basePackages = "org.owasp.webgoat.container")
|
|
||||||
public class WebGoat {
|
public class WebGoat {
|
||||||
|
|
||||||
@Bean(name = "pluginTargetDirectory")
|
@Bean(name = "pluginTargetDirectory")
|
||||||
@ -60,8 +57,14 @@ public class WebGoat {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||||
public LessonSession userSessionData() {
|
public WebSession webSession() {
|
||||||
return new LessonSession();
|
return new WebSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||||
|
public UserSessionData userSessionData() {
|
||||||
|
return new UserSessionData("test", "data");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -35,7 +35,6 @@ import org.owasp.webgoat.container.users.UserService;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Primary;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
@ -55,10 +54,9 @@ public class WebSecurityConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
return http.authorizeHttpRequests(
|
http.authorizeHttpRequests(
|
||||||
auth ->
|
auth ->
|
||||||
auth.requestMatchers(
|
auth.requestMatchers(
|
||||||
"/favicon.ico",
|
|
||||||
"/css/**",
|
"/css/**",
|
||||||
"/images/**",
|
"/images/**",
|
||||||
"/js/**",
|
"/js/**",
|
||||||
@ -69,27 +67,19 @@ public class WebSecurityConfig {
|
|||||||
"/actuator/**")
|
"/actuator/**")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.authenticated())
|
.authenticated());
|
||||||
.formLogin(
|
http.formLogin()
|
||||||
login ->
|
|
||||||
login
|
|
||||||
.loginPage("/login")
|
.loginPage("/login")
|
||||||
.defaultSuccessUrl("/welcome.mvc", true)
|
.defaultSuccessUrl("/welcome.mvc", true)
|
||||||
.usernameParameter("username")
|
.usernameParameter("username")
|
||||||
.passwordParameter("password")
|
.passwordParameter("password")
|
||||||
.permitAll())
|
.permitAll();
|
||||||
.oauth2Login(
|
http.logout().deleteCookies("JSESSIONID").invalidateHttpSession(true);
|
||||||
oidc -> {
|
http.csrf().disable();
|
||||||
oidc.defaultSuccessUrl("/login-oauth.mvc");
|
|
||||||
oidc.loginPage("/login");
|
http.headers().cacheControl().disable();
|
||||||
})
|
http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login"));
|
||||||
.logout(logout -> logout.deleteCookies("JSESSIONID").invalidateHttpSession(true))
|
return http.build();
|
||||||
.csrf(csrf -> csrf.disable())
|
|
||||||
.headers(headers -> headers.disable())
|
|
||||||
.exceptionHandling(
|
|
||||||
handling ->
|
|
||||||
handling.authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")))
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -98,7 +88,6 @@ public class WebSecurityConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Primary
|
|
||||||
public UserDetailsService userDetailsServiceBean() {
|
public UserDetailsService userDetailsServiceBean() {
|
||||||
return userDetailsService;
|
return userDetailsService;
|
||||||
}
|
}
|
||||||
@ -109,6 +98,7 @@ public class WebSecurityConfig {
|
|||||||
return authenticationConfiguration.getAuthenticationManager();
|
return authenticationConfiguration.getAuthenticationManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Bean
|
@Bean
|
||||||
public NoOpPasswordEncoder passwordEncoder() {
|
public NoOpPasswordEncoder passwordEncoder() {
|
||||||
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
|
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
|
||||||
|
@ -16,7 +16,7 @@ public class EnvironmentExposure implements ApplicationContextAware {
|
|||||||
private static ApplicationContext context;
|
private static ApplicationContext context;
|
||||||
|
|
||||||
public static Environment getEnv() {
|
public static Environment getEnv() {
|
||||||
return null != context ? context.getEnvironment() : null;
|
return context.getEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package org.owasp.webgoat.container.asciidoc;
|
package org.owasp.webgoat.container.asciidoc;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.asciidoctor.ast.PhraseNode;
|
import org.asciidoctor.ast.ContentNode;
|
||||||
import org.asciidoctor.ast.StructuralNode;
|
|
||||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||||
|
|
||||||
public class OperatingSystemMacro extends InlineMacroProcessor {
|
public class OperatingSystemMacro extends InlineMacroProcessor {
|
||||||
@ -16,8 +15,7 @@ public class OperatingSystemMacro extends InlineMacroProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PhraseNode process(
|
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
|
||||||
StructuralNode contentNode, String target, Map<String, Object> attributes) {
|
|
||||||
var osName = System.getProperty("os.name");
|
var osName = System.getProperty("os.name");
|
||||||
|
|
||||||
// see
|
// see
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package org.owasp.webgoat.container.asciidoc;
|
package org.owasp.webgoat.container.asciidoc;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.asciidoctor.ast.PhraseNode;
|
import org.asciidoctor.ast.ContentNode;
|
||||||
import org.asciidoctor.ast.StructuralNode;
|
|
||||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
import org.owasp.webgoat.container.users.WebGoatUser;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
@ -18,8 +17,7 @@ public class UsernameMacro extends InlineMacroProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PhraseNode process(
|
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
|
||||||
StructuralNode contentNode, String target, Map<String, Object> attributes) {
|
|
||||||
var auth = SecurityContextHolder.getContext().getAuthentication();
|
var auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
var username = "unknown";
|
var username = "unknown";
|
||||||
if (auth.getPrincipal() instanceof WebGoatUser webGoatUser) {
|
if (auth.getPrincipal() instanceof WebGoatUser webGoatUser) {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package org.owasp.webgoat.container.asciidoc;
|
package org.owasp.webgoat.container.asciidoc;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.asciidoctor.ast.PhraseNode;
|
import org.asciidoctor.ast.ContentNode;
|
||||||
import org.asciidoctor.ast.StructuralNode;
|
|
||||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||||
|
|
||||||
public class WebGoatTmpDirMacro extends InlineMacroProcessor {
|
public class WebGoatTmpDirMacro extends InlineMacroProcessor {
|
||||||
@ -16,12 +15,11 @@ public class WebGoatTmpDirMacro extends InlineMacroProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PhraseNode process(
|
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
|
||||||
StructuralNode structuralNode, String target, Map<String, Object> attributes) {
|
|
||||||
var env = EnvironmentExposure.getEnv().getProperty("webgoat.server.directory");
|
var env = EnvironmentExposure.getEnv().getProperty("webgoat.server.directory");
|
||||||
|
|
||||||
// see
|
// see
|
||||||
// https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
|
// https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
|
||||||
return createPhraseNode(structuralNode, "quoted", env);
|
return createPhraseNode(contentNode, "quoted", env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package org.owasp.webgoat.container.asciidoc;
|
package org.owasp.webgoat.container.asciidoc;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.asciidoctor.ast.PhraseNode;
|
import org.asciidoctor.ast.ContentNode;
|
||||||
import org.asciidoctor.ast.StructuralNode;
|
|
||||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||||
|
|
||||||
public class WebGoatVersionMacro extends InlineMacroProcessor {
|
public class WebGoatVersionMacro extends InlineMacroProcessor {
|
||||||
@ -16,8 +15,7 @@ public class WebGoatVersionMacro extends InlineMacroProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PhraseNode process(
|
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
|
||||||
StructuralNode contentNode, String target, Map<String, Object> attributes) {
|
|
||||||
var webgoatVersion = EnvironmentExposure.getEnv().getProperty("webgoat.build.version");
|
var webgoatVersion = EnvironmentExposure.getEnv().getProperty("webgoat.build.version");
|
||||||
|
|
||||||
// see
|
// see
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package org.owasp.webgoat.container.asciidoc;
|
package org.owasp.webgoat.container.asciidoc;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.asciidoctor.ast.PhraseNode;
|
import org.asciidoctor.ast.ContentNode;
|
||||||
import org.asciidoctor.ast.StructuralNode;
|
|
||||||
import org.asciidoctor.extension.InlineMacroProcessor;
|
import org.asciidoctor.extension.InlineMacroProcessor;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Usage in asciidoc:
|
* Usage in asciidoc:
|
||||||
@ -22,10 +24,9 @@ public class WebWolfMacro extends InlineMacroProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PhraseNode process(
|
public Object process(ContentNode contentNode, String linkText, Map<String, Object> attributes) {
|
||||||
StructuralNode contentNode, String linkText, Map<String, Object> attributes) {
|
|
||||||
var env = EnvironmentExposure.getEnv();
|
var env = EnvironmentExposure.getEnv();
|
||||||
var hostname = env.getProperty("webwolf.url");
|
var hostname = determineHost(env.getProperty("webwolf.port"));
|
||||||
var target = (String) attributes.getOrDefault("target", "home");
|
var target = (String) attributes.getOrDefault("target", "home");
|
||||||
var href = hostname + "/" + target;
|
var href = hostname + "/" + target;
|
||||||
|
|
||||||
@ -38,10 +39,35 @@ public class WebWolfMacro extends InlineMacroProcessor {
|
|||||||
options.put("type", ":link");
|
options.put("type", ":link");
|
||||||
options.put("target", href);
|
options.put("target", href);
|
||||||
attributes.put("window", "_blank");
|
attributes.put("window", "_blank");
|
||||||
return createPhraseNode(contentNode, "anchor", linkText, attributes, options);
|
return createPhraseNode(contentNode, "anchor", linkText, attributes, options).convert();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean displayCompleteLinkNoFormatting(Map<String, Object> attributes) {
|
private boolean displayCompleteLinkNoFormatting(Map<String, Object> attributes) {
|
||||||
return attributes.values().stream().anyMatch(a -> a.equals("noLink"));
|
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,4 +17,9 @@ public class WebWolfRootMacro extends WebWolfMacro {
|
|||||||
public WebWolfRootMacro(String macroName, Map<String, Object> config) {
|
public WebWolfRootMacro(String macroName, Map<String, Object> config) {
|
||||||
super(macroName, config);
|
super(macroName, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean includeWebWolfContext() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,4 +25,68 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.container.assignments;
|
package org.owasp.webgoat.container.assignments;
|
||||||
|
|
||||||
public interface AssignmentEndpoint {}
|
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 {
|
||||||
|
|
||||||
|
@Autowired private WebSession webSession;
|
||||||
|
@Autowired private UserSessionData userSessionData;
|
||||||
|
@Getter @Autowired private PluginMessages messages;
|
||||||
|
|
||||||
|
protected WebSession getWebSession() {
|
||||||
|
return webSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected UserSessionData getUserSessionData() {
|
||||||
|
return userSessionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for create a successful result:
|
||||||
|
*
|
||||||
|
* <p>- Assignment is set to solved - Feedback message is set to 'assignment.solved'
|
||||||
|
*
|
||||||
|
* <p>Of course you can overwrite these values in a specific lesson
|
||||||
|
*
|
||||||
|
* @return a builder for creating a result from a lesson
|
||||||
|
* @param assignment
|
||||||
|
*/
|
||||||
|
protected AttackResult.AttackResultBuilder success(AssignmentEndpoint assignment) {
|
||||||
|
return AttackResult.builder(messages)
|
||||||
|
.lessonCompleted(true)
|
||||||
|
.attemptWasMade()
|
||||||
|
.feedback("assignment.solved")
|
||||||
|
.assignment(assignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method for create a failed result:
|
||||||
|
*
|
||||||
|
* <p>- Assignment is set to not solved - Feedback message is set to 'assignment.not.solved'
|
||||||
|
*
|
||||||
|
* <p>Of course you can overwrite these values in a specific lesson
|
||||||
|
*
|
||||||
|
* @return a builder for creating a result from a lesson
|
||||||
|
* @param assignment
|
||||||
|
*/
|
||||||
|
protected AttackResult.AttackResultBuilder failed(AssignmentEndpoint assignment) {
|
||||||
|
return AttackResult.builder(messages)
|
||||||
|
.lessonCompleted(false)
|
||||||
|
.attemptWasMade()
|
||||||
|
.feedback("assignment.not.solved")
|
||||||
|
.assignment(assignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AttackResult.AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
|
||||||
|
return AttackResult.builder(messages).lessonCompleted(false).assignment(assignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(WebGoatUser user) {}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package org.owasp.webgoat.container.assignments;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
|
||||||
|
/** Created by nbaars on 1/14/17. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface AssignmentPath {
|
||||||
|
|
||||||
|
String[] path() default {};
|
||||||
|
|
||||||
|
RequestMethod[] method() default {};
|
||||||
|
|
||||||
|
String value() default "";
|
||||||
|
}
|
@ -30,18 +30,82 @@ import static org.apache.commons.text.StringEscapeUtils.escapeJson;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
import org.owasp.webgoat.container.i18n.PluginMessages;
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class AttackResult {
|
public class AttackResult {
|
||||||
|
|
||||||
|
public static class AttackResultBuilder {
|
||||||
|
|
||||||
private boolean lessonCompleted;
|
private boolean lessonCompleted;
|
||||||
private String feedback;
|
private PluginMessages messages;
|
||||||
private Object[] feedbackArgs;
|
private Object[] feedbackArgs;
|
||||||
|
private String feedbackResourceBundleKey;
|
||||||
private String output;
|
private String output;
|
||||||
private Object[] outputArgs;
|
private Object[] outputArgs;
|
||||||
private final String assignment;
|
private AssignmentEndpoint assignment;
|
||||||
private boolean attemptWasMade;
|
private boolean attemptWasMade = false;
|
||||||
|
|
||||||
private AttackResult(
|
public AttackResultBuilder(PluginMessages messages) {
|
||||||
|
this.messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResultBuilder lessonCompleted(boolean lessonCompleted) {
|
||||||
|
this.lessonCompleted = lessonCompleted;
|
||||||
|
this.feedbackResourceBundleKey = "lesson.completed";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResultBuilder lessonCompleted(boolean lessonCompleted, String resourceBundleKey) {
|
||||||
|
this.lessonCompleted = lessonCompleted;
|
||||||
|
this.feedbackResourceBundleKey = resourceBundleKey;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResultBuilder feedbackArgs(Object... args) {
|
||||||
|
this.feedbackArgs = args;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResultBuilder feedback(String resourceBundleKey) {
|
||||||
|
this.feedbackResourceBundleKey = resourceBundleKey;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResultBuilder output(String output) {
|
||||||
|
this.output = output;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResultBuilder outputArgs(Object... args) {
|
||||||
|
this.outputArgs = args;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResultBuilder attemptWasMade() {
|
||||||
|
this.attemptWasMade = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResult build() {
|
||||||
|
return new AttackResult(
|
||||||
|
lessonCompleted,
|
||||||
|
messages.getMessage(feedbackResourceBundleKey, feedbackArgs),
|
||||||
|
messages.getMessage(output, output, outputArgs),
|
||||||
|
assignment.getClass().getSimpleName(),
|
||||||
|
attemptWasMade);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttackResultBuilder assignment(AssignmentEndpoint assignment) {
|
||||||
|
this.assignment = assignment;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter private boolean lessonCompleted;
|
||||||
|
@Getter private String feedback;
|
||||||
|
@Getter private String output;
|
||||||
|
@Getter private final String assignment;
|
||||||
|
@Getter private boolean attemptWasMade;
|
||||||
|
|
||||||
|
public AttackResult(
|
||||||
boolean lessonCompleted,
|
boolean lessonCompleted,
|
||||||
String feedback,
|
String feedback,
|
||||||
String output,
|
String output,
|
||||||
@ -54,33 +118,11 @@ public class AttackResult {
|
|||||||
this.attemptWasMade = attemptWasMade;
|
this.attemptWasMade = attemptWasMade;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttackResult(
|
public static AttackResultBuilder builder(PluginMessages messages) {
|
||||||
boolean lessonCompleted,
|
return new AttackResultBuilder(messages);
|
||||||
String feedback,
|
|
||||||
Object[] feedbackArgs,
|
|
||||||
String output,
|
|
||||||
Object[] outputArgs,
|
|
||||||
String assignment,
|
|
||||||
boolean attemptWasMade) {
|
|
||||||
this.lessonCompleted = lessonCompleted;
|
|
||||||
this.feedback = feedback;
|
|
||||||
this.feedbackArgs = feedbackArgs;
|
|
||||||
this.output = output;
|
|
||||||
this.outputArgs = outputArgs;
|
|
||||||
this.assignment = assignment;
|
|
||||||
this.attemptWasMade = attemptWasMade;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean assignmentSolved() {
|
public boolean assignmentSolved() {
|
||||||
return lessonCompleted;
|
return lessonCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AttackResult apply(PluginMessages pluginMessages) {
|
|
||||||
return new AttackResult(
|
|
||||||
lessonCompleted,
|
|
||||||
pluginMessages.getMessage(feedback, feedback, feedbackArgs),
|
|
||||||
pluginMessages.getMessage(output, output, outputArgs),
|
|
||||||
assignment,
|
|
||||||
attemptWasMade);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,130 +0,0 @@
|
|||||||
package org.owasp.webgoat.container.assignments;
|
|
||||||
|
|
||||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
|
||||||
|
|
||||||
public class AttackResultBuilder {
|
|
||||||
|
|
||||||
private PluginMessages messages;
|
|
||||||
private boolean lessonCompleted;
|
|
||||||
private Object[] feedbackArgs;
|
|
||||||
private String feedbackResourceBundleKey;
|
|
||||||
private String output;
|
|
||||||
private Object[] outputArgs;
|
|
||||||
private AssignmentEndpoint assignment;
|
|
||||||
private boolean attemptWasMade = false;
|
|
||||||
private boolean assignmentCompleted;
|
|
||||||
|
|
||||||
public AttackResultBuilder(PluginMessages messages) {
|
|
||||||
this.messages = messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder() {}
|
|
||||||
|
|
||||||
public AttackResultBuilder lessonCompleted(boolean lessonCompleted) {
|
|
||||||
this.lessonCompleted = lessonCompleted;
|
|
||||||
this.feedbackResourceBundleKey = "lesson.completed";
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder lessonCompleted(boolean lessonCompleted, String resourceBundleKey) {
|
|
||||||
this.lessonCompleted = lessonCompleted;
|
|
||||||
this.feedbackResourceBundleKey = resourceBundleKey;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder assignmentCompleted(boolean assignmentCompleted) {
|
|
||||||
this.assignmentCompleted = assignmentCompleted;
|
|
||||||
this.feedbackResourceBundleKey = "assignment.completed";
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder assignmentCompleted(
|
|
||||||
boolean assignmentCompleted, String resourceBundleKey) {
|
|
||||||
this.assignmentCompleted = assignmentCompleted;
|
|
||||||
this.feedbackResourceBundleKey = resourceBundleKey;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder feedbackArgs(Object... args) {
|
|
||||||
this.feedbackArgs = args;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder feedback(String resourceBundleKey) {
|
|
||||||
this.feedbackResourceBundleKey = resourceBundleKey;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder output(String output) {
|
|
||||||
this.output = output;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder outputArgs(Object... args) {
|
|
||||||
this.outputArgs = args;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder attemptWasMade() {
|
|
||||||
this.attemptWasMade = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResult build() {
|
|
||||||
return new AttackResult(
|
|
||||||
lessonCompleted,
|
|
||||||
feedbackResourceBundleKey,
|
|
||||||
feedbackArgs,
|
|
||||||
output,
|
|
||||||
outputArgs,
|
|
||||||
assignment.getClass().getSimpleName(),
|
|
||||||
attemptWasMade);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder assignment(AssignmentEndpoint assignment) {
|
|
||||||
this.assignment = assignment;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method for create a successful result:
|
|
||||||
*
|
|
||||||
* <p>- Assignment is set to solved - Feedback message is set to 'assignment.solved'
|
|
||||||
*
|
|
||||||
* <p>Of course you can overwrite these values in a specific lesson
|
|
||||||
*
|
|
||||||
* @return a builder for creating a result from a lesson
|
|
||||||
* @param assignment
|
|
||||||
*/
|
|
||||||
public static AttackResultBuilder success(AssignmentEndpoint assignment) {
|
|
||||||
return new AttackResultBuilder()
|
|
||||||
.lessonCompleted(true)
|
|
||||||
.assignmentCompleted(true)
|
|
||||||
.attemptWasMade()
|
|
||||||
.feedback("assignment.solved")
|
|
||||||
.assignment(assignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method for create a failed result:
|
|
||||||
*
|
|
||||||
* <p>- Assignment is set to not solved - Feedback message is set to 'assignment.not.solved'
|
|
||||||
*
|
|
||||||
* <p>Of course you can overwrite these values in a specific lesson
|
|
||||||
*
|
|
||||||
* @return a builder for creating a result from a lesson
|
|
||||||
* @param assignment
|
|
||||||
*/
|
|
||||||
public static AttackResultBuilder failed(AssignmentEndpoint assignment) {
|
|
||||||
return new AttackResultBuilder()
|
|
||||||
.lessonCompleted(false)
|
|
||||||
.assignmentCompleted(true)
|
|
||||||
.attemptWasMade()
|
|
||||||
.feedback("assignment.not.solved")
|
|
||||||
.assignment(assignment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
|
|
||||||
return new AttackResultBuilder().lessonCompleted(false).assignment(assignment);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package org.owasp.webgoat.container.assignments;
|
|
||||||
|
|
||||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
|
||||||
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.web.bind.annotation.RestControllerAdvice;
|
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
|
||||||
|
|
||||||
/** This class intercepts the response body and applies the plugin messages to the attack result. */
|
|
||||||
@RestControllerAdvice
|
|
||||||
public class AttackResultMessageResponseBodyAdvice implements ResponseBodyAdvice<Object> {
|
|
||||||
|
|
||||||
private final PluginMessages pluginMessages;
|
|
||||||
|
|
||||||
public AttackResultMessageResponseBodyAdvice(PluginMessages pluginMessages) {
|
|
||||||
this.pluginMessages = pluginMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(
|
|
||||||
MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object beforeBodyWrite(
|
|
||||||
Object body,
|
|
||||||
MethodParameter returnType,
|
|
||||||
MediaType selectedContentType,
|
|
||||||
Class<? extends HttpMessageConverter<?>> selectedConverterType,
|
|
||||||
ServerHttpRequest request,
|
|
||||||
ServerHttpResponse response) {
|
|
||||||
if (body instanceof AttackResult a) {
|
|
||||||
return a.apply(pluginMessages);
|
|
||||||
}
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,30 +22,27 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.container.assignments;
|
package org.owasp.webgoat.container.assignments;
|
||||||
|
|
||||||
import org.owasp.webgoat.container.lessons.Lesson;
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.owasp.webgoat.container.session.Course;
|
import org.owasp.webgoat.container.users.UserTracker;
|
||||||
import org.owasp.webgoat.container.users.UserProgress;
|
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
|
||||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.server.ServerHttpRequest;
|
import org.springframework.http.server.ServerHttpRequest;
|
||||||
import org.springframework.http.server.ServerHttpResponse;
|
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.bind.annotation.RestControllerAdvice;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||||
|
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> {
|
public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> {
|
||||||
|
|
||||||
private final Course course;
|
private UserTrackerRepository userTrackerRepository;
|
||||||
private final UserProgressRepository userProgressRepository;
|
private WebSession webSession;
|
||||||
|
|
||||||
public LessonTrackerInterceptor(Course course, UserProgressRepository userProgressRepository) {
|
public LessonTrackerInterceptor(
|
||||||
this.course = course;
|
UserTrackerRepository userTrackerRepository, WebSession webSession) {
|
||||||
this.userProgressRepository = userProgressRepository;
|
this.userTrackerRepository = userTrackerRepository;
|
||||||
|
this.webSession = webSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -68,30 +65,18 @@ public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> {
|
|||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void trackProgress(AttackResult attackResult) {
|
protected AttackResult trackProgress(AttackResult attackResult) {
|
||||||
var user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
Assert.notNull(user, "User not found in SecurityContext");
|
if (userTracker == null) {
|
||||||
var username = realUsername(user);
|
userTracker = new UserTracker(webSession.getUserName());
|
||||||
|
|
||||||
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()) {
|
if (attackResult.assignmentSolved()) {
|
||||||
userProgress.assignmentSolved(lesson, attackResult.getAssignment());
|
userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment());
|
||||||
} else {
|
} else {
|
||||||
userProgress.assignmentFailed(lesson);
|
userTracker.assignmentFailed(webSession.getCurrentLesson());
|
||||||
}
|
|
||||||
userProgressRepository.save(userProgress);
|
|
||||||
}
|
}
|
||||||
|
userTrackerRepository.save(userTracker);
|
||||||
|
|
||||||
private String realUsername(WebGoatUser user) {
|
return attackResult;
|
||||||
// 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,20 +33,42 @@ package org.owasp.webgoat.container.controller;
|
|||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.owasp.webgoat.container.session.Course;
|
import org.owasp.webgoat.container.session.Course;
|
||||||
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class StartLesson {
|
public class StartLesson {
|
||||||
|
|
||||||
|
private final WebSession ws;
|
||||||
private final Course course;
|
private final Course course;
|
||||||
|
|
||||||
public StartLesson(Course course) {
|
public StartLesson(WebSession ws, Course course) {
|
||||||
|
this.ws = ws;
|
||||||
this.course = course;
|
this.course = course;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(
|
/**
|
||||||
|
* 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(
|
||||||
value = {"*.lesson"},
|
value = {"*.lesson"},
|
||||||
produces = "text/html")
|
produces = "text/html")
|
||||||
public ModelAndView lessonPage(HttpServletRequest request) {
|
public ModelAndView lessonPage(HttpServletRequest request) {
|
||||||
@ -59,7 +81,8 @@ public class StartLesson {
|
|||||||
.findFirst()
|
.findFirst()
|
||||||
.ifPresent(
|
.ifPresent(
|
||||||
lesson -> {
|
lesson -> {
|
||||||
request.setAttribute("lesson", lesson);
|
ws.setCurrentLesson(lesson);
|
||||||
|
model.addObject("lesson", lesson);
|
||||||
});
|
});
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
@ -51,11 +51,10 @@ public class Assignment {
|
|||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private String path;
|
private String path;
|
||||||
private boolean solved = false;
|
|
||||||
|
|
||||||
@Transient private List<String> hints;
|
@Transient private List<String> hints;
|
||||||
|
|
||||||
protected Assignment() {
|
private Assignment() {
|
||||||
// Hibernate
|
// Hibernate
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,8 +74,4 @@ public class Assignment {
|
|||||||
this.path = path;
|
this.path = path;
|
||||||
this.hints = hints;
|
this.hints = hints;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void solved() {
|
|
||||||
this.solved = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -34,28 +34,30 @@ import lombok.Getter;
|
|||||||
* @since October 28, 2003
|
* @since October 28, 2003
|
||||||
*/
|
*/
|
||||||
public enum Category {
|
public enum Category {
|
||||||
INTRODUCTION("Introduction"),
|
INTRODUCTION("Introduction", 5),
|
||||||
GENERAL("General"),
|
GENERAL("General", 100),
|
||||||
|
|
||||||
A1("(A1) Broken Access Control"),
|
A1("(A1) Broken Access Control", 301),
|
||||||
A2("(A2) Cryptographic Failures"),
|
A2("(A2) Cryptographic Failures", 302),
|
||||||
A3("(A3) Injection"),
|
A3("(A3) Injection", 303),
|
||||||
|
|
||||||
A5("(A5) Security Misconfiguration"),
|
A5("(A5) Security Misconfiguration", 305),
|
||||||
A6("(A6) Vuln & Outdated Components"),
|
A6("(A6) Vuln & Outdated Components", 306),
|
||||||
A7("(A7) Identity & Auth Failure"),
|
A7("(A7) Identity & Auth Failure", 307),
|
||||||
A8("(A8) Software & Data Integrity"),
|
A8("(A8) Software & Data Integrity", 308),
|
||||||
A9("(A9) Security Logging Failures"),
|
A9("(A9) Security Logging Failures", 309),
|
||||||
A10("(A10) Server-side Request Forgery"),
|
A10("(A10) Server-side Request Forgery", 310),
|
||||||
|
|
||||||
CLIENT_SIDE("Client side"),
|
CLIENT_SIDE("Client side", 1700),
|
||||||
|
|
||||||
CHALLENGE("Challenges");
|
CHALLENGE("Challenges", 3000);
|
||||||
|
|
||||||
@Getter private String name;
|
@Getter private String name;
|
||||||
|
@Getter private Integer ranking;
|
||||||
|
|
||||||
Category(String name) {
|
Category(String name, Integer ranking) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.ranking = ranking;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,107 +22,58 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.container.lessons;
|
package org.owasp.webgoat.container.lessons;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.groupingBy;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
import org.owasp.webgoat.container.session.Course;
|
import org.owasp.webgoat.container.session.Course;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Configuration
|
@Configuration
|
||||||
public class CourseConfiguration {
|
public class CourseConfiguration {
|
||||||
|
|
||||||
private final List<Lesson> lessons;
|
private final List<Lesson> lessons;
|
||||||
private final List<AssignmentEndpoint> assignments;
|
private final List<AssignmentEndpoint> assignments;
|
||||||
private final String contextPath;
|
private final Map<String, List<AssignmentEndpoint>> assignmentsByPackage;
|
||||||
|
|
||||||
public CourseConfiguration(
|
public CourseConfiguration(List<Lesson> lessons, List<AssignmentEndpoint> assignments) {
|
||||||
List<Lesson> lessons,
|
|
||||||
List<AssignmentEndpoint> assignments,
|
|
||||||
@Value("${server.servlet.context-path}") String contextPath) {
|
|
||||||
this.lessons = lessons;
|
this.lessons = lessons;
|
||||||
this.assignments = assignments;
|
this.assignments = assignments;
|
||||||
this.contextPath = contextPath.equals("/") ? "" : contextPath;
|
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
|
@Bean
|
||||||
public Course course() {
|
public Course course() {
|
||||||
assignments.stream().forEach(this::attachToLesson);
|
lessons.stream().forEach(l -> l.setAssignments(createAssignment(l)));
|
||||||
|
|
||||||
// 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);
|
return new Course(lessons);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> findDiff() {
|
private List<Assignment> createAssignment(Lesson lesson) {
|
||||||
var matchedToLessons =
|
var endpoints = assignmentsByPackage.get(lesson.getClass().getPackageName());
|
||||||
lessons.stream().flatMap(l -> l.getAssignments().stream()).map(a -> a.getName()).toList();
|
if (CollectionUtils.isEmpty(endpoints)) {
|
||||||
var allAssignments = assignments.stream().map(a -> a.getClass().getSimpleName()).toList();
|
log.warn("Lesson: {} has no endpoints, is this intentionally?", lesson.getTitle());
|
||||||
|
return new ArrayList<>();
|
||||||
var diff = new ArrayList<>(allAssignments);
|
}
|
||||||
diff.removeAll(matchedToLessons);
|
return endpoints.stream()
|
||||||
return diff;
|
.map(
|
||||||
|
e ->
|
||||||
|
new Assignment(
|
||||||
|
e.getClass().getSimpleName(), getPath(e.getClass()), getHints(e.getClass())))
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPath(Class<? extends AssignmentEndpoint> e) {
|
private String getPath(Class<? extends AssignmentEndpoint> e) {
|
||||||
@ -130,7 +81,7 @@ public class CourseConfiguration {
|
|||||||
if (methodReturnTypeIsOfTypeAttackResult(m)) {
|
if (methodReturnTypeIsOfTypeAttackResult(m)) {
|
||||||
var mapping = getMapping(m);
|
var mapping = getMapping(m);
|
||||||
if (mapping != null) {
|
if (mapping != null) {
|
||||||
return contextPath + mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
* 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.
|
* when a users reset a lesson. Make sure to clean beforehand and then re-initialize the lesson.
|
||||||
*/
|
*/
|
||||||
public interface Initializable {
|
public interface Initializeable {
|
||||||
|
|
||||||
default void initialize(WebGoatUser webGoatUser) {}
|
void initialize(WebGoatUser webGoatUser);
|
||||||
}
|
}
|
@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.container.lessons;
|
package org.owasp.webgoat.container.lessons;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -31,10 +30,13 @@ import lombok.Setter;
|
|||||||
@Setter
|
@Setter
|
||||||
public abstract class Lesson {
|
public abstract class Lesson {
|
||||||
|
|
||||||
private List<Assignment> assignments = new ArrayList<>();
|
private static int count = 1;
|
||||||
|
private Integer id = null;
|
||||||
|
private List<Assignment> assignments;
|
||||||
|
|
||||||
public void addAssignment(Assignment assignment) {
|
/** Constructor for the Lesson object */
|
||||||
this.assignments.add(assignment);
|
protected Lesson() {
|
||||||
|
id = ++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,9 +44,9 @@ public abstract class Lesson {
|
|||||||
*
|
*
|
||||||
* @return a {@link java.lang.String} object.
|
* @return a {@link java.lang.String} object.
|
||||||
*/
|
*/
|
||||||
public LessonName getName() {
|
public String getName() {
|
||||||
String className = getClass().getName();
|
String className = getClass().getName();
|
||||||
return new LessonName(className.substring(className.lastIndexOf('.') + 1));
|
return className.substring(className.lastIndexOf('.') + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,10 +116,6 @@ public abstract class Lesson {
|
|||||||
return this.getClass().getSimpleName();
|
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() {
|
public final String getPackage() {
|
||||||
var packageName = this.getClass().getPackageName();
|
var packageName = this.getClass().getPackageName();
|
||||||
// package name is the direct package name below lessons (any subpackage will be removed)
|
// package name is the direct package name below lessons (any subpackage will be removed)
|
||||||
|
@ -35,5 +35,6 @@ package org.owasp.webgoat.container.lessons;
|
|||||||
*/
|
*/
|
||||||
public enum LessonMenuItemType {
|
public enum LessonMenuItemType {
|
||||||
CATEGORY,
|
CATEGORY,
|
||||||
LESSON
|
LESSON,
|
||||||
|
STAGE
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
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,42 @@
|
|||||||
|
package org.owasp.webgoat.container.lessons;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class LessonScanner {
|
||||||
|
|
||||||
|
private static final Pattern lessonPattern = Pattern.compile("^.*/lessons/([^/]*)/.*$");
|
||||||
|
|
||||||
|
@Getter private final Set<String> lessons = new HashSet<>();
|
||||||
|
|
||||||
|
public LessonScanner(ResourcePatternResolver resourcePatternResolver) {
|
||||||
|
try {
|
||||||
|
var resources = resourcePatternResolver.getResources("classpath:/lessons/*/*");
|
||||||
|
for (var resource : resources) {
|
||||||
|
// WG can run as a fat jar or as directly from file system we need to support both so use
|
||||||
|
// the URL
|
||||||
|
var url = resource.getURL();
|
||||||
|
var matcher = lessonPattern.matcher(url.toString());
|
||||||
|
if (matcher.matches()) {
|
||||||
|
lessons.add(matcher.group(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug("Found {} lessons", lessons.size());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("No lessons found...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> applyPattern(String pattern) {
|
||||||
|
return lessons.stream().map(lesson -> String.format(pattern, lesson)).toList();
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
package org.owasp.webgoat.container.report;
|
|
||||||
|
|
||||||
record LessonStatistics(String name, boolean solved, int numberOfAttempts) {}
|
|
@ -1,88 +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.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,24 +10,26 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.owasp.webgoat.container.lessons.Assignment;
|
import org.owasp.webgoat.container.lessons.Assignment;
|
||||||
import org.owasp.webgoat.container.lessons.Hint;
|
import org.owasp.webgoat.container.lessons.Hint;
|
||||||
import org.owasp.webgoat.container.session.Course;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HintService class.
|
||||||
|
*
|
||||||
|
* @author rlawson
|
||||||
|
* @version $Id: $Id
|
||||||
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
public class HintService {
|
public class HintService {
|
||||||
|
|
||||||
public static final String URL_HINTS_MVC = "/service/hint.mvc";
|
public static final String URL_HINTS_MVC = "/service/hint.mvc";
|
||||||
private final List<Hint> allHints;
|
private final WebSession webSession;
|
||||||
|
|
||||||
public HintService(Course course) {
|
public HintService(WebSession webSession) {
|
||||||
this.allHints =
|
this.webSession = webSession;
|
||||||
course.getLessons().stream()
|
|
||||||
.flatMap(lesson -> lesson.getAssignments().stream())
|
|
||||||
.map(this::createHint)
|
|
||||||
.flatMap(Collection::stream)
|
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +40,15 @@ public class HintService {
|
|||||||
@GetMapping(path = URL_HINTS_MVC, produces = "application/json")
|
@GetMapping(path = URL_HINTS_MVC, produces = "application/json")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public List<Hint> getHints() {
|
public List<Hint> getHints() {
|
||||||
return allHints;
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Hint> createHint(Assignment a) {
|
private List<Hint> createHint(Assignment a) {
|
||||||
|
@ -1,24 +1,33 @@
|
|||||||
package org.owasp.webgoat.container.service;
|
package org.owasp.webgoat.container.service;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
import org.owasp.webgoat.container.lessons.LessonInfoModel;
|
import org.owasp.webgoat.container.lessons.LessonInfoModel;
|
||||||
import org.owasp.webgoat.container.lessons.LessonName;
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.owasp.webgoat.container.session.Course;
|
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.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LessonInfoService class.
|
||||||
|
*
|
||||||
|
* @author dm
|
||||||
|
* @version $Id: $Id
|
||||||
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@AllArgsConstructor
|
||||||
public class LessonInfoService {
|
public class LessonInfoService {
|
||||||
|
|
||||||
private final Course course;
|
private final WebSession webSession;
|
||||||
|
|
||||||
@GetMapping(path = "/service/lessoninfo.mvc/{lesson}")
|
/**
|
||||||
public @ResponseBody LessonInfoModel getLessonInfo(
|
* getLessonInfo.
|
||||||
@PathVariable("lesson") LessonName lessonName) {
|
*
|
||||||
var lesson = course.getLessonByName(lessonName);
|
* @return a {@link LessonInfoModel} object.
|
||||||
|
*/
|
||||||
|
@RequestMapping(path = "/service/lessoninfo.mvc", produces = "application/json")
|
||||||
|
public @ResponseBody LessonInfoModel getLessonInfo() {
|
||||||
|
Lesson lesson = webSession.getCurrentLesson();
|
||||||
return new LessonInfoModel(lesson.getTitle(), false, false, false);
|
return new LessonInfoModel(lesson.getTitle(), false, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,16 +30,18 @@ package org.owasp.webgoat.container.service;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import lombok.AllArgsConstructor;
|
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.Category;
|
||||||
import org.owasp.webgoat.container.lessons.Lesson;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
import org.owasp.webgoat.container.lessons.LessonMenuItem;
|
import org.owasp.webgoat.container.lessons.LessonMenuItem;
|
||||||
import org.owasp.webgoat.container.lessons.LessonMenuItemType;
|
import org.owasp.webgoat.container.lessons.LessonMenuItemType;
|
||||||
import org.owasp.webgoat.container.session.Course;
|
import org.owasp.webgoat.container.session.Course;
|
||||||
import org.owasp.webgoat.container.users.LessonProgress;
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.owasp.webgoat.container.users.UserProgress;
|
import org.owasp.webgoat.container.users.LessonTracker;
|
||||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
import org.owasp.webgoat.container.users.UserTracker;
|
||||||
|
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -57,7 +59,8 @@ public class LessonMenuService {
|
|||||||
|
|
||||||
public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc";
|
public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc";
|
||||||
private final Course course;
|
private final Course course;
|
||||||
private UserProgressRepository userTrackerRepository;
|
private final WebSession webSession;
|
||||||
|
private UserTrackerRepository userTrackerRepository;
|
||||||
|
|
||||||
@Value("#{'${exclude.categories}'.split(',')}")
|
@Value("#{'${exclude.categories}'.split(',')}")
|
||||||
private List<String> excludeCategories;
|
private List<String> excludeCategories;
|
||||||
@ -71,13 +74,10 @@ public class LessonMenuService {
|
|||||||
* @return a {@link java.util.List} object.
|
* @return a {@link java.util.List} object.
|
||||||
*/
|
*/
|
||||||
@RequestMapping(path = URL_LESSONMENU_MVC, produces = "application/json")
|
@RequestMapping(path = URL_LESSONMENU_MVC, produces = "application/json")
|
||||||
public @ResponseBody List<LessonMenuItem> showLeftNav(@CurrentUsername String username) {
|
public @ResponseBody List<LessonMenuItem> showLeftNav() {
|
||||||
// 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<LessonMenuItem> menu = new ArrayList<>();
|
||||||
List<Category> categories = course.getCategories();
|
List<Category> categories = course.getCategories();
|
||||||
UserProgress userTracker = userTrackerRepository.findByUser(username);
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
|
|
||||||
for (Category category : categories) {
|
for (Category category : categories) {
|
||||||
if (excludeCategories.contains(category.name())) {
|
if (excludeCategories.contains(category.name())) {
|
||||||
@ -97,14 +97,28 @@ public class LessonMenuService {
|
|||||||
lessonItem.setName(lesson.getTitle());
|
lessonItem.setName(lesson.getTitle());
|
||||||
lessonItem.setLink(lesson.getLink());
|
lessonItem.setLink(lesson.getLink());
|
||||||
lessonItem.setType(LessonMenuItemType.LESSON);
|
lessonItem.setType(LessonMenuItemType.LESSON);
|
||||||
LessonProgress lessonTracker = userTracker.getLessonProgress(lesson);
|
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
|
||||||
boolean lessonSolved = lessonTracker.isLessonSolved();
|
boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson);
|
||||||
lessonItem.setComplete(lessonSolved);
|
lessonItem.setComplete(lessonSolved);
|
||||||
categoryItem.addChild(lessonItem);
|
categoryItem.addChild(lessonItem);
|
||||||
}
|
}
|
||||||
categoryItem.getChildren().sort(Comparator.comparingInt(LessonMenuItem::getRanking));
|
categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking());
|
||||||
menu.add(categoryItem);
|
menu.add(categoryItem);
|
||||||
}
|
}
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean lessonCompleted(Map<Assignment, Boolean> map, Lesson currentLesson) {
|
||||||
|
boolean result = true;
|
||||||
|
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
|
||||||
|
Assignment storedAssignment = entry.getKey();
|
||||||
|
for (Assignment lessonAssignment : currentLesson.getAssignments()) {
|
||||||
|
if (lessonAssignment.getName().equals(storedAssignment.getName())) {
|
||||||
|
result = result && entry.getValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,11 @@ import java.util.List;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.owasp.webgoat.container.CurrentUsername;
|
|
||||||
import org.owasp.webgoat.container.lessons.Assignment;
|
import org.owasp.webgoat.container.lessons.Assignment;
|
||||||
import org.owasp.webgoat.container.lessons.LessonName;
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.owasp.webgoat.container.session.Course;
|
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.util.Assert;
|
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.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,8 +20,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class LessonProgressService {
|
public class LessonProgressService {
|
||||||
|
|
||||||
private final UserProgressRepository userProgressRepository;
|
private final UserTrackerRepository userTrackerRepository;
|
||||||
private final Course course;
|
private final WebSession webSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Endpoint for fetching the complete lesson overview which informs the user about whether all the
|
* Endpoint for fetching the complete lesson overview which informs the user about whether all the
|
||||||
@ -33,20 +29,20 @@ public class LessonProgressService {
|
|||||||
*
|
*
|
||||||
* @return list of assignments
|
* @return list of assignments
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = "/service/lessonoverview.mvc/{lesson}")
|
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public List<LessonOverview> lessonOverview(
|
public List<LessonOverview> lessonOverview() {
|
||||||
@PathVariable("lesson") LessonName lessonName, @CurrentUsername String username) {
|
var userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
var userProgress = userProgressRepository.findByUser(username);
|
var currentLesson = webSession.getCurrentLesson();
|
||||||
var lesson = course.getLessonByName(lessonName);
|
|
||||||
|
|
||||||
Assert.isTrue(lesson != null, "Lesson not found: " + lessonName);
|
if (currentLesson != null) {
|
||||||
|
var lessonTracker = userTracker.getLessonTracker(currentLesson);
|
||||||
var lessonProgress = userProgress.getLessonProgress(lesson);
|
return lessonTracker.getLessonOverview().entrySet().stream()
|
||||||
return lessonProgress.getLessonOverview().entrySet().stream()
|
|
||||||
.map(entry -> new LessonOverview(entry.getKey(), entry.getValue()))
|
.map(entry -> new LessonOverview(entry.getKey(), entry.getValue()))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
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() : "";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* *************************************************************************************************
|
||||||
|
*
|
||||||
|
* <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,17 +29,14 @@ import java.util.function.Function;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flywaydb.core.Flyway;
|
import org.flywaydb.core.Flyway;
|
||||||
import org.owasp.webgoat.container.CurrentUser;
|
import org.owasp.webgoat.container.lessons.Initializeable;
|
||||||
import org.owasp.webgoat.container.lessons.Initializable;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
import org.owasp.webgoat.container.lessons.LessonName;
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.owasp.webgoat.container.session.Course;
|
import org.owasp.webgoat.container.users.UserTracker;
|
||||||
import org.owasp.webgoat.container.users.UserProgress;
|
import org.owasp.webgoat.container.users.UserTrackerRepository;
|
||||||
import org.owasp.webgoat.container.users.UserProgressRepository;
|
|
||||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@ -47,25 +44,25 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class RestartLessonService {
|
public class RestartLessonService {
|
||||||
|
|
||||||
private final Course course;
|
private final WebSession webSession;
|
||||||
private final UserProgressRepository userTrackerRepository;
|
private final UserTrackerRepository userTrackerRepository;
|
||||||
private final Function<String, Flyway> flywayLessons;
|
private final Function<String, Flyway> flywayLessons;
|
||||||
private final List<Initializable> lessonsToInitialize;
|
private final List<Initializeable> lessonsToInitialize;
|
||||||
|
|
||||||
@GetMapping(path = "/service/restartlesson.mvc/{lesson}")
|
@RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text")
|
||||||
@ResponseStatus(value = HttpStatus.OK)
|
@ResponseStatus(value = HttpStatus.OK)
|
||||||
public void restartLesson(
|
public void restartLesson() {
|
||||||
@PathVariable("lesson") LessonName lessonName, @CurrentUser WebGoatUser user) {
|
Lesson al = webSession.getCurrentLesson();
|
||||||
var lesson = course.getLessonByName(lessonName);
|
log.debug("Restarting lesson: " + al);
|
||||||
|
|
||||||
UserProgress userTracker = userTrackerRepository.findByUser(user.getUsername());
|
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
|
||||||
userTracker.reset(lesson);
|
userTracker.reset(al);
|
||||||
userTrackerRepository.save(userTracker);
|
userTrackerRepository.save(userTracker);
|
||||||
|
|
||||||
var flyway = flywayLessons.apply(user.getUsername());
|
var flyway = flywayLessons.apply(webSession.getUserName());
|
||||||
flyway.clean();
|
flyway.clean();
|
||||||
flyway.migrate();
|
flyway.migrate();
|
||||||
|
|
||||||
lessonsToInitialize.forEach(i -> i.initialize(user));
|
lessonsToInitialize.forEach(i -> i.initialize(webSession.getUser()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,8 @@
|
|||||||
package org.owasp.webgoat.container.service;
|
package org.owasp.webgoat.container.service;
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.owasp.webgoat.container.CurrentUser;
|
|
||||||
import org.owasp.webgoat.container.i18n.Messages;
|
import org.owasp.webgoat.container.i18n.Messages;
|
||||||
import org.owasp.webgoat.container.users.WebGoatUser;
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
@ -18,17 +17,17 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SessionService {
|
public class SessionService {
|
||||||
|
|
||||||
|
private final WebSession webSession;
|
||||||
private final RestartLessonService restartLessonService;
|
private final RestartLessonService restartLessonService;
|
||||||
private final Messages messages;
|
private final Messages messages;
|
||||||
|
|
||||||
@RequestMapping(path = "/service/enable-security.mvc", produces = "application/json")
|
@RequestMapping(path = "/service/enable-security.mvc", produces = "application/json")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public String applySecurity(@CurrentUser WebGoatUser user) {
|
public String applySecurity() {
|
||||||
// webSession.toggleSecurity();
|
webSession.toggleSecurity();
|
||||||
// restartLessonService.restartLesson(user);
|
restartLessonService.restartLesson();
|
||||||
|
|
||||||
// TODO disabled for now
|
var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled";
|
||||||
// var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled";
|
return messages.getMessage(msg);
|
||||||
return messages.getMessage("Not working...");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.owasp.webgoat.container.lessons.Category;
|
import org.owasp.webgoat.container.lessons.Category;
|
||||||
import org.owasp.webgoat.container.lessons.Lesson;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
import org.owasp.webgoat.container.lessons.LessonName;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ************************************************************************************************
|
* ************************************************************************************************
|
||||||
@ -97,21 +96,4 @@ public class Course {
|
|||||||
return this.lessons.stream()
|
return this.lessons.stream()
|
||||||
.reduce(0, (total, lesson) -> lesson.getAssignments().size() + total, Integer::sum);
|
.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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,32 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
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
|
@Entity
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
public class LessonProgress {
|
public class LessonTracker {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@ -61,22 +61,25 @@ public class LessonProgress {
|
|||||||
@Getter private String lessonName;
|
@Getter private String lessonName;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||||
private final Set<Assignment> assignments = new HashSet<>();
|
private final Set<Assignment> solvedAssignments = new HashSet<>();
|
||||||
|
|
||||||
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||||
|
private final Set<Assignment> allAssignments = new HashSet<>();
|
||||||
|
|
||||||
@Getter private int numberOfAttempts = 0;
|
@Getter private int numberOfAttempts = 0;
|
||||||
@Version private Integer version;
|
@Version private Integer version;
|
||||||
|
|
||||||
protected LessonProgress() {
|
private LessonTracker() {
|
||||||
// JPA
|
// JPA
|
||||||
}
|
}
|
||||||
|
|
||||||
public LessonProgress(Lesson lesson) {
|
public LessonTracker(Lesson lesson) {
|
||||||
lessonName = lesson.getId();
|
lessonName = lesson.getId();
|
||||||
assignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments());
|
allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Assignment> getAssignment(String name) {
|
public Optional<Assignment> getAssignment(String name) {
|
||||||
return assignments.stream().filter(a -> a.getName().equals(name)).findFirst();
|
return allAssignments.stream().filter(a -> a.getName().equals(name)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,14 +88,14 @@ public class LessonProgress {
|
|||||||
* @param solvedAssignment the assignment which the user solved
|
* @param solvedAssignment the assignment which the user solved
|
||||||
*/
|
*/
|
||||||
public void assignmentSolved(String solvedAssignment) {
|
public void assignmentSolved(String solvedAssignment) {
|
||||||
getAssignment(solvedAssignment).ifPresent(Assignment::solved);
|
getAssignment(solvedAssignment).ifPresent(solvedAssignments::add);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return did they user solved all solvedAssignments for the lesson?
|
* @return did they user solved all solvedAssignments for the lesson?
|
||||||
*/
|
*/
|
||||||
public boolean isLessonSolved() {
|
public boolean isLessonSolved() {
|
||||||
return assignments.stream().allMatch(Assignment::isSolved);
|
return allAssignments.size() == solvedAssignments.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Increase the number attempts to solve the lesson */
|
/** Increase the number attempts to solve the lesson */
|
||||||
@ -102,17 +105,18 @@ public class LessonProgress {
|
|||||||
|
|
||||||
/** Reset the tracker. We do not reset the number of attempts here! */
|
/** Reset the tracker. We do not reset the number of attempts here! */
|
||||||
void reset() {
|
void reset() {
|
||||||
assignments.clear();
|
solvedAssignments.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return list containing all the assignments solved or not
|
* @return list containing all the assignments solved or not
|
||||||
*/
|
*/
|
||||||
public Map<Assignment, Boolean> getLessonOverview() {
|
public Map<Assignment, Boolean> getLessonOverview() {
|
||||||
return assignments.stream().collect(Collectors.toMap(a -> a, Assignment::isSolved));
|
List<Assignment> notSolved =
|
||||||
}
|
allAssignments.stream().filter(i -> !solvedAssignments.contains(i)).toList();
|
||||||
|
Map<Assignment, Boolean> overview =
|
||||||
long numberOfSolvedAssignments() {
|
notSolved.stream().collect(Collectors.toMap(a -> a, b -> false));
|
||||||
return assignments.size();
|
overview.putAll(solvedAssignments.stream().collect(Collectors.toMap(a -> a, b -> true)));
|
||||||
|
return overview;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,10 +3,8 @@ package org.owasp.webgoat.container.users;
|
|||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.util.UUID;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -46,12 +44,4 @@ public class RegistrationController {
|
|||||||
|
|
||||||
return "redirect:/attack";
|
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
|
@AllArgsConstructor
|
||||||
public class Scoreboard {
|
public class Scoreboard {
|
||||||
|
|
||||||
private final UserProgressRepository userTrackerRepository;
|
private final UserTrackerRepository userTrackerRepository;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final Course course;
|
private final Course course;
|
||||||
private final PluginMessages pluginMessages;
|
private final PluginMessages pluginMessages;
|
||||||
@ -46,7 +46,7 @@ public class Scoreboard {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> challengesSolved(UserProgress userTracker) {
|
private List<String> challengesSolved(UserTracker userTracker) {
|
||||||
List<String> challenges =
|
List<String> challenges =
|
||||||
List.of(
|
List.of(
|
||||||
"Challenge1",
|
"Challenge1",
|
||||||
@ -59,10 +59,10 @@ public class Scoreboard {
|
|||||||
"Challenge8",
|
"Challenge8",
|
||||||
"Challenge9");
|
"Challenge9");
|
||||||
return challenges.stream()
|
return challenges.stream()
|
||||||
.map(userTracker::getLessonProgress)
|
.map(userTracker::getLessonTracker)
|
||||||
.flatMap(Optional::stream)
|
.flatMap(Optional::stream)
|
||||||
.filter(LessonProgress::isLessonSolved)
|
.filter(LessonTracker::isLessonSolved)
|
||||||
.map(LessonProgress::getLessonName)
|
.map(LessonTracker::getLessonName)
|
||||||
.map(this::toLessonTitle)
|
.map(this::toLessonTitle)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
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 java.util.function.Function;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.flywaydb.core.Flyway;
|
import org.flywaydb.core.Flyway;
|
||||||
import org.owasp.webgoat.container.lessons.Initializable;
|
import org.owasp.webgoat.container.lessons.Initializeable;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
@ -19,10 +19,10 @@ import org.springframework.stereotype.Service;
|
|||||||
public class UserService implements UserDetailsService {
|
public class UserService implements UserDetailsService {
|
||||||
|
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final UserProgressRepository userTrackerRepository;
|
private final UserTrackerRepository userTrackerRepository;
|
||||||
private final JdbcTemplate jdbcTemplate;
|
private final JdbcTemplate jdbcTemplate;
|
||||||
private final Function<String, Flyway> flywayLessons;
|
private final Function<String, Flyway> flywayLessons;
|
||||||
private final List<Initializable> lessonInitializables;
|
private final List<Initializeable> lessonInitializables;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException {
|
public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
@ -43,7 +43,7 @@ public class UserService implements UserDetailsService {
|
|||||||
|
|
||||||
if (!userAlreadyExists) {
|
if (!userAlreadyExists) {
|
||||||
userTrackerRepository.save(
|
userTrackerRepository.save(
|
||||||
new UserProgress(username)); // if user previously existed it will not get another tracker
|
new UserTracker(username)); // if user previously existed it will not get another tracker
|
||||||
createLessonsForUser(webGoatUser);
|
createLessonsForUser(webGoatUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,13 @@ import jakarta.persistence.GenerationType;
|
|||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.OneToMany;
|
import jakarta.persistence.OneToMany;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.owasp.webgoat.container.lessons.Assignment;
|
||||||
import org.owasp.webgoat.container.lessons.Lesson;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -49,7 +52,7 @@ import org.owasp.webgoat.container.lessons.Lesson;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Entity
|
@Entity
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
public class UserProgress {
|
public class UserTracker {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@ -59,11 +62,11 @@ public class UserProgress {
|
|||||||
private String user;
|
private String user;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||||
private Set<LessonProgress> lessonProgress = new HashSet<>();
|
private Set<LessonTracker> lessonTrackers = new HashSet<>();
|
||||||
|
|
||||||
protected UserProgress() {}
|
private UserTracker() {}
|
||||||
|
|
||||||
public UserProgress(final String user) {
|
public UserTracker(final String user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,15 +76,15 @@ public class UserProgress {
|
|||||||
* @param lesson the lesson
|
* @param lesson the lesson
|
||||||
* @return a lesson tracker created if not already present
|
* @return a lesson tracker created if not already present
|
||||||
*/
|
*/
|
||||||
public LessonProgress getLessonProgress(Lesson lesson) {
|
public LessonTracker getLessonTracker(Lesson lesson) {
|
||||||
Optional<LessonProgress> progress =
|
Optional<LessonTracker> lessonTracker =
|
||||||
lessonProgress.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst();
|
lessonTrackers.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst();
|
||||||
if (!progress.isPresent()) {
|
if (!lessonTracker.isPresent()) {
|
||||||
LessonProgress newLessonTracker = new LessonProgress(lesson);
|
LessonTracker newLessonTracker = new LessonTracker(lesson);
|
||||||
lessonProgress.add(newLessonTracker);
|
lessonTrackers.add(newLessonTracker);
|
||||||
return newLessonTracker;
|
return newLessonTracker;
|
||||||
} else {
|
} else {
|
||||||
return progress.get();
|
return lessonTracker.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,34 +94,43 @@ public class UserProgress {
|
|||||||
* @param id the id of the lesson
|
* @param id the id of the lesson
|
||||||
* @return optional due to the fact we can only create a lesson tracker based on a lesson
|
* @return optional due to the fact we can only create a lesson tracker based on a lesson
|
||||||
*/
|
*/
|
||||||
public Optional<LessonProgress> getLessonProgress(String id) {
|
public Optional<LessonTracker> getLessonTracker(String id) {
|
||||||
return lessonProgress.stream().filter(l -> l.getLessonName().equals(id)).findFirst();
|
return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assignmentSolved(Lesson lesson, String assignmentName) {
|
public void assignmentSolved(Lesson lesson, String assignmentName) {
|
||||||
LessonProgress progress = getLessonProgress(lesson);
|
LessonTracker lessonTracker = getLessonTracker(lesson);
|
||||||
progress.incrementAttempts();
|
lessonTracker.incrementAttempts();
|
||||||
progress.assignmentSolved(assignmentName);
|
lessonTracker.assignmentSolved(assignmentName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assignmentFailed(Lesson lesson) {
|
public void assignmentFailed(Lesson lesson) {
|
||||||
LessonProgress progress = getLessonProgress(lesson);
|
LessonTracker lessonTracker = getLessonTracker(lesson);
|
||||||
progress.incrementAttempts();
|
lessonTracker.incrementAttempts();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset(Lesson al) {
|
public void reset(Lesson al) {
|
||||||
LessonProgress progress = getLessonProgress(al);
|
LessonTracker lessonTracker = getLessonTracker(al);
|
||||||
progress.reset();
|
lessonTracker.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long numberOfLessonsSolved() {
|
public int numberOfLessonsSolved() {
|
||||||
return lessonProgress.stream().filter(LessonProgress::isLessonSolved).count();
|
int numberOfLessonsSolved = 0;
|
||||||
|
for (LessonTracker lessonTracker : lessonTrackers) {
|
||||||
|
if (lessonTracker.isLessonSolved()) {
|
||||||
|
numberOfLessonsSolved = numberOfLessonsSolved + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numberOfLessonsSolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long numberOfAssignmentsSolved() {
|
public int numberOfAssignmentsSolved() {
|
||||||
return lessonProgress.stream()
|
int numberOfAssignmentsSolved = 0;
|
||||||
.map(LessonProgress::numberOfSolvedAssignments)
|
for (LessonTracker lessonTracker : lessonTrackers) {
|
||||||
.mapToLong(Long::valueOf)
|
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
|
||||||
.sum();
|
numberOfAssignmentsSolved =
|
||||||
|
lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue();
|
||||||
|
}
|
||||||
|
return numberOfAssignmentsSolved;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
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);
|
||||||
|
}
|
@ -22,9 +22,6 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.lessons.authbypass;
|
package org.owasp.webgoat.lessons.authbypass;
|
||||||
|
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
|
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
|
|
||||||
|
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -35,7 +32,9 @@ import java.util.Map;
|
|||||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
||||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
import org.owasp.webgoat.container.session.LessonSession;
|
import org.owasp.webgoat.container.session.UserSessionData;
|
||||||
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
@ -49,13 +48,11 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
"auth-bypass.hints.verify.3",
|
"auth-bypass.hints.verify.3",
|
||||||
"auth-bypass.hints.verify.4"
|
"auth-bypass.hints.verify.4"
|
||||||
})
|
})
|
||||||
public class VerifyAccount implements AssignmentEndpoint {
|
public class VerifyAccount extends AssignmentEndpoint {
|
||||||
|
|
||||||
private final LessonSession userSessionData;
|
@Autowired private WebSession webSession;
|
||||||
|
|
||||||
public VerifyAccount(LessonSession userSessionData) {
|
@Autowired UserSessionData userSessionData;
|
||||||
this.userSessionData = userSessionData;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping(
|
@PostMapping(
|
||||||
path = "/auth-bypass/verify-account",
|
path = "/auth-bypass/verify-account",
|
||||||
|
@ -22,9 +22,6 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.lessons.bypassrestrictions;
|
package org.owasp.webgoat.lessons.bypassrestrictions;
|
||||||
|
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
|
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
|
|
||||||
|
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -33,7 +30,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
public class BypassRestrictionsFieldRestrictions implements AssignmentEndpoint {
|
public class BypassRestrictionsFieldRestrictions extends AssignmentEndpoint {
|
||||||
|
|
||||||
@PostMapping("/BypassRestrictions/FieldRestrictions")
|
@PostMapping("/BypassRestrictions/FieldRestrictions")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
|
@ -22,9 +22,6 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.lessons.bypassrestrictions;
|
package org.owasp.webgoat.lessons.bypassrestrictions;
|
||||||
|
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
|
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
|
|
||||||
|
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -33,7 +30,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
public class BypassRestrictionsFrontendValidation implements AssignmentEndpoint {
|
public class BypassRestrictionsFrontendValidation extends AssignmentEndpoint {
|
||||||
|
|
||||||
@PostMapping("/BypassRestrictions/frontendValidation")
|
@PostMapping("/BypassRestrictions/frontendValidation")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
|
@ -2,13 +2,11 @@ package org.owasp.webgoat.lessons.challenges;
|
|||||||
|
|
||||||
import org.owasp.webgoat.container.lessons.Category;
|
import org.owasp.webgoat.container.lessons.Category;
|
||||||
import org.owasp.webgoat.container.lessons.Lesson;
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author nbaars
|
* @author nbaars
|
||||||
* @since 3/21/17.
|
* @since 3/21/17.
|
||||||
*/
|
*/
|
||||||
@Component
|
|
||||||
public class ChallengeIntro extends Lesson {
|
public class ChallengeIntro extends Lesson {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,30 +22,27 @@
|
|||||||
|
|
||||||
package org.owasp.webgoat.lessons.challenges;
|
package org.owasp.webgoat.lessons.challenges;
|
||||||
|
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
|
import lombok.AllArgsConstructor;
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
|
|
||||||
|
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.owasp.webgoat.container.session.WebSession;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
public class FlagController implements AssignmentEndpoint {
|
@AllArgsConstructor
|
||||||
|
public class FlagController extends AssignmentEndpoint {
|
||||||
|
|
||||||
|
private final WebSession webSession;
|
||||||
private final Flags flags;
|
private final Flags flags;
|
||||||
|
|
||||||
public FlagController(Flags flags) {
|
@PostMapping(path = "/challenge/flag", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
this.flags = flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping(path = "/challenge/flag/{flagNumber}")
|
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AttackResult postFlag(@PathVariable int flagNumber, @RequestParam String flag) {
|
public AttackResult postFlag(@RequestParam String flag) {
|
||||||
var expectedFlag = flags.getFlag(flagNumber);
|
Flag expectedFlag = flags.getFlag(webSession.getCurrentLesson());
|
||||||
if (expectedFlag.isCorrect(flag)) {
|
if (expectedFlag.isCorrect(flag)) {
|
||||||
return success(this).feedback("challenge.flag.correct").build();
|
return success(this).feedback("challenge.flag.correct").build();
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,6 +4,7 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
import org.owasp.webgoat.container.lessons.Lesson;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ -14,6 +15,12 @@ public class Flags {
|
|||||||
IntStream.range(1, 10).forEach(i -> FLAGS.put(i, new Flag(i, UUID.randomUUID().toString())));
|
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) {
|
public Flag getFlag(int flagNumber) {
|
||||||
return FLAGS.get(flagNumber);
|
return FLAGS.get(flagNumber);
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user