diff --git a/.github/stale.yml b/.github/stale.yml index 619a771a4..1df9ad312 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -2,9 +2,9 @@ daysUntilStale: 90 daysUntilClose: 14 onlyLabels: - - waiting-for-input + - waiting for input - wontfix staleLabel: stale markComment: > This issue has been automatically marked as `stale` because it has not had recent activity. :calendar: It will be _closed automatically_ in one week if no further activity occurs. -closeComment: false \ No newline at end of file +closeComment: false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5376ac9b1..16a6cf2b8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,6 +47,8 @@ jobs: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2- + - name: Check code formatting + run: mvn --no-transfer-progress spotless:check - name: Build with Maven run: mvn --no-transfer-progress package @@ -68,5 +70,8 @@ jobs: path: ~/.m2 key: ubuntu-latest-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ubuntu-latest-m2- + - name: Check code formatting + #Fail fast + run: mvn --no-transfer-progress spotless:check - name: Test with Maven run: mvn --no-transfer-progress verify diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e1e172452..a6f530e5f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,5 @@ # Contributing + [![GitHub contributors](https://img.shields.io/github/contributors/WebGoat/WebGoat.svg)](https://github.com/WebGoat/WebGoat/graphs/contributors) ![GitHub issues by-label "help wanted"](https://img.shields.io/github/issues/WebGoat/WebGoat/help%20wanted.svg) ![GitHub issues by-label "good first issue"](https://img.shields.io/github/issues/WebGoat/WebGoat/good%20first%20issue.svg) @@ -24,7 +25,7 @@ There are a couple of ways on how you can contribute to the project: Your PR is valuable to us, and to make sure we can integrate it smoothly, we have a few items for you to consider. In short: The minimum requirements for code contributions are: -1. The code _must_ be compliant with the configured Checkstyle and PMD rules. +1. The code _must_ be compliant with the configured Java Google Formatter, Checkstyle and PMD rules. 2. All new and changed code _should_ have a corresponding unit and/or integration test. 3. New and changed lessons _must_ have a corresponding integration test. 4. [Status checks](https://docs.github.com/en/github/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/about-status-checks) should pass for your last commit. @@ -38,14 +39,13 @@ Pull requests should be as small/atomic as possible. Large, wide-sweeping change * If you are making spelling corrections in the docs, don't modify other files. * If you are adding new functions don't '*cleanup*' unrelated functions. That cleanup belongs in another pull request. - ### Write a good commit message * Explain why you make the changes. [More infos about a good commit message.](https://betterprogramming.pub/stop-writing-bad-commit-messages-8df79517177d) * If you fix an issue with your commit, please close the issue by [adding one of the keywords and the issue number](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) to your commit message. - For example: `Fix #545` or `Closes #10` +For example: `Fix #545` or `Closes #10` ## How to set up your Contributor Environment @@ -54,27 +54,34 @@ Pull requests should be as small/atomic as possible. Large, wide-sweeping change 3. Clone your own repository to your host computer so that you can make modifications. If you followed the GitHub tutorial from step 2, you have already done this. 4. Go to the newly cloned directory "WebGoat" and add the remote upstream repository: - ```bash - $ git remote -v - origin git@github.com:/WebGoat.git (fetch) - origin git@github.com:/WebGoat.git (push) + ```bash + $ git remote -v + origin git@github.com:/WebGoat.git (fetch) + origin git@github.com:/WebGoat.git (push) - $ git remote add upstream git@github.com:WebGoat/WebGoat.git + $ git remote add upstream git@github.com:WebGoat/WebGoat.git - $ git remote -v - origin git@github.com:/WebGoat.git (fetch) - origin git@github.com:/WebGoat.git (push) - upstream git@github.com:OWASP/WebGoat.git (fetch) - upstream git@github.com:OWASP/WebGoat.git (push) - ``` + $ git remote -v + origin git@github.com:/WebGoat.git (fetch) + origin git@github.com:/WebGoat.git (push) + upstream git@github.com:OWASP/WebGoat.git (fetch) + upstream git@github.com:OWASP/WebGoat.git (push) + ``` + + See also the GitHub documentation on "[Configuring a remote for a fork](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork "Configuring a remote for a fork")". - See also the GitHub documentation on "[Configuring a remote for a fork](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/configuring-a-remote-for-a-fork "Configuring a remote for a fork")". 5. Choose what to work on, based on any of the outstanding [issues](https://github.com/WebGoat/WebGoat/issues "WebGoat Issues"). + 6. Create a branch so that you can cleanly work on the chosen issue: `git checkout -b FixingIssue66` + 7. Open your favorite editor and start making modifications. We recommend using the [IntelliJ Idea](https://www.jetbrains.com/idea/). + 8. After your modifications are done, push them to your forked repository. This can be done by executing the command `git add MYFILE` for every file you have modified, followed by `git commit -m 'your commit message here'` to commit the modifications and `git push` to push your modifications to GitHub. + 9. Create a Pull Request (PR) by going to your fork, and click on the "New Pull Request" button. The target branch should typically be the Master branch. When submitting a PR, be sure to follow the checklist that is provided in the PR template. The checklist itself will be filled out by the reviewer. + 10. Your PR will be reviewed and comments may be given. In order to process a comment, simply make modifications to the same branch as before and push them to your repository. GitHub will automatically detect these changes and add them to your existing PR. + 11. When starting on a new PR in the future, make sure to always keep your local repo up to date: ```bash diff --git a/CREATE_RELEASE.md b/CREATE_RELEASE.md index 9daf57065..1c37fd033 100644 --- a/CREATE_RELEASE.md +++ b/CREATE_RELEASE.md @@ -1,21 +1,21 @@ ## Release WebGoat - ### Version numbers For WebGoat we use milestone releases first before we release the official version, we use `v8.0.0.M3` while tagging - and 8.0.0.M3 in the `pom.xml`. When we create the final release we remove the milestone release and use - `v8.0.0` in the `pom.xml` - +and 8.0.0.M3 in the `pom.xml`. When we create the final release we remove the milestone release and use +`v8.0.0` in the `pom.xml` + ### Release notes: -Update the release notes with the correct version. Use `git shortlog -s -n --since "SEP 31 2019"` for the list of + +Update the release notes with the correct version. Use `git shortlog -s -n --since "SEP 31 2019"` for the list of committers. At the moment we use Gitflow, for a release you create a new release branch and take the following steps: ``` git checkout develop -git flow release start +git flow release start git flow release publish <> @@ -30,5 +30,3 @@ git push --tags Now Travis takes over and will create the release in Github and on Docker Hub. NOTE: the `mvn versions:set` command above is just there to make sure the master branch contains the latest version - - diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md index 8a74ce118..f419c6ef6 100644 --- a/PULL_REQUEST_TEMPLATE.md +++ b/PULL_REQUEST_TEMPLATE.md @@ -1 +1 @@ -Thank you for submitting a pull request to the WebGoat! \ No newline at end of file +Thank you for submitting a pull request to the WebGoat! diff --git a/README.md b/README.md index 7bfae574d..ecda99449 100644 --- a/README.md +++ b/README.md @@ -44,13 +44,12 @@ docker run -it -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 -e TZ=Europe/Amster **Important**: *Choose the correct timezone, so that the docker container and your host are in the same timezone. As it is important for the validity of JWT tokens used in certain exercises.* - ## 2. Standalone Download the latest WebGoat release from [https://github.com/WebGoat/WebGoat/releases](https://github.com/WebGoat/WebGoat/releases) ```shell -java -Dfile.encoding=UTF-8 -Dwebgoat.port=8080 -Dwebwolf.port=9090 -jar webgoat-8.2.3.jar +java -Dfile.encoding=UTF-8 -Dwebgoat.port=8080 -Dwebwolf.port=9090 -jar webgoat-8.2.3.jar ``` Click the link in the log to start WebGoat. @@ -75,7 +74,7 @@ Now let's start by compiling the project. cd WebGoat git checkout <> # On Linux/Mac: -./mvnw clean install +./mvnw clean install # On Windows: ./mvnw.cmd clean install @@ -93,11 +92,11 @@ Now we are ready to run the project. WebGoat 8.x is using Spring-Boot. ./mvnw.cmd spring-boot:run ``` + ... you should be running WebGoat on http://localhost:8080/WebGoat momentarily. Note: The above link will redirect you to login page if you are not logged in. LogIn/Create account to proceed. - To change the IP address add the following variable to the `WebGoat/webgoat-container/src/main/resources/application.properties` file: ``` @@ -109,6 +108,7 @@ server.address=x.x.x.x For specialist only. There is a way to set up WebGoat with a personalized menu. You can leave out some menu categories or individual lessons by setting certain environment variables. For instance running as a jar on a Linux/macOS it will look like this: + ```Shell export EXCLUDE_CATEGORIES="CLIENT_SIDE,GENERAL,CHALLENGE" export EXCLUDE_LESSONS="SqlInjectionAdvanced,SqlInjectionMitigations" @@ -120,3 +120,4 @@ Or in a docker run it would (once this version is pushed into docker hub) look l ```Shell docker run -d -p 8080:8080 -p 9090:9090 -e TZ=Europe/Amsterdam -e EXCLUDE_CATEGORIES="CLIENT_SIDE,GENERAL,CHALLENGE" -e EXCLUDE_LESSONS="SqlInjectionAdvanced,SqlInjectionMitigations" webgoat/webgoat ``` + diff --git a/README_I18N.md b/README_I18N.md index ef14f191b..6a4769f1e 100644 --- a/README_I18N.md +++ b/README_I18N.md @@ -22,7 +22,7 @@ The following steps are required when you want to add a new language 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) 2. Add a highlighted section that explains that most parts of WebGoat will still be in English and invite people to translate parts where it would be valuable -5. Translate the main labels +5. Translate the main labels 1. Copy messages.properties to messages_es.properties (if in this case you want to add Spanish) 2. Translate the label values 6. Optionally translate lessons by diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 6263ff392..0e217e36e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,4 +1,4 @@ -# WebGoat release notes +# WebGoat release notes ## Unreleased @@ -6,14 +6,14 @@ - New year's resolution: major refactoring of WebGoat to simplify the setup and improve building times. - Move away from multi-project setup: - - This has a huge performance benefit when building the application. Build time locally is now `Total time: 42.469 s` (depends on your local machine of course) - - No longer add Maven dependencies in several places - - H2 no longer needs to run as separate process, which solves the issue of WebWolf sharing and needing to configure the correct database connection. + * This has a huge performance benefit when building the application. Build time locally is now `Total time: 42.469 s` (depends on your local machine of course) + * No longer add Maven dependencies in several places + * H2 no longer needs to run as separate process, which solves the issue of WebWolf sharing and needing to configure the correct database connection. - More explicit paths in html files to reference `adoc` files, less magic. - Integrate WebWolf in WebGoat, the setup was way too complicated and needed configuration which could lead to mistakes and a not working application. This also simplifies the Docker configuration as there is only 1 Docker image. - Add WebWolf button in WebGoat -- Move all lessons into `src/main/resources` -- WebGoat selects a port dynamically when starting. It will still start of port 8080 it will try another port to ease the user experience. +- Move all lessons into `src/main/resources` +- WebGoat selects a port dynamically when starting. It will still start of port 8080 it will try another port to ease the user experience. - WebGoat logs URL after startup: `Please browse to http://127.0.0.1:8080/WebGoat to get started...` - Simplify `Dockerfile` as we no longer need a script to start everything - Maven build now start WebGoat jar with Maven plugin to make sure we run against the latest build. @@ -35,7 +35,7 @@ ### New functionality -- Docker image now supports nginx when browsing to http://localhost a landing page is shown. +- Docker image now supports nginx when browsing to http://localhost a landing page is shown. ### Bug fixes @@ -43,14 +43,12 @@ - [#1031 SQL Injection (intro) 5: Data Control Language (DCL) the wiki's solution is not correct](https://github.com/WebGoat/WebGoat/issues/1031) - [#1027 Webgoat 8.2.1 Vulnerable_Components_12 Shows internal server error](https://github.com/WebGoat/WebGoat/issues/1027) - ## Version 8.2.1 ### New functionality - New Docker image for arm64 architecture is now available (for Apple M1) - ## Version 8.2.0 ### New functionality @@ -85,11 +83,10 @@ Special thanks to the following contributors providing us with a pull request: - maximmasiutin - toshihue - avivmu -- KellyMarchewa +- KellyMarchewa - NatasG - gabe-sky - ## Version 8.1.0 ### New functionality @@ -97,27 +94,27 @@ Special thanks to the following contributors providing us with a pull request: - Added new lessons for cryptography and path-traversal - Extra content added to the XXE lesson - Explanation of the assignments will be part of WebGoat, in this release we added detailed descriptions on how to solve the XXE lesson. In the upcoming releases new explanations will be added. If you want to contribute please create a pull request on Github. -- Docker improvements + docker stack for complete container with nginx -- Included JWT token decoding and generation, since jwt.io does not support None anymore +- Docker improvements + docker stack for complete container with nginx +- Included JWT token decoding and generation, since jwt.io does not support None anymore ### Bug fixes - [#743 - Character encoding errors](https://github.com/WebGoat/WebGoat/issues/743) - [#811 - Flag submission fails](https://github.com/WebGoat/WebGoat/issues/811) - [#810 - Scoreboard for challenges shows csrf users](https://github.com/WebGoat/WebGoat/issues/810) -- [#788 - strange copy in constructor](https://github.com/WebGoat/WebGoat/issues/788) +- [#788 - strange copy in constructor](https://github.com/WebGoat/WebGoat/issues/788) - [#760 - Execution of standalone jar fails (Flyway migration step](https://github.com/WebGoat/WebGoat/issues/760) - [#766 - Unclear objective of vulnerable components practical assignment](https://github.com/WebGoat/WebGoat/issues/766) - [#708 - Seems like the home directory of WebGoat always use @project.version@](https://github.com/WebGoat/WebGoat/issues/708) - [#719 - WebGoat: 'Contact Us' email link in header is not correctly set](https://github.com/WebGoat/WebGoat/issues/719) - - [#715 - Reset lesson doesn't reset the "HTML lesson" => forms stay succesful](https://github.com/WebGoat/WebGoat/issues/715) - - [#725 - Vulnerable Components lesson 12 broken due to too new dependency](https://github.com/WebGoat/WebGoat/issues/725) - - [#716 - On M26 @project.version@ is not "interpreted" #7](https://github.com/WebGoat/WebGoat/issues/716) - - [#721 couldn't be able to run CSRF lesson 3: Receive Whitelabel Error Page](https://github.com/WebGoat/WebGoat/issues/721) - - [#724 - Dead link in VulnerableComponents lesson 11](https://github.com/WebGoat/WebGoat/issues/724) - - ## Contributors - +- [#715 - Reset lesson doesn't reset the "HTML lesson" => forms stay succesful](https://github.com/WebGoat/WebGoat/issues/715) +- [#725 - Vulnerable Components lesson 12 broken due to too new dependency](https://github.com/WebGoat/WebGoat/issues/725) +- [#716 - On M26 @project.version@ is not "interpreted" #7](https://github.com/WebGoat/WebGoat/issues/716) +- [#721 couldn't be able to run CSRF lesson 3: Receive Whitelabel Error Page](https://github.com/WebGoat/WebGoat/issues/721) +- [#724 - Dead link in VulnerableComponents lesson 11](https://github.com/WebGoat/WebGoat/issues/724) + +## Contributors + Special thanks to the following contributors providing us with a pull request: - Satoshi SAKAO @@ -132,9 +129,5 @@ Special thanks to the following contributors providing us with a pull request: And everyone who provided feedback through Github. - Team WebGoat - - - diff --git a/docs/README.md b/docs/README.md index ec3085b27..6f0484341 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,4 +2,3 @@ Old GitHub page which now redirects to OWASP website. - diff --git a/pom.xml b/pom.xml index 3c07b76dd..21dcfc4c7 100644 --- a/pom.xml +++ b/pom.xml @@ -1,674 +1,726 @@ - - + + - 4.0.0 - org.owasp.webgoat - webgoat - jar - 8.2.3-SNAPSHOT + 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.7.1 - + + org.springframework.boot + spring-boot-starter-parent + 2.7.1 + + org.owasp.webgoat + webgoat + 8.2.3-SNAPSHOT + jar - WebGoat - WebGoat, a deliberately insecure Web Application - 2006 + WebGoat + WebGoat, a deliberately insecure Web Application + https://github.com/WebGoat/WebGoat + 2006 + + OWASP + https://github.com/WebGoat/WebGoat/ + + + + GNU General Public License, version 2 + https://www.gnu.org/licenses/gpl-2.0.txt + + + + + mayhew64 + Bruce Mayhew + webgoat@owasp.org + OWASP + https://github.com/WebGoat/WebGoat + + + nbaars + Nanne Baars + nanne.baars@owasp.org + https://github.com/nbaars + Europe/Amsterdam + + + misfir3 + Jason White + jason.white@owasp.org + + + zubcevic + René Zubcevic + rene.zubcevic@owasp.org + + + aolle + Àngel Ollé Blázquez + angel@olleb.com + + + jwayman + Jeff Wayman + + + + dcowden + Dave Cowden + + + + lawson89 + Richard Lawson + + + + dougmorato + Doug Morato + doug.morato@owasp.org + OWASP + https://github.com/dougmorato + America/New_York + + https://avatars2.githubusercontent.com/u/9654?v=3&s=150 + + + + + + + OWASP WebGoat Mailing List + https://lists.owasp.org/mailman/listinfo/owasp-webgoat + Owasp-webgoat-request@lists.owasp.org + owasp-webgoat@lists.owasp.org + http://lists.owasp.org/pipermail/owasp-webgoat/ + + + + + scm:git:git@github.com:WebGoat/WebGoat.git + scm:git:git@github.com:WebGoat/WebGoat.git + HEAD https://github.com/WebGoat/WebGoat - - OWASP - https://github.com/WebGoat/WebGoat/ - - - - GNU General Public License, version 2 - https://www.gnu.org/licenses/gpl-2.0.txt - - - - - mayhew64 - Bruce Mayhew - webgoat@owasp.org - OWASP - https://github.com/WebGoat/WebGoat - - - nbaars - Nanne Baars - nanne.baars@owasp.org - https://github.com/nbaars - Europe/Amsterdam - - - misfir3 - Jason White - jason.white@owasp.org - - - zubcevic - René Zubcevic - rene.zubcevic@owasp.org - - - aolle - Àngel Ollé Blázquez - angel@olleb.com - - - jwayman - Jeff Wayman - - - - dcowden - Dave Cowden - - - - lawson89 - Richard Lawson - - - - dougmorato - Doug Morato - doug.morato@owasp.org - OWASP - https://github.com/dougmorato - America/New_York - - https://avatars2.githubusercontent.com/u/9654?v=3&s=150 - - - + - - - OWASP WebGoat Mailing List - https://lists.owasp.org/mailman/listinfo/owasp-webgoat - Owasp-webgoat-request@lists.owasp.org - owasp-webgoat@lists.owasp.org - http://lists.owasp.org/pipermail/owasp-webgoat/ - - + + Github Issues + https://github.com/WebGoat/WebGoat/issues + - - https://github.com/WebGoat/WebGoat - scm:git:git@github.com:WebGoat/WebGoat.git - scm:git:git@github.com:WebGoat/WebGoat.git - HEAD - - - - Github Issues - https://github.com/WebGoat/WebGoat/issues - - - - - UTF-8 - UTF-8 - 17 - 17 - 17 - 8080 - 9090 - - - 2.5.3 - 3.3.7 - 2.2 - 3.1.2 - 3.2.1 - 3.12.0 - 2.6 - 1.9 - 30.1-jre - 0.9.1 - 0.7.6 - 1.14.3 - 3.5.1 - 3.8.0 - 2.22.0 - 3.1.2 - 3.1.1 - 3.1.0 - 3.0.0-M5 - 3.15.0 - 3.0.15.RELEASE - 4.3.1 - 2.27.2 - 1.2 - 1.4.5 - 1.5.2 - - - - - - - org.ow2.asm - asm - 9.1 - - - - org.apache.commons - commons-exec - 1.3 - - - org.asciidoctor - asciidoctorj - ${asciidoctorj.version} - - - - org.jsoup - jsoup - ${jsoup.version} - - - com.nulab-inc - zxcvbn - ${zxcvbn.version} - - - com.thoughtworks.xstream - xstream - ${xstream.version} - - - cglib - cglib-nodep - ${cglib.version} - - - xml-resolver - xml-resolver - ${xml-resolver.version} - - - io.jsonwebtoken - jjwt - ${jjwt.version} - - - com.google.guava - guava - ${guava.version} - - - commons-io - commons-io - ${commons-io.version} - - - org.apache.commons - commons-text - ${commons-text.version} - - - org.bitbucket.b_c - jose4j - ${jose4j.version} - - - org.webjars - bootstrap - ${bootstrap.version} - - - org.webjars - jquery - ${jquery.version} - - - com.github.tomakehurst - wiremock - ${wiremock.version} - - - io.github.bonigarcia - webdrivermanager - ${webdriver.version} - - - org.apache.commons - commons-compress - 1.21 - - - org.jruby - jruby - 9.3.6.0 - - - - - - - local-server - - - start-server - - true - - - - - org.codehaus.mojo - build-helper-maven-plugin - - - reserve-container-port - - reserve-network-port - - process-resources - - - webgoat.port - webwolf.port - jmxPort - - - - - - - com.bazaarvoice.maven.plugins - process-exec-maven-plugin - 0.9 - - - start-jar - pre-integration-test - - start - - - ${project.build.directory} - - java - -jar - -Dlogging.pattern.console= - -Dspring.main.banner-mode=off - -Dspring.datasource.url=jdbc:hsqldb:file:${java.io.tmpdir}/webgoat - - -Dwebgoat.port=${webgoat.port} - -Dwebwolf.port=${webwolf.port} - --add-opens - java.base/java.lang=ALL-UNNAMED - --add-opens - java.base/java.util=ALL-UNNAMED - --add-opens - java.base/java.lang.reflect=ALL-UNNAMED - --add-opens - java.base/java.text=ALL-UNNAMED - --add-opens - java.desktop/java.beans=ALL-UNNAMED - --add-opens - java.desktop/java.awt.font=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 - - ${project.build.directory}/webgoat-${project.version}.jar - - - false - http://localhost:${webgoat.port}/WebGoat/ - - - - stop-jar-process - post-integration-test - - stop-all - - - - - - - - - owasp - - false - - - - - org.owasp - dependency-check-maven - 6.5.1 - - 7 - false - false - - - - ${maven.multiModuleProjectDirectory}/config/dependency-check/project-suppression.xml - - - - - - - check - - - - - - - - + + + 2.5.3 + 3.3.7 + 2.2 + + 3.1.2 + 3.2.1 + 2.6 + 3.12.0 + 1.9 + 30.1-jre + 17 + 0.9.1 + 0.7.6 + 3.5.1 + 1.14.3 + 3.8.0 + 2.22.0 + 3.1.2 + 3.1.1 + 3.1.0 + 3.0.0-M5 + 17 + 17 + 3.15.0 + + UTF-8 + UTF-8 + 3.0.15.RELEASE + 4.3.1 + 8080 + 9090 + 2.27.2 + 1.2 + 1.4.5 + + 1.5.2 + + - - org.apache.commons - commons-exec - - - org.springframework.boot - spring-boot-starter-validation - - - org.projectlombok - lombok - provided - true - - - javax.xml.bind - jaxb-api - - - org.springframework.boot - spring-boot-starter-undertow - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-tomcat - - - - - org.springframework.boot - spring-boot-starter-actuator - - - org.flywaydb - flyway-core - - - org.asciidoctor - asciidoctorj - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-security - - - org.springframework.boot - spring-boot-starter-thymeleaf - - - org.thymeleaf.extras - thymeleaf-extras-springsecurity5 - - - org.hsqldb - hsqldb - - - org.jsoup - jsoup - - - com.nulab-inc - zxcvbn - - - com.thoughtworks.xstream - xstream - - - cglib - cglib-nodep - - - xml-resolver - xml-resolver - - - io.jsonwebtoken - jjwt - - - com.google.guava - guava - - - commons-io - commons-io - - - org.apache.commons - commons-lang3 - - - org.apache.commons - commons-text - - - org.bitbucket.b_c - jose4j - - - org.webjars - bootstrap - - - org.webjars - jquery - - - org.glassfish.jaxb - jaxb-runtime - - - org.springframework.boot - spring-boot-starter-test - test - - - org.springframework.security - spring-security-test - test - - - com.github.tomakehurst - wiremock - test - - - io.rest-assured - rest-assured - test - + + org.ow2.asm + asm + 9.1 + + + + org.apache.commons + commons-exec + 1.3 + + + org.asciidoctor + asciidoctorj + ${asciidoctorj.version} + + + + org.jsoup + jsoup + ${jsoup.version} + + + com.nulab-inc + zxcvbn + ${zxcvbn.version} + + + com.thoughtworks.xstream + xstream + ${xstream.version} + + + cglib + cglib-nodep + ${cglib.version} + + + xml-resolver + xml-resolver + ${xml-resolver.version} + + + io.jsonwebtoken + jjwt + ${jjwt.version} + + + com.google.guava + guava + ${guava.version} + + + commons-io + commons-io + ${commons-io.version} + + + org.apache.commons + commons-text + ${commons-text.version} + + + org.bitbucket.b_c + jose4j + ${jose4j.version} + + + org.webjars + bootstrap + ${bootstrap.version} + + + org.webjars + jquery + ${jquery.version} + + + com.github.tomakehurst + wiremock + ${wiremock.version} + + + io.github.bonigarcia + webdrivermanager + ${webdriver.version} + + + org.apache.commons + commons-compress + 1.21 + + + org.jruby + jruby + 9.3.6.0 + + - + + + org.apache.commons + commons-exec + + + org.springframework.boot + spring-boot-starter-validation + + + org.projectlombok + lombok + provided + true + + + javax.xml.bind + jaxb-api + + + org.springframework.boot + spring-boot-starter-undertow + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.flywaydb + flyway-core + + + org.asciidoctor + asciidoctorj + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity5 + + + org.hsqldb + hsqldb + + + org.jsoup + jsoup + + + com.nulab-inc + zxcvbn + + + com.thoughtworks.xstream + xstream + + + cglib + cglib-nodep + + + xml-resolver + xml-resolver + + + io.jsonwebtoken + jjwt + + + com.google.guava + guava + + + commons-io + commons-io + + + org.apache.commons + commons-lang3 + + + org.apache.commons + commons-text + + + org.bitbucket.b_c + jose4j + + + org.webjars + bootstrap + + + org.webjars + jquery + + + org.glassfish.jaxb + jaxb-runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + com.github.tomakehurst + wiremock + test + + + io.rest-assured + rest-assured + test + + + + + + + false + + central + https://repo.maven.apache.org/maven2 + + + + + + false + + central + https://repo.maven.apache.org/maven2 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + true + org.owasp.webgoat.server.StartWebGoat + + + + org.asciidoctor + asciidoctorj + + + + + + + repackage + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-integration-test-source-as-test-sources + + add-test-source + + generate-test-sources + + + src/it/java + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + ${basedir}/src/test/resources/logback-test.xml + + -Xmx512m -Dwebgoatport=${webgoat.port} -Dwebwolfport=${webwolf.port} + org/owasp/webgoat/*Test + + + + integration-test + + integration-test + + + + verify + + verify + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + --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.text=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED + + **/*IntegrationTest.java + src/it/java + org/owasp/webgoat/*Test + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.version} + + UTF-8 + true + true + config/checkstyle/checkstyle.xml + config/checkstyle/suppressions.xml + checkstyle.suppressions.file + + + + com.diffplug.spotless + spotless-maven-plugin + 2.29.0 + + + + + .gitignore + + + + + true + 4 + + + + + + **/*.md + + + + + + + + true + + + + + UTF-8 + ${line.separator} + true + false + true + 2 + false + false + recommended_2008_06 + true + true + true + + + + + + + check + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0 + + + restrict-log4j-versions + + enforce + + validate + + + + + org.apache.logging.log4j:log4j-core + + + + true + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + + + + + + + + local-server + + + start-server + + true + + - - org.springframework.boot - spring-boot-maven-plugin - - - - repackage - - - + + org.codehaus.mojo + build-helper-maven-plugin + + + reserve-container-port + + reserve-network-port + + process-resources - true - true - org.owasp.webgoat.server.StartWebGoat - - - - org.asciidoctor - asciidoctorj - - + + webgoat.port + webwolf.port + jmxPort + - - - org.codehaus.mojo - build-helper-maven-plugin - - - add-integration-test-source-as-test-sources - generate-test-sources - - add-test-source - - - - src/it/java - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin + + + + + com.bazaarvoice.maven.plugins + process-exec-maven-plugin + 0.9 + + + start-jar + + start + + pre-integration-test - - ${basedir}/src/test/resources/logback-test.xml - - -Xmx512m -Dwebgoatport=${webgoat.port} -Dwebwolfport=${webwolf.port} - org/owasp/webgoat/*Test + ${project.build.directory} + + java + -jar + -Dlogging.pattern.console= + -Dspring.main.banner-mode=off + -Dspring.datasource.url=jdbc:hsqldb:file:${java.io.tmpdir}/webgoat + -Dwebgoat.port=${webgoat.port} + -Dwebwolf.port=${webwolf.port} + --add-opens + java.base/java.lang=ALL-UNNAMED + --add-opens + java.base/java.util=ALL-UNNAMED + --add-opens + java.base/java.lang.reflect=ALL-UNNAMED + --add-opens + java.base/java.text=ALL-UNNAMED + --add-opens + java.desktop/java.beans=ALL-UNNAMED + --add-opens + java.desktop/java.awt.font=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 + ${project.build.directory}/webgoat-${project.version}.jar + + false + http://localhost:${webgoat.port}/WebGoat/ - - - integration-test - - integration-test - - - - verify - - verify - - - - - - org.apache.maven.plugins - maven-surefire-plugin - ${maven-surefire-plugin.version} - - - --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.text=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED - - - **/*IntegrationTest.java - src/it/java - org/owasp/webgoat/*Test - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - ${checkstyle.version} - - UTF-8 - true - true - config/checkstyle/checkstyle.xml - config/checkstyle/suppressions.xml - checkstyle.suppressions.file - - - - org.apache.maven.plugins - maven-enforcer-plugin - 3.0.0 - - - restrict-log4j-versions - validate - - enforce - - - - - - org.apache.logging.log4j:log4j-core - - - - true - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 17 - 17 - - + + + stop-jar-process + + stop-all + + post-integration-test + + + - - - - - central - https://repo.maven.apache.org/maven2 - - false - - - - - - central - https://repo.maven.apache.org/maven2 - - false - - - + + + + owasp + + false + + + + + org.owasp + dependency-check-maven + 6.5.1 + + 7 + false + false + + + ${maven.multiModuleProjectDirectory}/config/dependency-check/project-suppression.xml + + + + + + check + + + + + + + + diff --git a/robot/README.md b/robot/README.md index 7acf94023..5ed805c9f 100644 --- a/robot/README.md +++ b/robot/README.md @@ -2,17 +2,18 @@ ## Install Chromedriver on Mac OS - brew install cask chromedriver - chromedriver --version + brew install cask chromedriver + chromedriver --version Then see security settings and allow the file to run ## Install - pip3 install virtualenv --user - python3 -m virtualenv .venv - source .venv/bin/activate - pip install robotframework - pip install robotframework-SeleniumLibrary - pip install webdriver-manager - robot --variable HEADLESS:"0" --variable ENDPOINT:"http://127.0.0.1:8080/WebGoat" goat.robot + pip3 install virtualenv --user + python3 -m virtualenv .venv + source .venv/bin/activate + pip install robotframework + pip install robotframework-SeleniumLibrary + pip install webdriver-manager + robot --variable HEADLESS:"0" --variable ENDPOINT:"http://127.0.0.1:8080/WebGoat" goat.robot + diff --git a/src/main/java/org/dummy/insecure/framework/VulnerableTaskHolder.java b/src/main/java/org/dummy/insecure/framework/VulnerableTaskHolder.java index 3dccbb916..98c37a64e 100644 --- a/src/main/java/org/dummy/insecure/framework/VulnerableTaskHolder.java +++ b/src/main/java/org/dummy/insecure/framework/VulnerableTaskHolder.java @@ -1,74 +1,76 @@ package org.dummy.insecure.framework; -import lombok.extern.slf4j.Slf4j; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.Serializable; import java.time.LocalDateTime; +import lombok.extern.slf4j.Slf4j; @Slf4j -//TODO move back to lesson +// TODO move back to lesson public class VulnerableTaskHolder implements Serializable { - private static final long serialVersionUID = 2; + private static final long serialVersionUID = 2; - private String taskName; - private String taskAction; - private LocalDateTime requestedExecutionTime; - - public VulnerableTaskHolder(String taskName, String taskAction) { - super(); - this.taskName = taskName; - this.taskAction = taskAction; - this.requestedExecutionTime = LocalDateTime.now(); - } - - @Override - public String toString() { - return "VulnerableTaskHolder [taskName=" + taskName + ", taskAction=" + taskAction + ", requestedExecutionTime=" - + requestedExecutionTime + "]"; - } + private String taskName; + private String taskAction; + private LocalDateTime requestedExecutionTime; - /** - * Execute a task when de-serializing a saved or received object. - * @author stupid develop - */ - private void readObject( ObjectInputStream stream ) throws Exception { - //unserialize data so taskName and taskAction are available - stream.defaultReadObject(); - - //do something with the data - log.info("restoring task: {}", taskName); - log.info("restoring time: {}", requestedExecutionTime); - - if (requestedExecutionTime!=null && - (requestedExecutionTime.isBefore(LocalDateTime.now().minusMinutes(10)) - || requestedExecutionTime.isAfter(LocalDateTime.now()))) { - //do nothing is the time is not within 10 minutes after the object has been created - log.debug(this.toString()); - throw new IllegalArgumentException("outdated"); - } - - //condition is here to prevent you from destroying the goat altogether - if ((taskAction.startsWith("sleep")||taskAction.startsWith("ping")) - && taskAction.length() < 22) { - log.info("about to execute: {}", taskAction); - try { - Process p = Runtime.getRuntime().exec(taskAction); - BufferedReader in = new BufferedReader( - new InputStreamReader(p.getInputStream())); - String line = null; - while ((line = in.readLine()) != null) { - log.info(line); - } - } catch (IOException e) { - log.error("IO Exception", e); - } - } - + public VulnerableTaskHolder(String taskName, String taskAction) { + super(); + this.taskName = taskName; + this.taskAction = taskAction; + this.requestedExecutionTime = LocalDateTime.now(); + } + + @Override + public String toString() { + return "VulnerableTaskHolder [taskName=" + + taskName + + ", taskAction=" + + taskAction + + ", requestedExecutionTime=" + + requestedExecutionTime + + "]"; + } + + /** + * Execute a task when de-serializing a saved or received object. + * + * @author stupid develop + */ + private void readObject(ObjectInputStream stream) throws Exception { + // unserialize data so taskName and taskAction are available + stream.defaultReadObject(); + + // do something with the data + log.info("restoring task: {}", taskName); + log.info("restoring time: {}", requestedExecutionTime); + + if (requestedExecutionTime != null + && (requestedExecutionTime.isBefore(LocalDateTime.now().minusMinutes(10)) + || requestedExecutionTime.isAfter(LocalDateTime.now()))) { + // do nothing is the time is not within 10 minutes after the object has been created + log.debug(this.toString()); + throw new IllegalArgumentException("outdated"); } - + + // condition is here to prevent you from destroying the goat altogether + if ((taskAction.startsWith("sleep") || taskAction.startsWith("ping")) + && taskAction.length() < 22) { + log.info("about to execute: {}", taskAction); + try { + Process p = Runtime.getRuntime().exec(taskAction); + BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line = null; + while ((line = in.readLine()) != null) { + log.info(line); + } + } catch (IOException e) { + log.error("IO Exception", e); + } + } + } } diff --git a/src/main/java/org/owasp/webgoat/container/AjaxAuthenticationEntryPoint.java b/src/main/java/org/owasp/webgoat/container/AjaxAuthenticationEntryPoint.java index 67b0cf977..1ed96e146 100644 --- a/src/main/java/org/owasp/webgoat/container/AjaxAuthenticationEntryPoint.java +++ b/src/main/java/org/owasp/webgoat/container/AjaxAuthenticationEntryPoint.java @@ -1,59 +1,59 @@ /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - *

- * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository * for free software projects. */ - package org.owasp.webgoat.container; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; - +import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; /** - *

AjaxAuthenticationEntryPoint class.

+ * AjaxAuthenticationEntryPoint class. * * @author zupzup */ - public class AjaxAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { - public AjaxAuthenticationEntryPoint(String loginFormUrl) { - super(loginFormUrl); - } + public AjaxAuthenticationEntryPoint(String loginFormUrl) { + super(loginFormUrl); + } - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { - if (request.getHeader("x-requested-with") != null) { - response.sendError(401, authException.getMessage()); - } else { - super.commence(request, response, authException); - } + @Override + public void commence( + HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) + throws IOException, ServletException { + if (request.getHeader("x-requested-with") != null) { + response.sendError(401, authException.getMessage()); + } else { + super.commence(request, response, authException); } + } } diff --git a/src/main/java/org/owasp/webgoat/container/AsciiDoctorTemplateResolver.java b/src/main/java/org/owasp/webgoat/container/AsciiDoctorTemplateResolver.java index fddf3e053..723e8cb7c 100644 --- a/src/main/java/org/owasp/webgoat/container/AsciiDoctorTemplateResolver.java +++ b/src/main/java/org/owasp/webgoat/container/AsciiDoctorTemplateResolver.java @@ -1,37 +1,47 @@ - /** * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat * @version $Id: $Id * @since December 12, 2015 */ - package org.owasp.webgoat.container; +import static org.asciidoctor.Asciidoctor.Factory.create; + import io.undertow.util.Headers; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.asciidoctor.Asciidoctor; import org.asciidoctor.extension.JavaExtensionRegistry; @@ -46,113 +56,117 @@ import org.thymeleaf.templateresolver.FileTemplateResolver; import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.StringTemplateResource; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.StringWriter; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import static org.asciidoctor.Asciidoctor.Factory.create; - /** * Thymeleaf resolver for AsciiDoc used in the lesson, can be used as follows inside a lesson file: - *

- * + * + *

*

* */ @Slf4j public class AsciiDoctorTemplateResolver extends FileTemplateResolver { - private static final Asciidoctor asciidoctor = create(); - private static final String PREFIX = "doc:"; + private static final Asciidoctor asciidoctor = create(); + private static final String PREFIX = "doc:"; - private final Language language; - private final ResourceLoader resourceLoader; + private final Language language; + private final ResourceLoader resourceLoader; - public AsciiDoctorTemplateResolver(Language language, ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - this.language = language; - setResolvablePatterns(Set.of(PREFIX + "*")); + public AsciiDoctorTemplateResolver(Language language, ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + this.language = language; + setResolvablePatterns(Set.of(PREFIX + "*")); + } + + @Override + protected ITemplateResource computeTemplateResource( + IEngineConfiguration configuration, + String ownerTemplate, + String template, + String resourceName, + String characterEncoding, + Map templateResolutionAttributes) { + var templateName = resourceName.substring(PREFIX.length()); + log.debug("template used: {}", templateName); + try (InputStream is = getInputStream(templateName)) { + JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry(); + extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class); + extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class); + extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class); + extensionRegistry.inlineMacro("webGoatTempDir", WebGoatTmpDirMacro.class); + extensionRegistry.inlineMacro("operatingSystem", OperatingSystemMacro.class); + extensionRegistry.inlineMacro("username", UsernameMacro.class); + + StringWriter writer = new StringWriter(); + asciidoctor.convert(new InputStreamReader(is), writer, createAttributes()); + return new StringTemplateResource(writer.getBuffer().toString()); + } catch (IOException e) { + return new StringTemplateResource( + "
Unable to find documentation for: " + templateName + "
"); } + } - @Override - protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map templateResolutionAttributes) { - var templateName = resourceName.substring(PREFIX.length()); - log.debug("template used: {}", templateName); - try (InputStream is = getInputStream(templateName)) { - JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry(); - extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class); - extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class); - extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class); - extensionRegistry.inlineMacro("webGoatTempDir", WebGoatTmpDirMacro.class); - extensionRegistry.inlineMacro("operatingSystem", OperatingSystemMacro.class); - extensionRegistry.inlineMacro("username", UsernameMacro.class); - - StringWriter writer = new StringWriter(); - asciidoctor.convert(new InputStreamReader(is), writer, createAttributes()); - return new StringTemplateResource(writer.getBuffer().toString()); - } catch (IOException e) { - return new StringTemplateResource("
Unable to find documentation for: " + templateName + "
"); - } + private InputStream getInputStream(String templateName) throws IOException { + log.debug("locale: {}", language.getLocale().getLanguage()); + String computedResourceName = + computeResourceName(templateName, language.getLocale().getLanguage()); + if (resourceLoader + .getResource("classpath:/" + computedResourceName) + .isReadable() /*isFile()*/) { + log.debug("localized file exists"); + return resourceLoader.getResource("classpath:/" + computedResourceName).getInputStream(); + } else { + log.debug("using english template"); + return resourceLoader.getResource("classpath:/" + templateName).getInputStream(); } + } - private InputStream getInputStream(String templateName) throws IOException { - log.debug("locale: {}",language.getLocale().getLanguage()); - String computedResourceName = computeResourceName(templateName, language.getLocale().getLanguage()); - if (resourceLoader.getResource("classpath:/" + computedResourceName).isReadable()/*isFile()*/) { - log.debug("localized file exists"); - return resourceLoader.getResource("classpath:/" + computedResourceName).getInputStream(); - } else { - log.debug("using english template"); - return resourceLoader.getResource("classpath:/" + templateName).getInputStream(); - } + private String computeResourceName(String resourceName, String language) { + String computedResourceName; + if (language.equals("en")) { + computedResourceName = resourceName; + } else { + computedResourceName = resourceName.replace(".adoc", "_".concat(language).concat(".adoc")); } - private String computeResourceName(String resourceName, String language) { - String computedResourceName; - if (language.equals("en")) { - computedResourceName = resourceName; - } else { - computedResourceName = resourceName.replace(".adoc", "_".concat(language).concat(".adoc")); - } - log.debug("computed local file name: {}", computedResourceName); - log.debug("file exists: {}",resourceLoader.getResource("classpath:/"+computedResourceName).isReadable()); - return computedResourceName; - } - - private Map createAttributes() { - Map attributes = new HashMap<>(); - attributes.put("source-highlighter", "coderay"); - attributes.put("backend", "xhtml"); - attributes.put("lang", determineLanguage()); - attributes.put("icons", org.asciidoctor.Attributes.FONT_ICONS); - - Map options = new HashMap<>(); - options.put("attributes", attributes); - - return options; - } - - private String determineLanguage() { - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); - - Locale browserLocale = (Locale) request.getSession().getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME); - if (null != browserLocale) { - log.debug("browser locale {}", browserLocale); - return browserLocale.getLanguage(); - } else { - String langHeader = request.getHeader(Headers.ACCEPT_LANGUAGE_STRING); - if (null != langHeader) { - log.debug("browser locale {}", langHeader); - return langHeader.substring(0,2); - } else { - log.debug("browser default english"); - return "en"; - } - } + log.debug("computed local file name: {}", computedResourceName); + log.debug( + "file exists: {}", + resourceLoader.getResource("classpath:/" + computedResourceName).isReadable()); + return computedResourceName; + } + + private Map createAttributes() { + Map attributes = new HashMap<>(); + attributes.put("source-highlighter", "coderay"); + attributes.put("backend", "xhtml"); + attributes.put("lang", determineLanguage()); + attributes.put("icons", org.asciidoctor.Attributes.FONT_ICONS); + + Map options = new HashMap<>(); + options.put("attributes", attributes); + + return options; + } + + private String determineLanguage() { + HttpServletRequest request = + ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + + Locale browserLocale = + (Locale) + request.getSession().getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME); + if (null != browserLocale) { + log.debug("browser locale {}", browserLocale); + return browserLocale.getLanguage(); + } else { + String langHeader = request.getHeader(Headers.ACCEPT_LANGUAGE_STRING); + if (null != langHeader) { + log.debug("browser locale {}", langHeader); + return langHeader.substring(0, 2); + } else { + log.debug("browser default english"); + return "en"; + } } + } } diff --git a/src/main/java/org/owasp/webgoat/container/DatabaseConfiguration.java b/src/main/java/org/owasp/webgoat/container/DatabaseConfiguration.java index 28559c92a..ef54ff007 100644 --- a/src/main/java/org/owasp/webgoat/container/DatabaseConfiguration.java +++ b/src/main/java/org/owasp/webgoat/container/DatabaseConfiguration.java @@ -1,5 +1,8 @@ package org.owasp.webgoat.container; +import java.util.Map; +import java.util.function.Function; +import javax.sql.DataSource; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flywaydb.core.Flyway; @@ -11,58 +14,54 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.jdbc.datasource.DriverManagerDataSource; -import javax.sql.DataSource; -import java.util.Map; -import java.util.function.Function; - @Configuration @RequiredArgsConstructor @Slf4j public class DatabaseConfiguration { - private final DataSourceProperties properties; - private final LessonScanner lessonScanner; + private final DataSourceProperties properties; + private final LessonScanner lessonScanner; - @Bean - @Primary - public DataSource dataSource() { - DriverManagerDataSource dataSource = new DriverManagerDataSource(); - dataSource.setDriverClassName(properties.getDriverClassName()); - dataSource.setUrl(properties.getUrl()); - dataSource.setUsername(properties.getUsername()); - dataSource.setPassword(properties.getPassword()); - return dataSource; - } + @Bean + @Primary + public DataSource dataSource() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(properties.getDriverClassName()); + dataSource.setUrl(properties.getUrl()); + dataSource.setUsername(properties.getUsername()); + dataSource.setPassword(properties.getPassword()); + return dataSource; + } - /** - * Define 2 Flyway instances, 1 for WebGoat itself which it uses for internal storage like users and 1 for lesson - * specific tables we use. This way we clean the data in the lesson database quite easily see {@link RestartLessonService#restartLesson()} - * for how we clean the lesson related tables. - */ - @Bean(initMethod = "migrate") - public Flyway flyWayContainer() { - return Flyway - .configure() - .configuration(Map.of("driver", properties.getDriverClassName())) - .dataSource(dataSource()) - .schemas("container") - .locations("db/container") - .load(); - } + /** + * Define 2 Flyway instances, 1 for WebGoat itself which it uses for internal storage like users + * and 1 for lesson specific tables we use. This way we clean the data in the lesson database + * quite easily see {@link RestartLessonService#restartLesson()} for how we clean the lesson + * related tables. + */ + @Bean(initMethod = "migrate") + public Flyway flyWayContainer() { + return Flyway.configure() + .configuration(Map.of("driver", properties.getDriverClassName())) + .dataSource(dataSource()) + .schemas("container") + .locations("db/container") + .load(); + } - @Bean - public Function flywayLessons(LessonDataSource lessonDataSource) { - return schema -> Flyway - .configure() - .configuration(Map.of("driver", properties.getDriverClassName())) - .schemas(schema) - .dataSource(lessonDataSource) - .locations("lessons") - .load(); - } + @Bean + public Function flywayLessons(LessonDataSource lessonDataSource) { + return schema -> + Flyway.configure() + .configuration(Map.of("driver", properties.getDriverClassName())) + .schemas(schema) + .dataSource(lessonDataSource) + .locations("lessons") + .load(); + } - @Bean - public LessonDataSource lessonDataSource() { - return new LessonDataSource(dataSource()); - } + @Bean + public LessonDataSource lessonDataSource() { + return new LessonDataSource(dataSource()); + } } diff --git a/src/main/java/org/owasp/webgoat/container/HammerHead.java b/src/main/java/org/owasp/webgoat/container/HammerHead.java index b186a1b9f..04fd73ce5 100644 --- a/src/main/java/org/owasp/webgoat/container/HammerHead.java +++ b/src/main/java/org/owasp/webgoat/container/HammerHead.java @@ -9,30 +9,29 @@ import org.springframework.web.servlet.ModelAndView; /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - *

- * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository * for free software projects. * * @author Jeff Williams @@ -45,13 +44,13 @@ import org.springframework.web.servlet.ModelAndView; @AllArgsConstructor public class HammerHead { - private final Course course; + private final Course course; - /** - * Entry point for WebGoat, redirects to the first lesson found within the course. - */ - @RequestMapping(path = "/attack", method = {RequestMethod.GET, RequestMethod.POST}) - public ModelAndView attack() { - return new ModelAndView("redirect:" + "start.mvc" + course.getFirstLesson().getLink()); - } + /** Entry point for WebGoat, redirects to the first lesson found within the course. */ + @RequestMapping( + path = "/attack", + method = {RequestMethod.GET, RequestMethod.POST}) + public ModelAndView attack() { + return new ModelAndView("redirect:" + "start.mvc" + course.getFirstLesson().getLink()); + } } diff --git a/src/main/java/org/owasp/webgoat/container/LessonDataSource.java b/src/main/java/org/owasp/webgoat/container/LessonDataSource.java index e386a67ae..c09f69d12 100644 --- a/src/main/java/org/owasp/webgoat/container/LessonDataSource.java +++ b/src/main/java/org/owasp/webgoat/container/LessonDataSource.java @@ -1,70 +1,70 @@ package org.owasp.webgoat.container; -import org.owasp.webgoat.container.lessons.LessonConnectionInvocationHandler; -import org.springframework.jdbc.datasource.ConnectionProxy; - -import javax.sql.DataSource; import java.io.PrintWriter; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.logging.Logger; +import javax.sql.DataSource; +import org.owasp.webgoat.container.lessons.LessonConnectionInvocationHandler; +import org.springframework.jdbc.datasource.ConnectionProxy; public class LessonDataSource implements DataSource { - private final DataSource originalDataSource; + private final DataSource originalDataSource; - public LessonDataSource(DataSource dataSource) { - this.originalDataSource = dataSource; - } + public LessonDataSource(DataSource dataSource) { + this.originalDataSource = dataSource; + } - @Override - public Connection getConnection() throws SQLException { - var targetConnection = originalDataSource.getConnection(); - return (Connection) Proxy.newProxyInstance( - ConnectionProxy.class.getClassLoader(), - new Class[]{ConnectionProxy.class}, - new LessonConnectionInvocationHandler(targetConnection)); - } + @Override + public Connection getConnection() throws SQLException { + var targetConnection = originalDataSource.getConnection(); + return (Connection) + Proxy.newProxyInstance( + ConnectionProxy.class.getClassLoader(), + new Class[] {ConnectionProxy.class}, + new LessonConnectionInvocationHandler(targetConnection)); + } - @Override - public Connection getConnection(String username, String password) throws SQLException { - return originalDataSource.getConnection(username, password); - } + @Override + public Connection getConnection(String username, String password) throws SQLException { + return originalDataSource.getConnection(username, password); + } - @Override - public PrintWriter getLogWriter() throws SQLException { - return originalDataSource.getLogWriter(); - } + @Override + public PrintWriter getLogWriter() throws SQLException { + return originalDataSource.getLogWriter(); + } - @Override - public void setLogWriter(PrintWriter out) throws SQLException { - originalDataSource.setLogWriter(out); - } + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + originalDataSource.setLogWriter(out); + } - @Override - public void setLoginTimeout(int seconds) throws SQLException { - originalDataSource.setLoginTimeout(seconds); - } + @Override + public void setLoginTimeout(int seconds) throws SQLException { + originalDataSource.setLoginTimeout(seconds); + } - @Override - public int getLoginTimeout() throws SQLException { - return originalDataSource.getLoginTimeout(); - } + @Override + public int getLoginTimeout() throws SQLException { + return originalDataSource.getLoginTimeout(); + } - @Override - public Logger getParentLogger() throws SQLFeatureNotSupportedException { - return originalDataSource.getParentLogger(); - } + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return originalDataSource.getParentLogger(); + } - @Override - public T unwrap(Class clazz) throws SQLException { - return originalDataSource.unwrap(clazz); - } + @Override + public T unwrap(Class clazz) throws SQLException { + return originalDataSource.unwrap(clazz); + } - @Override - public boolean isWrapperFor(Class clazz) throws SQLException { - return originalDataSource.isWrapperFor(clazz); - } + @Override + public boolean isWrapperFor(Class clazz) throws SQLException { + return originalDataSource.isWrapperFor(clazz); + } } diff --git a/src/main/java/org/owasp/webgoat/container/LessonTemplateResolver.java b/src/main/java/org/owasp/webgoat/container/LessonTemplateResolver.java index 732deb519..cfd569720 100644 --- a/src/main/java/org/owasp/webgoat/container/LessonTemplateResolver.java +++ b/src/main/java/org/owasp/webgoat/container/LessonTemplateResolver.java @@ -1,36 +1,41 @@ /** * ************************************************************************************************ + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author WebGoat * @version $Id: $Id * @since October 28, 2003 */ - package org.owasp.webgoat.container; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import lombok.extern.slf4j.Slf4j; import org.springframework.core.io.ResourceLoader; import org.thymeleaf.IEngineConfiguration; @@ -38,45 +43,48 @@ import org.thymeleaf.templateresolver.FileTemplateResolver; import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.StringTemplateResource; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - /** - * Dynamically resolve a lesson. In the html file this can be invoked as: - * - * + * Dynamically resolve a lesson. In the html file this can be invoked as: *

* - *

- * Thymeleaf will invoke this resolver based on the prefix and this implementation will resolve the html in the plugins directory + * + *

Thymeleaf will invoke this resolver based on the prefix and this implementation will resolve + * the html in the plugins directory */ @Slf4j public class LessonTemplateResolver extends FileTemplateResolver { - private static final String PREFIX = "lesson:"; - private ResourceLoader resourceLoader; - private Map resources = new HashMap<>(); + private static final String PREFIX = "lesson:"; + private ResourceLoader resourceLoader; + private Map resources = new HashMap<>(); - public LessonTemplateResolver(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - setResolvablePatterns(Set.of(PREFIX + "*")); - } + public LessonTemplateResolver(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + setResolvablePatterns(Set.of(PREFIX + "*")); + } - @Override - protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map templateResolutionAttributes) { - var templateName = resourceName.substring(PREFIX.length()); - byte[] resource = resources.get(templateName); - if (resource == null) { - try { - resource = resourceLoader.getResource("classpath:/" + templateName).getInputStream().readAllBytes(); - } catch (IOException e) { - log.error("Unable to find lesson HTML: {}", template); - } - resources.put(templateName, resource); - } - return new StringTemplateResource(new String(resource, StandardCharsets.UTF_8)); + @Override + protected ITemplateResource computeTemplateResource( + IEngineConfiguration configuration, + String ownerTemplate, + String template, + String resourceName, + String characterEncoding, + Map templateResolutionAttributes) { + var templateName = resourceName.substring(PREFIX.length()); + byte[] resource = resources.get(templateName); + if (resource == null) { + try { + resource = + resourceLoader + .getResource("classpath:/" + templateName) + .getInputStream() + .readAllBytes(); + } catch (IOException e) { + log.error("Unable to find lesson HTML: {}", template); + } + resources.put(templateName, resource); } + return new StringTemplateResource(new String(resource, StandardCharsets.UTF_8)); + } } diff --git a/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java b/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java index ad0851aa9..114157a90 100644 --- a/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java +++ b/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java @@ -1,36 +1,40 @@ /** * ************************************************************************************************ + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author WebGoat * @version $Id: $Id * @since October 28, 2003 */ - package org.owasp.webgoat.container; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Set; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.i18n.Language; @@ -62,175 +66,195 @@ import org.thymeleaf.templateresolver.ITemplateResolver; import org.thymeleaf.templateresource.ITemplateResource; import org.thymeleaf.templateresource.StringTemplateResource; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.Set; - -/** - * Configuration for Spring MVC - */ +/** Configuration for Spring MVC */ @Configuration @RequiredArgsConstructor @Slf4j public class MvcConfiguration implements WebMvcConfigurer { - private static final String UTF8 = "UTF-8"; + private static final String UTF8 = "UTF-8"; - private final LessonScanner lessonScanner; + private final LessonScanner lessonScanner; - @Override - public void addViewControllers(ViewControllerRegistry registry) { - registry.addViewController("/login").setViewName("login"); - registry.addViewController("/lesson_content").setViewName("lesson_content"); - registry.addViewController("/start.mvc").setViewName("main_new"); - registry.addViewController("/scoreboard").setViewName("scoreboard"); - } + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/login").setViewName("login"); + registry.addViewController("/lesson_content").setViewName("lesson_content"); + registry.addViewController("/start.mvc").setViewName("main_new"); + registry.addViewController("/scoreboard").setViewName("scoreboard"); + } - @Bean - public ViewResolver viewResolver(SpringTemplateEngine thymeleafTemplateEngine) { - ThymeleafViewResolver resolver = new ThymeleafViewResolver(); - resolver.setTemplateEngine(thymeleafTemplateEngine); - resolver.setCharacterEncoding(StandardCharsets.UTF_8.displayName()); - return resolver; - } + @Bean + public ViewResolver viewResolver(SpringTemplateEngine thymeleafTemplateEngine) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(thymeleafTemplateEngine); + resolver.setCharacterEncoding(StandardCharsets.UTF_8.displayName()); + return resolver; + } - /** - * Responsible for loading lesson templates based on Thymeleaf, for example: - * - *

- */ - @Bean - public ITemplateResolver lessonThymeleafTemplateResolver(ResourceLoader resourceLoader) { - var resolver = new FileTemplateResolver() { - @Override - protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map templateResolutionAttributes) { - try (var is = resourceLoader.getResource("classpath:" + resourceName).getInputStream()) { - return new StringTemplateResource(new String(is.readAllBytes(), StandardCharsets.UTF_8)); - } catch (IOException e) { - return null; - } + /** + * Responsible for loading lesson templates based on Thymeleaf, for example: + * + *

+ */ + @Bean + public ITemplateResolver lessonThymeleafTemplateResolver(ResourceLoader resourceLoader) { + var resolver = + new FileTemplateResolver() { + @Override + protected ITemplateResource computeTemplateResource( + IEngineConfiguration configuration, + String ownerTemplate, + String template, + String resourceName, + String characterEncoding, + Map templateResolutionAttributes) { + try (var is = + resourceLoader.getResource("classpath:" + resourceName).getInputStream()) { + return new StringTemplateResource( + new String(is.readAllBytes(), StandardCharsets.UTF_8)); + } catch (IOException e) { + return null; } + } }; - resolver.setOrder(1); - return resolver; - } + resolver.setOrder(1); + return resolver; + } - /** - * Loads all normal WebGoat specific Thymeleaf templates - */ - @Bean - public ITemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) { - SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); - resolver.setPrefix("classpath:/webgoat/templates/"); - resolver.setSuffix(".html"); - resolver.setTemplateMode(TemplateMode.HTML); - resolver.setOrder(2); - resolver.setCharacterEncoding(UTF8); - resolver.setApplicationContext(applicationContext); - return resolver; - } + /** Loads all normal WebGoat specific Thymeleaf templates */ + @Bean + public ITemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) { + SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); + resolver.setPrefix("classpath:/webgoat/templates/"); + resolver.setSuffix(".html"); + resolver.setTemplateMode(TemplateMode.HTML); + resolver.setOrder(2); + resolver.setCharacterEncoding(UTF8); + resolver.setApplicationContext(applicationContext); + return resolver; + } - /** - * Loads the html for the complete lesson, see lesson_content.html - */ - @Bean - public LessonTemplateResolver lessonTemplateResolver(ResourceLoader resourceLoader) { - LessonTemplateResolver resolver = new LessonTemplateResolver(resourceLoader); - resolver.setOrder(0); - resolver.setCacheable(false); - resolver.setCharacterEncoding(UTF8); - return resolver; - } + /** Loads the html for the complete lesson, see lesson_content.html */ + @Bean + public LessonTemplateResolver lessonTemplateResolver(ResourceLoader resourceLoader) { + LessonTemplateResolver resolver = new LessonTemplateResolver(resourceLoader); + resolver.setOrder(0); + resolver.setCacheable(false); + resolver.setCharacterEncoding(UTF8); + return resolver; + } - /** - * Loads the lesson asciidoc. - */ - @Bean - public AsciiDoctorTemplateResolver asciiDoctorTemplateResolver(Language language, ResourceLoader resourceLoader) { - log.debug("template locale {}", language); - AsciiDoctorTemplateResolver resolver = new AsciiDoctorTemplateResolver(language, resourceLoader); - resolver.setCacheable(false); - resolver.setOrder(1); - resolver.setCharacterEncoding(UTF8); - return resolver; - } + /** Loads the lesson asciidoc. */ + @Bean + public AsciiDoctorTemplateResolver asciiDoctorTemplateResolver( + Language language, ResourceLoader resourceLoader) { + log.debug("template locale {}", language); + AsciiDoctorTemplateResolver resolver = + new AsciiDoctorTemplateResolver(language, resourceLoader); + resolver.setCacheable(false); + resolver.setOrder(1); + resolver.setCharacterEncoding(UTF8); + return resolver; + } - @Bean - public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver springThymeleafTemplateResolver, - LessonTemplateResolver lessonTemplateResolver, - AsciiDoctorTemplateResolver asciiDoctorTemplateResolver, - ITemplateResolver lessonThymeleafTemplateResolver) { - SpringTemplateEngine engine = new SpringTemplateEngine(); - engine.setEnableSpringELCompiler(true); - engine.addDialect(new SpringSecurityDialect()); - engine.setTemplateResolvers( - Set.of(lessonTemplateResolver, asciiDoctorTemplateResolver, lessonThymeleafTemplateResolver, springThymeleafTemplateResolver)); - return engine; - } + @Bean + public SpringTemplateEngine thymeleafTemplateEngine( + ITemplateResolver springThymeleafTemplateResolver, + LessonTemplateResolver lessonTemplateResolver, + AsciiDoctorTemplateResolver asciiDoctorTemplateResolver, + ITemplateResolver lessonThymeleafTemplateResolver) { + SpringTemplateEngine engine = new SpringTemplateEngine(); + engine.setEnableSpringELCompiler(true); + engine.addDialect(new SpringSecurityDialect()); + engine.setTemplateResolvers( + Set.of( + lessonTemplateResolver, + asciiDoctorTemplateResolver, + lessonThymeleafTemplateResolver, + springThymeleafTemplateResolver)); + return engine; + } - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - //WebGoat internal - registry.addResourceHandler("/css/**").addResourceLocations("classpath:/webgoat/static/css/"); - registry.addResourceHandler("/js/**") - .addResourceLocations("classpath:/webgoat/static/js/"); - registry.addResourceHandler("/plugins/**").addResourceLocations("classpath:/webgoat/static/plugins/"); - registry.addResourceHandler("/fonts/**").addResourceLocations("classpath:/webgoat/static/fonts/"); + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + // WebGoat internal + registry.addResourceHandler("/css/**").addResourceLocations("classpath:/webgoat/static/css/"); + registry.addResourceHandler("/js/**").addResourceLocations("classpath:/webgoat/static/js/"); + registry + .addResourceHandler("/plugins/**") + .addResourceLocations("classpath:/webgoat/static/plugins/"); + registry + .addResourceHandler("/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)); - } + // 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 - public PluginMessages pluginMessages(Messages messages, Language language, - ResourcePatternResolver resourcePatternResolver) { - PluginMessages pluginMessages = new PluginMessages(messages, language, resourcePatternResolver); - pluginMessages.setDefaultEncoding("UTF-8"); - pluginMessages.setBasenames("i18n/WebGoatLabels"); - pluginMessages.setFallbackToSystemLocale(false); - return pluginMessages; - } + @Bean + public PluginMessages pluginMessages( + Messages messages, Language language, ResourcePatternResolver resourcePatternResolver) { + PluginMessages pluginMessages = new PluginMessages(messages, language, resourcePatternResolver); + pluginMessages.setDefaultEncoding("UTF-8"); + pluginMessages.setBasenames("i18n/WebGoatLabels"); + pluginMessages.setFallbackToSystemLocale(false); + return pluginMessages; + } - @Bean - public Language language(LocaleResolver localeResolver) { - return new Language(localeResolver); - } + @Bean + public Language language(LocaleResolver localeResolver) { + return new Language(localeResolver); + } - @Bean - public LocaleResolver localeResolver() { - SessionLocaleResolver localeResolver = new SessionLocaleResolver(); - return localeResolver; - } + @Bean + public LocaleResolver localeResolver() { + SessionLocaleResolver localeResolver = new SessionLocaleResolver(); + return localeResolver; + } - @Bean - public LocaleChangeInterceptor localeChangeInterceptor() { - LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); - lci.setParamName("lang"); - return lci; - } + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() { + LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); + lci.setParamName("lang"); + return lci; + } - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(localeChangeInterceptor()); - } + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(localeChangeInterceptor()); + } - @Bean - public Messages messageSource(Language language) { - Messages messages = new Messages(language); - messages.setDefaultEncoding("UTF-8"); - messages.setBasename("classpath:i18n/messages"); - messages.setFallbackToSystemLocale(false); - return messages; - } - - @Bean - public LabelDebugger labelDebugger() { - return new LabelDebugger(); - } + @Bean + public Messages messageSource(Language language) { + Messages messages = new Messages(language); + messages.setDefaultEncoding("UTF-8"); + messages.setBasename("classpath:i18n/messages"); + messages.setFallbackToSystemLocale(false); + return messages; + } + @Bean + public LabelDebugger labelDebugger() { + return new LabelDebugger(); + } } diff --git a/src/main/java/org/owasp/webgoat/container/WebGoat.java b/src/main/java/org/owasp/webgoat/container/WebGoat.java index b44f4b5e7..e721fddee 100644 --- a/src/main/java/org/owasp/webgoat/container/WebGoat.java +++ b/src/main/java/org/owasp/webgoat/container/WebGoat.java @@ -1,36 +1,37 @@ /** * ************************************************************************************************ + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author WebGoat * @version $Id: $Id * @since October 28, 2003 */ - package org.owasp.webgoat.container; +import java.io.File; import org.owasp.webgoat.container.session.UserSessionData; import org.owasp.webgoat.container.session.WebSession; import org.springframework.beans.factory.annotation.Value; @@ -43,33 +44,31 @@ import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.web.client.RestTemplate; -import java.io.File; - @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") @EnableAutoConfiguration public class WebGoat { - @Bean(name = "pluginTargetDirectory") - public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) { - return new File(webgoatHome); - } + @Bean(name = "pluginTargetDirectory") + public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) { + return new File(webgoatHome); + } - @Bean - @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) - public WebSession webSession() { - return new WebSession(); - } + @Bean + @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) + public WebSession webSession() { + return new WebSession(); + } - @Bean - @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) - public UserSessionData userSessionData() { - return new UserSessionData("test", "data"); - } + @Bean + @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) + public UserSessionData userSessionData() { + return new UserSessionData("test", "data"); + } - @Bean - public RestTemplate restTemplate() { - return new RestTemplate(); - } + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } } diff --git a/src/main/java/org/owasp/webgoat/container/WebSecurityConfig.java b/src/main/java/org/owasp/webgoat/container/WebSecurityConfig.java index 0339adc35..59084aa2f 100644 --- a/src/main/java/org/owasp/webgoat/container/WebSecurityConfig.java +++ b/src/main/java/org/owasp/webgoat/container/WebSecurityConfig.java @@ -2,36 +2,35 @@ * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat * @version $Id: $Id * @since December 12, 2015 */ - package org.owasp.webgoat.container; import lombok.AllArgsConstructor; -import org.owasp.webgoat.container.i18n.Language; import org.owasp.webgoat.container.users.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -44,59 +43,66 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.NoOpPasswordEncoder; -import org.springframework.web.servlet.i18n.SessionLocaleResolver; -/** - * Security configuration for WebGoat. - */ +/** Security configuration for WebGoat. */ @Configuration @AllArgsConstructor @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - private final UserService userDetailsService; + private final UserService userDetailsService; - @Override - protected void configure(HttpSecurity http) throws Exception { - ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry security = http - .authorizeRequests() - .antMatchers("/css/**", "/images/**", "/js/**", "fonts/**", "/plugins/**", "/registration", "/register.mvc", "/actuator/**").permitAll() - .anyRequest().authenticated(); - security.and() - .formLogin() - .loginPage("/login") - .defaultSuccessUrl("/welcome.mvc", true) - .usernameParameter("username") - .passwordParameter("password") - .permitAll(); - security.and() - .logout().deleteCookies("JSESSIONID").invalidateHttpSession(true); - security.and().csrf().disable(); + @Override + protected void configure(HttpSecurity http) throws Exception { + ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry security = + http.authorizeRequests() + .antMatchers( + "/css/**", + "/images/**", + "/js/**", + "fonts/**", + "/plugins/**", + "/registration", + "/register.mvc", + "/actuator/**") + .permitAll() + .anyRequest() + .authenticated(); + security + .and() + .formLogin() + .loginPage("/login") + .defaultSuccessUrl("/welcome.mvc", true) + .usernameParameter("username") + .passwordParameter("password") + .permitAll(); + security.and().logout().deleteCookies("JSESSIONID").invalidateHttpSession(true); + security.and().csrf().disable(); - http.headers().cacheControl().disable(); - http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")); - } + http.headers().cacheControl().disable(); + http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")); + } - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService); - } + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService); + } - @Bean - @Override - public UserDetailsService userDetailsServiceBean() throws Exception { - return userDetailsService; - } + @Bean + @Override + public UserDetailsService userDetailsServiceBean() throws Exception { + return userDetailsService; + } - @Override - @Bean - protected AuthenticationManager authenticationManager() throws Exception { - return super.authenticationManager(); - } + @Override + @Bean + protected AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } - @SuppressWarnings("deprecation") - @Bean - public NoOpPasswordEncoder passwordEncoder() { - return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); - } + @SuppressWarnings("deprecation") + @Bean + public NoOpPasswordEncoder passwordEncoder() { + return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); + } } diff --git a/src/main/java/org/owasp/webgoat/container/WebWolfRedirect.java b/src/main/java/org/owasp/webgoat/container/WebWolfRedirect.java index b3e26c10a..6c48ce1fa 100644 --- a/src/main/java/org/owasp/webgoat/container/WebWolfRedirect.java +++ b/src/main/java/org/owasp/webgoat/container/WebWolfRedirect.java @@ -10,12 +10,12 @@ import org.springframework.web.servlet.ModelAndView; @RequiredArgsConstructor public class WebWolfRedirect { - private final ApplicationContext applicationContext; + private final ApplicationContext applicationContext; - @GetMapping("/WebWolf") - public ModelAndView openWebWolf() { - var url = applicationContext.getEnvironment().getProperty("webwolf.url"); + @GetMapping("/WebWolf") + public ModelAndView openWebWolf() { + var url = applicationContext.getEnvironment().getProperty("webwolf.url"); - return new ModelAndView("redirect:" + url + "/home"); - } + return new ModelAndView("redirect:" + url + "/home"); + } } diff --git a/src/main/java/org/owasp/webgoat/container/asciidoc/EnvironmentExposure.java b/src/main/java/org/owasp/webgoat/container/asciidoc/EnvironmentExposure.java index 16175c3c7..7abaf10c9 100644 --- a/src/main/java/org/owasp/webgoat/container/asciidoc/EnvironmentExposure.java +++ b/src/main/java/org/owasp/webgoat/container/asciidoc/EnvironmentExposure.java @@ -7,19 +7,20 @@ import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; /** - * Make environment available in the asciidoc code (which you cannot inject because it is handled by the framework) + * Make environment available in the asciidoc code (which you cannot inject because it is handled by + * the framework) */ @Component public class EnvironmentExposure implements ApplicationContextAware { - private static ApplicationContext context; + private static ApplicationContext context; - public static Environment getEnv() { - return context.getEnvironment(); - } + public static Environment getEnv() { + return context.getEnvironment(); + } - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - context = applicationContext; - } + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + context = applicationContext; + } } diff --git a/src/main/java/org/owasp/webgoat/container/asciidoc/OperatingSystemMacro.java b/src/main/java/org/owasp/webgoat/container/asciidoc/OperatingSystemMacro.java index c40c30fe6..87a60a879 100644 --- a/src/main/java/org/owasp/webgoat/container/asciidoc/OperatingSystemMacro.java +++ b/src/main/java/org/owasp/webgoat/container/asciidoc/OperatingSystemMacro.java @@ -1,25 +1,25 @@ package org.owasp.webgoat.container.asciidoc; +import java.util.Map; import org.asciidoctor.ast.ContentNode; import org.asciidoctor.extension.InlineMacroProcessor; -import java.util.Map; - public class OperatingSystemMacro extends InlineMacroProcessor { - public OperatingSystemMacro(String macroName) { - super(macroName); - } + public OperatingSystemMacro(String macroName) { + super(macroName); + } - public OperatingSystemMacro(String macroName, Map config) { - super(macroName, config); - } + public OperatingSystemMacro(String macroName, Map config) { + super(macroName, config); + } - @Override - public Object process(ContentNode contentNode, String target, Map attributes) { - var osName = System.getProperty("os.name"); + @Override + public Object process(ContentNode contentNode, String target, Map attributes) { + var osName = System.getProperty("os.name"); - //see https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used - return createPhraseNode(contentNode, "quoted", osName); - } + // see + // https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used + return createPhraseNode(contentNode, "quoted", osName); + } } diff --git a/src/main/java/org/owasp/webgoat/container/asciidoc/UsernameMacro.java b/src/main/java/org/owasp/webgoat/container/asciidoc/UsernameMacro.java index ac4fe0535..7275ba9b1 100644 --- a/src/main/java/org/owasp/webgoat/container/asciidoc/UsernameMacro.java +++ b/src/main/java/org/owasp/webgoat/container/asciidoc/UsernameMacro.java @@ -1,31 +1,31 @@ package org.owasp.webgoat.container.asciidoc; +import java.util.Map; import org.asciidoctor.ast.ContentNode; import org.asciidoctor.extension.InlineMacroProcessor; import org.owasp.webgoat.container.users.WebGoatUser; import org.springframework.security.core.context.SecurityContextHolder; -import java.util.Map; - public class UsernameMacro extends InlineMacroProcessor { - public UsernameMacro(String macroName) { - super(macroName); + public UsernameMacro(String macroName) { + super(macroName); + } + + public UsernameMacro(String macroName, Map config) { + super(macroName, config); + } + + @Override + public Object process(ContentNode contentNode, String target, Map attributes) { + var auth = SecurityContextHolder.getContext().getAuthentication(); + var username = "unknown"; + if (auth.getPrincipal() instanceof WebGoatUser webGoatUser) { + username = webGoatUser.getUsername(); } - public UsernameMacro(String macroName, Map config) { - super(macroName, config); - } - - @Override - public Object process(ContentNode contentNode, String target, Map attributes) { - var auth = SecurityContextHolder.getContext().getAuthentication(); - var username = "unknown"; - if (auth.getPrincipal() instanceof WebGoatUser webGoatUser) { - username = webGoatUser.getUsername(); - } - - //see https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used - return createPhraseNode(contentNode, "quoted", username); - } + // see + // https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used + return createPhraseNode(contentNode, "quoted", username); + } } diff --git a/src/main/java/org/owasp/webgoat/container/asciidoc/WebGoatTmpDirMacro.java b/src/main/java/org/owasp/webgoat/container/asciidoc/WebGoatTmpDirMacro.java index c7158378d..12c283f9a 100644 --- a/src/main/java/org/owasp/webgoat/container/asciidoc/WebGoatTmpDirMacro.java +++ b/src/main/java/org/owasp/webgoat/container/asciidoc/WebGoatTmpDirMacro.java @@ -1,26 +1,25 @@ package org.owasp.webgoat.container.asciidoc; +import java.util.Map; import org.asciidoctor.ast.ContentNode; import org.asciidoctor.extension.InlineMacroProcessor; -import java.util.Map; - public class WebGoatTmpDirMacro extends InlineMacroProcessor { - public WebGoatTmpDirMacro(String macroName) { - super(macroName); - } + public WebGoatTmpDirMacro(String macroName) { + super(macroName); + } - public WebGoatTmpDirMacro(String macroName, Map config) { - super(macroName, config); - } + public WebGoatTmpDirMacro(String macroName, Map config) { + super(macroName, config); + } - @Override - public Object process(ContentNode contentNode, String target, Map attributes) { - var env = EnvironmentExposure.getEnv().getProperty("webgoat.server.directory"); + @Override + public Object process(ContentNode contentNode, String target, Map attributes) { + var env = EnvironmentExposure.getEnv().getProperty("webgoat.server.directory"); - //see https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used - return createPhraseNode(contentNode, "quoted", env); - - } + // see + // https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used + return createPhraseNode(contentNode, "quoted", env); + } } diff --git a/src/main/java/org/owasp/webgoat/container/asciidoc/WebGoatVersionMacro.java b/src/main/java/org/owasp/webgoat/container/asciidoc/WebGoatVersionMacro.java index 929136c45..09658e8b2 100644 --- a/src/main/java/org/owasp/webgoat/container/asciidoc/WebGoatVersionMacro.java +++ b/src/main/java/org/owasp/webgoat/container/asciidoc/WebGoatVersionMacro.java @@ -1,25 +1,25 @@ package org.owasp.webgoat.container.asciidoc; +import java.util.Map; import org.asciidoctor.ast.ContentNode; import org.asciidoctor.extension.InlineMacroProcessor; -import java.util.Map; - public class WebGoatVersionMacro extends InlineMacroProcessor { - public WebGoatVersionMacro(String macroName) { - super(macroName); - } + public WebGoatVersionMacro(String macroName) { + super(macroName); + } - public WebGoatVersionMacro(String macroName, Map config) { - super(macroName, config); - } + public WebGoatVersionMacro(String macroName, Map config) { + super(macroName, config); + } - @Override - public Object process(ContentNode contentNode, String target, Map attributes) { - var webgoatVersion = EnvironmentExposure.getEnv().getProperty("webgoat.build.version"); + @Override + public Object process(ContentNode contentNode, String target, Map attributes) { + var webgoatVersion = EnvironmentExposure.getEnv().getProperty("webgoat.build.version"); - //see https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used - return createPhraseNode(contentNode, "quoted", webgoatVersion); - } + // see + // https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used + return createPhraseNode(contentNode, "quoted", webgoatVersion); + } } diff --git a/src/main/java/org/owasp/webgoat/container/asciidoc/WebWolfMacro.java b/src/main/java/org/owasp/webgoat/container/asciidoc/WebWolfMacro.java index 4a736c96f..9ab0fac86 100644 --- a/src/main/java/org/owasp/webgoat/container/asciidoc/WebWolfMacro.java +++ b/src/main/java/org/owasp/webgoat/container/asciidoc/WebWolfMacro.java @@ -1,73 +1,73 @@ package org.owasp.webgoat.container.asciidoc; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; import org.asciidoctor.ast.ContentNode; import org.asciidoctor.extension.InlineMacroProcessor; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import javax.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.Map; - /** * Usage in asciidoc: - *

- * webWolfLink:here[] will display a href with here as text + * + *

webWolfLink:here[] will display a href with here as text */ public class WebWolfMacro extends InlineMacroProcessor { - public WebWolfMacro(String macroName) { - super(macroName); + public WebWolfMacro(String macroName) { + super(macroName); + } + + public WebWolfMacro(String macroName, Map config) { + super(macroName, config); + } + + @Override + public Object process(ContentNode contentNode, String linkText, Map attributes) { + var env = EnvironmentExposure.getEnv(); + var hostname = determineHost(env.getProperty("webwolf.port")); + var target = (String) attributes.getOrDefault("target", "home"); + var href = hostname + "/" + target; + + // are we using noLink in webWolfLink:landing[noLink]? Then display link with full href + if (displayCompleteLinkNoFormatting(attributes)) { + linkText = href; } - public WebWolfMacro(String macroName, Map config) { - super(macroName, config); + var options = new HashMap(); + options.put("type", ":link"); + options.put("target", href); + attributes.put("window", "_blank"); + return createPhraseNode(contentNode, "anchor", linkText, attributes, options).convert(); + } + + private boolean displayCompleteLinkNoFormatting(Map attributes) { + return attributes.values().stream().anyMatch(a -> a.equals("noLink")); + } + + /** + * Determine the host from the hostname and ports that were used. The purpose is to make it + * possible to use the application behind a reverse proxy. For instance in the docker + * compose/stack version with webgoat webwolf and nginx proxy. You do not have to use the + * indicated hostname, but if you do, you should define two hosts aliases 127.0.0.1 + * www.webgoat.local www.webwolf.local + */ + private String determineHost(String port) { + HttpServletRequest request = + ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + String host = request.getHeader("Host"); + int semicolonIndex = host.indexOf(":"); + if (semicolonIndex == -1 || host.endsWith(":80")) { + host = host.replace(":80", "").replace("www.webgoat.local", "www.webwolf.local"); + } else { + host = host.substring(0, semicolonIndex); + host = host.concat(":").concat(port); } + return "http://" + host + (includeWebWolfContext() ? "/WebWolf" : ""); + } - @Override - public Object process(ContentNode contentNode, String linkText, Map attributes) { - var env = EnvironmentExposure.getEnv(); - var hostname = determineHost(env.getProperty("webwolf.port")); - var target = (String) attributes.getOrDefault("target", "home"); - var href = hostname + "/" + target; - - //are we using noLink in webWolfLink:landing[noLink]? Then display link with full href - if (displayCompleteLinkNoFormatting(attributes)) { - linkText = href; - } - - var options = new HashMap(); - options.put("type", ":link"); - options.put("target", href); - attributes.put("window", "_blank"); - return createPhraseNode(contentNode, "anchor", linkText, attributes, options).convert(); - } - - private boolean displayCompleteLinkNoFormatting(Map attributes) { - return attributes.values().stream().anyMatch(a -> a.equals("noLink")); - } - - /** - * Determine the host from the hostname and ports that were used. - * The purpose is to make it possible to use the application behind a reverse proxy. For instance in the docker - * compose/stack version with webgoat webwolf and nginx proxy. - * You do not have to use the indicated hostname, but if you do, you should define two hosts aliases - * 127.0.0.1 www.webgoat.local www.webwolf.local - */ - private String determineHost(String port) { - HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); - String host = request.getHeader("Host"); - int semicolonIndex = host.indexOf(":"); - if (semicolonIndex == -1 || host.endsWith(":80")) { - host = host.replace(":80", "").replace("www.webgoat.local", "www.webwolf.local"); - } else { - host = host.substring(0, semicolonIndex); - host = host.concat(":").concat(port); - } - return "http://" + host + (includeWebWolfContext() ? "/WebWolf" : ""); - } - - protected boolean includeWebWolfContext() { - return true; - } + protected boolean includeWebWolfContext() { + return true; + } } diff --git a/src/main/java/org/owasp/webgoat/container/asciidoc/WebWolfRootMacro.java b/src/main/java/org/owasp/webgoat/container/asciidoc/WebWolfRootMacro.java index 8c5d5450c..58b12e547 100644 --- a/src/main/java/org/owasp/webgoat/container/asciidoc/WebWolfRootMacro.java +++ b/src/main/java/org/owasp/webgoat/container/asciidoc/WebWolfRootMacro.java @@ -4,22 +4,22 @@ import java.util.Map; /** * Usage in asciidoc: - *

- * webWolfLink:here[] will display a href with here as text - * webWolfLink:landing[noLink] will display the complete url, for example: http://WW_HOST:WW_PORT/landing + * + *

webWolfLink:here[] will display a href with here as text webWolfLink:landing[noLink] will + * display the complete url, for example: http://WW_HOST:WW_PORT/landing */ public class WebWolfRootMacro extends WebWolfMacro { - public WebWolfRootMacro(String macroName) { - super(macroName); - } + public WebWolfRootMacro(String macroName) { + super(macroName); + } - public WebWolfRootMacro(String macroName, Map config) { - super(macroName, config); - } + public WebWolfRootMacro(String macroName, Map config) { + super(macroName, config); + } - @Override - protected boolean includeWebWolfContext() { - return false; - } + @Override + protected boolean includeWebWolfContext() { + return false; + } } diff --git a/src/main/java/org/owasp/webgoat/container/assignments/AssignmentEndpoint.java b/src/main/java/org/owasp/webgoat/container/assignments/AssignmentEndpoint.java index 09e4d7cfc..c48fb2f23 100644 --- a/src/main/java/org/owasp/webgoat/container/assignments/AssignmentEndpoint.java +++ b/src/main/java/org/owasp/webgoat/container/assignments/AssignmentEndpoint.java @@ -35,57 +35,58 @@ 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; + @Autowired private WebSession webSession; + @Autowired private UserSessionData userSessionData; + @Getter @Autowired private PluginMessages messages; - protected WebSession getWebSession() { - return webSession; - } + protected WebSession getWebSession() { + return webSession; + } - protected UserSessionData getUserSessionData() { - return userSessionData; - } + protected UserSessionData getUserSessionData() { + return userSessionData; + } - /** - * Convenience method for create a successful result: - *

- * - Assignment is set to solved - * - Feedback message is set to 'assignment.solved' - *

- * 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 successful result: + * + *

- Assignment is set to solved - Feedback message is set to 'assignment.solved' + * + *

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: - *

- * - Assignment is set to not solved - * - Feedback message is set to 'assignment.not.solved' - *

- * 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); - } + /** + * Convenience method for create a failed result: + * + *

- Assignment is set to not solved - Feedback message is set to 'assignment.not.solved' + * + *

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); - } + protected AttackResult.AttackResultBuilder informationMessage(AssignmentEndpoint assignment) { + return AttackResult.builder(messages).lessonCompleted(false).assignment(assignment); + } - @Override - public void initialize(WebGoatUser user) { - } + @Override + public void initialize(WebGoatUser user) {} } diff --git a/src/main/java/org/owasp/webgoat/container/assignments/AssignmentHints.java b/src/main/java/org/owasp/webgoat/container/assignments/AssignmentHints.java index b6111b5c7..bfea97438 100644 --- a/src/main/java/org/owasp/webgoat/container/assignments/AssignmentHints.java +++ b/src/main/java/org/owasp/webgoat/container/assignments/AssignmentHints.java @@ -5,12 +5,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** - * Created by nbaars on 1/14/17. - */ +/** Created by nbaars on 1/14/17. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface AssignmentHints { - String[] value() default {}; + String[] value() default {}; } diff --git a/src/main/java/org/owasp/webgoat/container/assignments/AssignmentPath.java b/src/main/java/org/owasp/webgoat/container/assignments/AssignmentPath.java index 7e57d593b..0c1993393 100644 --- a/src/main/java/org/owasp/webgoat/container/assignments/AssignmentPath.java +++ b/src/main/java/org/owasp/webgoat/container/assignments/AssignmentPath.java @@ -1,22 +1,19 @@ package org.owasp.webgoat.container.assignments; -import org.springframework.web.bind.annotation.RequestMethod; - 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. - */ +/** Created by nbaars on 1/14/17. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface AssignmentPath { - String[] path() default {}; + String[] path() default {}; - RequestMethod[] method() default {}; + RequestMethod[] method() default {}; - String value() default ""; + String value() default ""; } diff --git a/src/main/java/org/owasp/webgoat/container/assignments/AttackResult.java b/src/main/java/org/owasp/webgoat/container/assignments/AttackResult.java index b2d18b7a6..3cf353c21 100644 --- a/src/main/java/org/owasp/webgoat/container/assignments/AttackResult.java +++ b/src/main/java/org/owasp/webgoat/container/assignments/AttackResult.java @@ -25,100 +25,104 @@ package org.owasp.webgoat.container.assignments; +import static org.apache.commons.text.StringEscapeUtils.escapeJson; + import lombok.Getter; import org.owasp.webgoat.container.i18n.PluginMessages; -import static org.apache.commons.text.StringEscapeUtils.escapeJson; - public class AttackResult { + public static class AttackResultBuilder { - public static class AttackResultBuilder { - - private boolean lessonCompleted; - private PluginMessages messages; - private Object[] feedbackArgs; - private String feedbackResourceBundleKey; - private String output; - private Object[] outputArgs; - private AssignmentEndpoint assignment; - private boolean attemptWasMade = false; - - 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 PluginMessages messages; + private Object[] feedbackArgs; + private String feedbackResourceBundleKey; private String output; - @Getter - private final String assignment; - @Getter - private boolean attemptWasMade; + private Object[] outputArgs; + private AssignmentEndpoint assignment; + private boolean attemptWasMade = false; - public AttackResult(boolean lessonCompleted, String feedback, String output, String assignment, boolean attemptWasMade) { - this.lessonCompleted = lessonCompleted; - this.feedback = escapeJson(feedback); - this.output = escapeJson(output); - this.assignment = assignment; - this.attemptWasMade = attemptWasMade; + public AttackResultBuilder(PluginMessages messages) { + this.messages = messages; } - public static AttackResultBuilder builder(PluginMessages messages) { - return new AttackResultBuilder(messages); + public AttackResultBuilder lessonCompleted(boolean lessonCompleted) { + this.lessonCompleted = lessonCompleted; + this.feedbackResourceBundleKey = "lesson.completed"; + return this; } - public boolean assignmentSolved() { - return lessonCompleted; + 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, + String feedback, + String output, + String assignment, + boolean attemptWasMade) { + this.lessonCompleted = lessonCompleted; + this.feedback = escapeJson(feedback); + this.output = escapeJson(output); + this.assignment = assignment; + this.attemptWasMade = attemptWasMade; + } + + public static AttackResultBuilder builder(PluginMessages messages) { + return new AttackResultBuilder(messages); + } + + public boolean assignmentSolved() { + return lessonCompleted; + } } diff --git a/src/main/java/org/owasp/webgoat/container/assignments/LessonTrackerInterceptor.java b/src/main/java/org/owasp/webgoat/container/assignments/LessonTrackerInterceptor.java index 5b15965d9..4e76af9d6 100644 --- a/src/main/java/org/owasp/webgoat/container/assignments/LessonTrackerInterceptor.java +++ b/src/main/java/org/owasp/webgoat/container/assignments/LessonTrackerInterceptor.java @@ -36,39 +36,46 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; @RestControllerAdvice public class LessonTrackerInterceptor implements ResponseBodyAdvice { - private UserTrackerRepository userTrackerRepository; - private WebSession webSession; + private UserTrackerRepository userTrackerRepository; + private WebSession webSession; - public LessonTrackerInterceptor(UserTrackerRepository userTrackerRepository, WebSession webSession) { - this.userTrackerRepository = userTrackerRepository; - this.webSession = webSession; + public LessonTrackerInterceptor( + UserTrackerRepository userTrackerRepository, WebSession webSession) { + this.userTrackerRepository = userTrackerRepository; + this.webSession = webSession; + } + + @Override + public boolean supports( + MethodParameter methodParameter, Class> clazz) { + return true; + } + + @Override + public Object beforeBodyWrite( + Object o, + MethodParameter methodParameter, + MediaType mediaType, + Class> aClass, + ServerHttpRequest serverHttpRequest, + ServerHttpResponse serverHttpResponse) { + if (o instanceof AttackResult attackResult) { + trackProgress(attackResult); } + return o; + } - @Override - public boolean supports(MethodParameter methodParameter, Class> clazz) { - return true; + protected AttackResult trackProgress(AttackResult attackResult) { + UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); + if (userTracker == null) { + userTracker = new UserTracker(webSession.getUserName()); } - - @Override - public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { - if (o instanceof AttackResult attackResult) { - trackProgress(attackResult); - } - return o; - } - - - protected AttackResult trackProgress(AttackResult attackResult) { - UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); - if (userTracker == null) { - userTracker = new UserTracker(webSession.getUserName()); - } - if (attackResult.assignmentSolved()) { - userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment()); - } else { - userTracker.assignmentFailed(webSession.getCurrentLesson()); - } - userTrackerRepository.saveAndFlush(userTracker); - return attackResult; + if (attackResult.assignmentSolved()) { + userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment()); + } else { + userTracker.assignmentFailed(webSession.getCurrentLesson()); } + userTrackerRepository.saveAndFlush(userTracker); + return attackResult; + } } diff --git a/src/main/java/org/owasp/webgoat/container/controller/StartLesson.java b/src/main/java/org/owasp/webgoat/container/controller/StartLesson.java index 8093a9d03..7d94f6044 100644 --- a/src/main/java/org/owasp/webgoat/container/controller/StartLesson.java +++ b/src/main/java/org/owasp/webgoat/container/controller/StartLesson.java @@ -1,36 +1,37 @@ /** * ************************************************************************************************ + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author WebGoat * @version $Id: $Id * @since October 28, 2003 */ - package org.owasp.webgoat.container.controller; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.session.Course; import org.owasp.webgoat.container.session.WebSession; import org.springframework.stereotype.Controller; @@ -38,52 +39,52 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.servlet.ModelAndView; -import javax.servlet.http.HttpServletRequest; - - @Controller public class StartLesson { - private final WebSession ws; - private final Course course; + private final WebSession ws; + private final Course course; - public StartLesson(WebSession ws, Course course) { - this.ws = ws; - this.course = course; - } + public StartLesson(WebSession ws, Course course) { + this.ws = ws; + this.course = course; + } - /** - *

start.

- * - * @return a {@link ModelAndView} object. - */ - @RequestMapping(path = "startlesson.mvc", method = {RequestMethod.GET, RequestMethod.POST}) - public ModelAndView start() { - var model = new ModelAndView(); + /** + * 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"); + model.addObject("course", course); + model.addObject("lesson", ws.getCurrentLesson()); + model.setViewName("lesson_content"); - return model; - } + return model; + } - @RequestMapping(value = {"*.lesson"}, produces = "text/html") - public ModelAndView lessonPage(HttpServletRequest request) { - var model = new ModelAndView("lesson_content"); - var path = request.getRequestURL().toString(); // we now got /a/b/c/AccessControlMatrix.lesson - var lessonName = path.substring(path.lastIndexOf('/') + 1, path.indexOf(".lesson")); + @RequestMapping( + value = {"*.lesson"}, + produces = "text/html") + public ModelAndView lessonPage(HttpServletRequest request) { + var model = new ModelAndView("lesson_content"); + var path = request.getRequestURL().toString(); // we now got /a/b/c/AccessControlMatrix.lesson + var lessonName = path.substring(path.lastIndexOf('/') + 1, path.indexOf(".lesson")); - course.getLessons() - .stream() - .filter(l -> l.getId().equals(lessonName)) - .findFirst() - .ifPresent(lesson -> { - ws.setCurrentLesson(lesson); - model.addObject("lesson", lesson); - }); - - return model; - } + course.getLessons().stream() + .filter(l -> l.getId().equals(lessonName)) + .findFirst() + .ifPresent( + lesson -> { + ws.setCurrentLesson(lesson); + model.addObject("lesson", lesson); + }); + return model; + } } diff --git a/src/main/java/org/owasp/webgoat/container/controller/Welcome.java b/src/main/java/org/owasp/webgoat/container/controller/Welcome.java index 1ea65f3ee..fddc5f640 100644 --- a/src/main/java/org/owasp/webgoat/container/controller/Welcome.java +++ b/src/main/java/org/owasp/webgoat/container/controller/Welcome.java @@ -1,45 +1,42 @@ /** - ************************************************************************************************* + * ************************************************************************************************ * - * - * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ * - * Copyright (c) 2002 - 2014 Bruce Mayhew + *

Copyright (c) 2002 - 2014 Bruce Mayhew * - * This program is free software; you can redistribute it and/or modify it under the terms of the + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with this program; if + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * - * Getting Source ============== + *

Getting Source ============== * - * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author WebGoat * @since October 28, 2003 * @version $Id: $Id */ - package org.owasp.webgoat.container.controller; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.servlet.ModelAndView; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - /** - *

Welcome class.

+ * Welcome class. * * @author rlawson * @version $Id: $Id @@ -47,29 +44,28 @@ import javax.servlet.http.HttpSession; @Controller public class Welcome { - private static final String WELCOMED = "welcomed"; - - /** - *

welcome.

- * - * @param request a {@link javax.servlet.http.HttpServletRequest} object. - * @return a {@link org.springframework.web.servlet.ModelAndView} object. - */ - @GetMapping(path = {"welcome.mvc"}) - public ModelAndView welcome(HttpServletRequest request) { + private static final String WELCOMED = "welcomed"; - // set the welcome attribute - // this is so the attack servlet does not also - // send them to the welcome page - HttpSession session = request.getSession(); - if (session.getAttribute(WELCOMED) == null) { - session.setAttribute(WELCOMED, "true"); - } - - //go ahead and send them to webgoat (skip the welcome page) - ModelAndView model = new ModelAndView(); - model.setViewName("forward:/attack?start=true"); - return model; + /** + * welcome. + * + * @param request a {@link javax.servlet.http.HttpServletRequest} object. + * @return a {@link org.springframework.web.servlet.ModelAndView} object. + */ + @GetMapping(path = {"welcome.mvc"}) + public ModelAndView welcome(HttpServletRequest request) { + + // set the welcome attribute + // this is so the attack servlet does not also + // send them to the welcome page + HttpSession session = request.getSession(); + if (session.getAttribute(WELCOMED) == null) { + session.setAttribute(WELCOMED, "true"); } - + + // go ahead and send them to webgoat (skip the welcome page) + ModelAndView model = new ModelAndView(); + model.setViewName("forward:/attack?start=true"); + return model; + } } diff --git a/src/main/java/org/owasp/webgoat/container/i18n/Language.java b/src/main/java/org/owasp/webgoat/container/i18n/Language.java index 5b73e0755..76e2a9728 100644 --- a/src/main/java/org/owasp/webgoat/container/i18n/Language.java +++ b/src/main/java/org/owasp/webgoat/container/i18n/Language.java @@ -25,15 +25,15 @@ package org.owasp.webgoat.container.i18n; +import java.util.Locale; import lombok.AllArgsConstructor; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.servlet.LocaleResolver; -import java.util.Locale; /** - * Wrapper around the LocaleResolver from Spring so we do not need to bother with passing the HttpRequest object - * when asking for a Locale. + * Wrapper around the LocaleResolver from Spring so we do not need to bother with passing the + * HttpRequest object when asking for a Locale. * * @author nbaars * @date 2/7/17 @@ -41,9 +41,10 @@ import java.util.Locale; @AllArgsConstructor public class Language { - private final LocaleResolver localeResolver; + private final LocaleResolver localeResolver; - public Locale getLocale() { - return localeResolver.resolveLocale(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()); - } + public Locale getLocale() { + return localeResolver.resolveLocale( + ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()); + } } diff --git a/src/main/java/org/owasp/webgoat/container/i18n/Messages.java b/src/main/java/org/owasp/webgoat/container/i18n/Messages.java index 04a3b3ad5..5fd9c9c92 100644 --- a/src/main/java/org/owasp/webgoat/container/i18n/Messages.java +++ b/src/main/java/org/owasp/webgoat/container/i18n/Messages.java @@ -25,36 +25,35 @@ package org.owasp.webgoat.container.i18n; +import java.util.Properties; import lombok.AllArgsConstructor; import org.springframework.context.support.ReloadableResourceBundleMessageSource; -import java.util.Properties; - /** - *

ExposedReloadableResourceMessageBundleSource class.

- * Extends the reloadable message source with a way to get all messages + * ExposedReloadableResourceMessageBundleSource class. Extends the reloadable message source with a + * way to get all messages * * @author zupzup */ @AllArgsConstructor public class Messages extends ReloadableResourceBundleMessageSource { - private final Language language; + private final Language language; - /** - * Gets all messages for presented Locale. - * - * @return all messages - */ - public Properties getMessages() { - return getMergedProperties(language.getLocale()).getProperties(); - } + /** + * Gets all messages for presented Locale. + * + * @return all messages + */ + public Properties getMessages() { + return getMergedProperties(language.getLocale()).getProperties(); + } - public String getMessage(String code, Object... args) { - return getMessage(code, args, language.getLocale()); - } + public String getMessage(String code, Object... args) { + return getMessage(code, args, language.getLocale()); + } - public String getMessage(String code, String defaultValue, Object... args) { - return super.getMessage(code, args, defaultValue, language.getLocale()); - } + public String getMessage(String code, String defaultValue, Object... args) { + return super.getMessage(code, args, defaultValue, language.getLocale()); + } } diff --git a/src/main/java/org/owasp/webgoat/container/i18n/PluginMessages.java b/src/main/java/org/owasp/webgoat/container/i18n/PluginMessages.java index e0c6d3583..16df55cb2 100644 --- a/src/main/java/org/owasp/webgoat/container/i18n/PluginMessages.java +++ b/src/main/java/org/owasp/webgoat/container/i18n/PluginMessages.java @@ -25,11 +25,10 @@ package org.owasp.webgoat.container.i18n; -import org.springframework.context.support.ReloadableResourceBundleMessageSource; -import org.springframework.core.io.support.ResourcePatternResolver; - import java.io.IOException; import java.util.Properties; +import org.springframework.context.support.ReloadableResourceBundleMessageSource; +import org.springframework.core.io.support.ResourcePatternResolver; /** * Message resource bundle for plugins. @@ -38,49 +37,49 @@ import java.util.Properties; * @date 2/4/17 */ public class PluginMessages extends ReloadableResourceBundleMessageSource { - private static final String PROPERTIES_SUFFIX = ".properties"; + private static final String PROPERTIES_SUFFIX = ".properties"; - private final Language language; - private final ResourcePatternResolver resourcePatternResolver; + private final Language language; + private final ResourcePatternResolver resourcePatternResolver; + public PluginMessages( + Messages messages, Language language, ResourcePatternResolver resourcePatternResolver) { + this.language = language; + this.setParentMessageSource(messages); + this.setBasename("WebGoatLabels"); + this.resourcePatternResolver = resourcePatternResolver; + } - public PluginMessages(Messages messages, Language language, ResourcePatternResolver resourcePatternResolver) { - this.language = language; - this.setParentMessageSource(messages); - this.setBasename("WebGoatLabels"); - this.resourcePatternResolver = resourcePatternResolver; + @Override + protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) { + Properties properties = new Properties(); + long lastModified = System.currentTimeMillis(); + + try { + var resources = + resourcePatternResolver.getResources( + "classpath:/lessons/**/i18n" + "/WebGoatLabels" + PROPERTIES_SUFFIX); + for (var resource : resources) { + String sourcePath = resource.getURI().toString().replace(PROPERTIES_SUFFIX, ""); + PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder); + properties.putAll(holder.getProperties()); + } + } catch (IOException e) { + logger.error("Unable to read plugin message", e); } - @Override - protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) { - Properties properties = new Properties(); - long lastModified = System.currentTimeMillis(); + return new PropertiesHolder(properties, lastModified); + } - try { - var resources = resourcePatternResolver.getResources("classpath:/lessons/**/i18n" + - "/WebGoatLabels" + PROPERTIES_SUFFIX); - for (var resource : resources) { - String sourcePath = resource.getURI().toString().replace(PROPERTIES_SUFFIX, ""); - PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder); - properties.putAll(holder.getProperties()); - } - } catch (IOException e) { - logger.error("Unable to read plugin message", e); - } + public Properties getMessages() { + return getMergedProperties(language.getLocale()).getProperties(); + } - return new PropertiesHolder(properties, lastModified); - } + public String getMessage(String code, Object... args) { + return getMessage(code, args, language.getLocale()); + } - - public Properties getMessages() { - return getMergedProperties(language.getLocale()).getProperties(); - } - - public String getMessage(String code, Object... args) { - return getMessage(code, args, language.getLocale()); - } - - public String getMessage(String code, String defaultValue, Object... args) { - return super.getMessage(code, args, defaultValue, language.getLocale()); - } + public String getMessage(String code, String defaultValue, Object... args) { + return super.getMessage(code, args, defaultValue, language.getLocale()); + } } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/Assignment.java b/src/main/java/org/owasp/webgoat/container/lessons/Assignment.java index f7f726186..92e8d0e9e 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/Assignment.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/Assignment.java @@ -1,34 +1,34 @@ package org.owasp.webgoat.container.lessons; -import lombok.*; - -import javax.persistence.*; import java.util.ArrayList; import java.util.List; +import javax.persistence.*; +import lombok.*; /** * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author nbaars @@ -40,30 +40,33 @@ import java.util.List; @Entity public class Assignment { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - private String name; - private String path; + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; - @Transient - private List hints; + private String name; + private String path; - private Assignment() { - //Hibernate + @Transient private List hints; + + private Assignment() { + // Hibernate + } + + public Assignment(String name) { + this(name, name, new ArrayList<>()); + } + + public Assignment(String name, String path, List hints) { + if (path.equals("") || path.equals("/") || path.equals("/WebGoat/")) { + throw new IllegalStateException( + "The path of assignment '" + + name + + "' overrides WebGoat endpoints, please choose a path within the scope of the" + + " lesson"); } - - public Assignment(String name) { - this(name, name, new ArrayList<>()); - } - - public Assignment(String name, String path, List hints) { - if (path.equals("") || path.equals("/") || path.equals("/WebGoat/")) { - throw new IllegalStateException("The path of assignment '" + name + "' overrides WebGoat endpoints, please choose a path within the scope of the lesson"); - } - this.name = name; - this.path = path; - this.hints = hints; - } - + this.name = name; + this.path = path; + this.hints = hints; + } } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/Category.java b/src/main/java/org/owasp/webgoat/container/lessons/Category.java index 30cccd889..8b4d64ee1 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/Category.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/Category.java @@ -4,30 +4,29 @@ import lombok.Getter; /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - *

- * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository * for free software projects. * * @author Bruce Mayhew WebGoat @@ -35,40 +34,35 @@ import lombok.Getter; * @since October 28, 2003 */ public enum Category { + INTRODUCTION("Introduction", 5), + GENERAL("General", 100), - INTRODUCTION("Introduction", 5), - GENERAL("General", 100), - - A1("(A1) Broken Access Control", 301), - A2("(A2) Cryptographic Failures", 302), - A3("(A3) Injection", 303), + A1("(A1) Broken Access Control", 301), + A2("(A2) Cryptographic Failures", 302), + A3("(A3) Injection", 303), - A5("(A5) Security Misconfiguration", 305), - A6("(A6) Vuln & Outdated Components", 306), - A7("(A7) Identity & Auth Failure", 307), - A8("(A8) Software & Data Integrity", 308), - A9("(A9) Security Logging Failures", 309), - A10("(A10) Server-side Request Forgery", 310), - - CLIENT_SIDE("Client side", 1700), + A5("(A5) Security Misconfiguration", 305), + A6("(A6) Vuln & Outdated Components", 306), + A7("(A7) Identity & Auth Failure", 307), + A8("(A8) Software & Data Integrity", 308), + A9("(A9) Security Logging Failures", 309), + A10("(A10) Server-side Request Forgery", 310), - CHALLENGE("Challenges", 3000); + CLIENT_SIDE("Client side", 1700), - @Getter - private String name; - @Getter - private Integer ranking; + CHALLENGE("Challenges", 3000); - Category(String name, Integer ranking) { - this.name = name; - this.ranking = ranking; - } + @Getter private String name; + @Getter private Integer ranking; - /** - * {@inheritDoc} - */ - @Override - public String toString() { - return getName(); - } + Category(String name, Integer ranking) { + this.name = name; + this.ranking = ranking; + } + + /** {@inheritDoc} */ + @Override + public String toString() { + return getName(); + } } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/CourseConfiguration.java b/src/main/java/org/owasp/webgoat/container/lessons/CourseConfiguration.java index fccc1fa16..c6be7cfad 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/CourseConfiguration.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/CourseConfiguration.java @@ -22,6 +22,11 @@ package org.owasp.webgoat.container.lessons; +import static java.util.stream.Collectors.groupingBy; + +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.*; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -36,91 +41,103 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.util.*; - -import static java.util.stream.Collectors.groupingBy; -import static java.util.stream.Collectors.toList; - @Slf4j @Configuration public class CourseConfiguration { - private final List lessons; - private final List assignments; - private final Map> assignmentsByPackage; + private final List lessons; + private final List assignments; + private final Map> assignmentsByPackage; - public CourseConfiguration(List lessons, List assignments) { - this.lessons = lessons; - this.assignments = assignments; - assignmentsByPackage = this.assignments.stream().collect(groupingBy(a -> a.getClass().getPackageName())); - } + public CourseConfiguration(List lessons, List assignments) { + this.lessons = lessons; + this.assignments = assignments; + assignmentsByPackage = + this.assignments.stream().collect(groupingBy(a -> a.getClass().getPackageName())); + } - @Bean - public Course course() { - lessons.stream().forEach(l -> l.setAssignments(createAssignment(l))); - return new Course(lessons); - } + @Bean + public Course course() { + lessons.stream().forEach(l -> l.setAssignments(createAssignment(l))); + return new Course(lessons); + } - private List createAssignment(Lesson lesson) { - var endpoints = assignmentsByPackage.get(lesson.getClass().getPackageName()); - if (CollectionUtils.isEmpty(endpoints)) { - log.warn("Lesson: {} has no endpoints, is this intentionally?", lesson.getTitle()); - return new ArrayList<>(); - } - return endpoints.stream() - .map(e -> new Assignment(e.getClass().getSimpleName(), getPath(e.getClass()), getHints(e.getClass()))) - .toList(); + private List createAssignment(Lesson lesson) { + var endpoints = assignmentsByPackage.get(lesson.getClass().getPackageName()); + if (CollectionUtils.isEmpty(endpoints)) { + log.warn("Lesson: {} has no endpoints, is this intentionally?", lesson.getTitle()); + return new ArrayList<>(); } + return endpoints.stream() + .map( + e -> + new Assignment( + e.getClass().getSimpleName(), getPath(e.getClass()), getHints(e.getClass()))) + .toList(); + } - private String getPath(Class e) { - for (Method m : e.getMethods()) { - if (methodReturnTypeIsOfTypeAttackResult(m)) { - var mapping = getMapping(m); - if (mapping != null) { - return mapping; - } - } + private String getPath(Class e) { + for (Method m : e.getMethods()) { + if (methodReturnTypeIsOfTypeAttackResult(m)) { + var mapping = getMapping(m); + if (mapping != null) { + return mapping; } - throw new IllegalStateException("Assignment endpoint: " + e + " has no mapping like @GetMapping/@PostMapping etc," + - "with return type 'AttackResult' or 'ResponseEntity' please consider adding one"); + } } + throw new IllegalStateException( + "Assignment endpoint: " + + e + + " has no mapping like @GetMapping/@PostMapping etc,with return type 'AttackResult' or" + + " 'ResponseEntity' please consider adding one"); + } - private boolean methodReturnTypeIsOfTypeAttackResult(Method m) { - if (m.getReturnType() == AttackResult.class) { - return true; - } - var genericType = m.getGenericReturnType(); - if (genericType instanceof ParameterizedType) { - return ((ParameterizedType) m.getGenericReturnType()).getActualTypeArguments()[0] == AttackResult.class; - } - return false; + private boolean methodReturnTypeIsOfTypeAttackResult(Method m) { + if (m.getReturnType() == AttackResult.class) { + return true; } + var genericType = m.getGenericReturnType(); + if (genericType instanceof ParameterizedType) { + return ((ParameterizedType) m.getGenericReturnType()).getActualTypeArguments()[0] + == AttackResult.class; + } + return false; + } - private String getMapping(Method m) { - String[] paths = null; - //Find the path, either it is @GetMapping("/attack") of GetMapping(path = "/attack") both are valid, we need to consider both - if (m.getAnnotation(RequestMapping.class) != null) { - paths = ArrayUtils.addAll(m.getAnnotation(RequestMapping.class).value(), m.getAnnotation(RequestMapping.class).path()); - } else if (m.getAnnotation(PostMapping.class) != null) { - paths = ArrayUtils.addAll(m.getAnnotation(PostMapping.class).value(), m.getAnnotation(PostMapping.class).path()); - } else if (m.getAnnotation(GetMapping.class) != null) { - paths = ArrayUtils.addAll(m.getAnnotation(GetMapping.class).value(), m.getAnnotation(GetMapping.class).path()); - } else if (m.getAnnotation(PutMapping.class) != null) { - paths = ArrayUtils.addAll(m.getAnnotation(PutMapping.class).value(), m.getAnnotation(PutMapping.class).path()); - } - if (paths == null) { - return null; - } else { - return Arrays.stream(paths).filter(path -> !"".equals(path)).findFirst().orElse(""); - } + private String getMapping(Method m) { + String[] paths = null; + // Find the path, either it is @GetMapping("/attack") of GetMapping(path = "/attack") both are + // valid, we need to consider both + if (m.getAnnotation(RequestMapping.class) != null) { + paths = + ArrayUtils.addAll( + m.getAnnotation(RequestMapping.class).value(), + m.getAnnotation(RequestMapping.class).path()); + } else if (m.getAnnotation(PostMapping.class) != null) { + paths = + ArrayUtils.addAll( + m.getAnnotation(PostMapping.class).value(), + m.getAnnotation(PostMapping.class).path()); + } else if (m.getAnnotation(GetMapping.class) != null) { + paths = + ArrayUtils.addAll( + m.getAnnotation(GetMapping.class).value(), m.getAnnotation(GetMapping.class).path()); + } else if (m.getAnnotation(PutMapping.class) != null) { + paths = + ArrayUtils.addAll( + m.getAnnotation(PutMapping.class).value(), m.getAnnotation(PutMapping.class).path()); } + if (paths == null) { + return null; + } else { + return Arrays.stream(paths).filter(path -> !"".equals(path)).findFirst().orElse(""); + } + } - private List getHints(Class e) { - if (e.isAnnotationPresent(AssignmentHints.class)) { - return List.of(e.getAnnotationsByType(AssignmentHints.class)[0].value()); - } - return Collections.emptyList(); + private List getHints(Class e) { + if (e.isAnnotationPresent(AssignmentHints.class)) { + return List.of(e.getAnnotationsByType(AssignmentHints.class)[0].value()); } + return Collections.emptyList(); + } } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/Hint.java b/src/main/java/org/owasp/webgoat/container/lessons/Hint.java index 8b61b904a..6a18d8f94 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/Hint.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/Hint.java @@ -1,28 +1,28 @@ /*************************************************************************************************** - * - * + * + * * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - * + * * Copyright (c) 2002 - 2014 Bruce Mayhew - * + * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + * * You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - * + * * Getting Source ============== - * + * * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software * projects. - * + * */ package org.owasp.webgoat.container.lessons; @@ -30,7 +30,7 @@ package org.owasp.webgoat.container.lessons; import lombok.Value; /** - *

Hint class.

+ * Hint class. * * @author rlawson * @version $Id: $Id @@ -38,6 +38,6 @@ import lombok.Value; @Value public class Hint { - private String hint; - private String assignmentPath; + private String hint; + private String assignmentPath; } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/Initializeable.java b/src/main/java/org/owasp/webgoat/container/lessons/Initializeable.java index 6c810d7ca..2a9726b6f 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/Initializeable.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/Initializeable.java @@ -3,10 +3,10 @@ package org.owasp.webgoat.container.lessons; import org.owasp.webgoat.container.users.WebGoatUser; /** - * Interface for initialization of a lesson. It is called when a new user is added to WebGoat and when a users - * reset a lesson. Make sure to clean beforehand and then re-initialize the lesson. + * Interface for initialization of a lesson. It is called when a new user is added to WebGoat and + * when a users reset a lesson. Make sure to clean beforehand and then re-initialize the lesson. */ public interface Initializeable { - void initialize(WebGoatUser webGoatUser); + void initialize(WebGoatUser webGoatUser); } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/Lesson.java b/src/main/java/org/owasp/webgoat/container/lessons/Lesson.java index 91c0743e7..18f031c93 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/Lesson.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/Lesson.java @@ -22,115 +22,103 @@ package org.owasp.webgoat.container.lessons; +import java.util.List; import lombok.Getter; import lombok.Setter; -import java.util.List; - @Getter @Setter public abstract class Lesson { - private static int count = 1; - private Integer id = null; - private List assignments; + private static int count = 1; + private Integer id = null; + private List assignments; - /** - * Constructor for the Lesson object - */ - protected Lesson() { - id = ++count; - } + /** Constructor for the Lesson object */ + protected Lesson() { + id = ++count; + } + /** + * getName. + * + * @return a {@link java.lang.String} object. + */ + public String getName() { + String className = getClass().getName(); + return className.substring(className.lastIndexOf('.') + 1); + } - /** - *

getName.

- * - * @return a {@link java.lang.String} object. - */ - public String getName() { - String className = getClass().getName(); - return className.substring(className.lastIndexOf('.') + 1); - } + /** + * Gets the category attribute of the Lesson object + * + * @return The category value + */ + public Category getCategory() { + return getDefaultCategory(); + } - /** - * Gets the category attribute of the Lesson object - * - * @return The category value - */ - public Category getCategory() { - return getDefaultCategory(); - } + /** + * getDefaultCategory. + * + * @return a {@link org.owasp.webgoat.container.lessons.Category} object. + */ + protected abstract Category getDefaultCategory(); - /** - *

getDefaultCategory.

- * - * @return a {@link org.owasp.webgoat.container.lessons.Category} object. - */ - protected abstract Category getDefaultCategory(); + /** + * Gets the title attribute of the HelloScreen object + * + * @return The title value + */ + public abstract String getTitle(); - /** - * Gets the title attribute of the HelloScreen object - * - * @return The title value - */ - public abstract String getTitle(); + /** + * Returns the default "path" portion of a lesson's URL. + * + *

+ * + *

Legacy webgoat lesson links are of the form "attack?Screen=Xmenu=Ystage=Z". This method + * returns the path portion of the url, i.e., "attack" in the string above. + * + *

Newer, Spring-Controller-based classes will override this method to return "*.do"-styled + * paths. + * + * @return a {@link java.lang.String} object. + */ + protected String getPath() { + return "#lesson/"; + } - /** - *

Returns the default "path" portion of a lesson's URL.

- *

- *

- * Legacy webgoat lesson links are of the form - * "attack?Screen=Xmenu=Ystage=Z". This method returns the path portion of - * the url, i.e., "attack" in the string above. - *

- * Newer, Spring-Controller-based classes will override this method to - * return "*.do"-styled paths. - * - * @return a {@link java.lang.String} object. - */ - protected String getPath() { - return "#lesson/"; - } - - /** - * Get the link that can be used to request this screen. - *

- * Rendering the link in the browser may result in Javascript sending - * additional requests to perform necessary actions or to obtain data - * relevant to the lesson or the element of the lesson selected by the - * user. Thanks to using the hash mark "#" and Javascript handling the - * clicks, the user will experience less waiting as the pages do not have - * to reload entirely. - * - * @return a {@link java.lang.String} object. - */ - public String getLink() { - return String.format("%s%s.lesson", getPath(), getId()); - } - - /** - * Description of the Method - * - * @return Description of the Return Value - */ - public String toString() { - return getTitle(); - } - - public final String getId() { - return this.getClass().getSimpleName(); - } - - public final String getPackage() { - var packageName = this.getClass().getPackageName(); - //package name is the direct package name below lessons (any subpackage will be removed) - return packageName.replaceAll("org.owasp.webgoat.lessons.", "").replaceAll("\\..*", ""); - - - - } + /** + * Get the link that can be used to request this screen. + * + *

Rendering the link in the browser may result in Javascript sending additional requests to + * perform necessary actions or to obtain data relevant to the lesson or the element of the lesson + * selected by the user. Thanks to using the hash mark "#" and Javascript handling the clicks, the + * user will experience less waiting as the pages do not have to reload entirely. + * + * @return a {@link java.lang.String} object. + */ + public String getLink() { + return String.format("%s%s.lesson", getPath(), getId()); + } + /** + * Description of the Method + * + * @return Description of the Return Value + */ + public String toString() { + return getTitle(); + } + public final String getId() { + return this.getClass().getSimpleName(); + } + public final String getPackage() { + var packageName = this.getClass().getPackageName(); + // package name is the direct package name below lessons (any subpackage will be removed) + return packageName.replaceAll("org.owasp.webgoat.lessons.", "").replaceAll("\\..*", ""); + } } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/LessonConnectionInvocationHandler.java b/src/main/java/org/owasp/webgoat/container/lessons/LessonConnectionInvocationHandler.java index fa2643eff..3b90c963d 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/LessonConnectionInvocationHandler.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/LessonConnectionInvocationHandler.java @@ -1,39 +1,38 @@ package org.owasp.webgoat.container.lessons; -import lombok.extern.slf4j.Slf4j; -import org.owasp.webgoat.container.users.WebGoatUser; -import org.springframework.security.core.context.SecurityContextHolder; - import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.Connection; +import lombok.extern.slf4j.Slf4j; +import org.owasp.webgoat.container.users.WebGoatUser; +import org.springframework.security.core.context.SecurityContextHolder; /** - * Handler which sets the correct schema for the currently bounded user. This way users are not seeing each other - * data and we can reset data for just one particular user. + * Handler which sets the correct schema for the currently bounded user. This way users are not + * seeing each other data and we can reset data for just one particular user. */ @Slf4j public class LessonConnectionInvocationHandler implements InvocationHandler { - private final Connection targetConnection; + private final Connection targetConnection; - public LessonConnectionInvocationHandler(Connection targetConnection) { - this.targetConnection = targetConnection; - } + public LessonConnectionInvocationHandler(Connection targetConnection) { + this.targetConnection = targetConnection; + } - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - var authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication != null && authentication.getPrincipal() instanceof WebGoatUser user) { - try (var statement = targetConnection.createStatement()) { - statement.execute("SET SCHEMA \"" + user.getUsername() + "\""); - } - } - try { - return method.invoke(targetConnection, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + var authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.getPrincipal() instanceof WebGoatUser user) { + try (var statement = targetConnection.createStatement()) { + statement.execute("SET SCHEMA \"" + user.getUsername() + "\""); + } } + try { + return method.invoke(targetConnection, args); + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/LessonInfoModel.java b/src/main/java/org/owasp/webgoat/container/lessons/LessonInfoModel.java index 3c77ce095..9a56859ba 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/LessonInfoModel.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/LessonInfoModel.java @@ -4,7 +4,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - *

LessonInfoModel class.

+ * LessonInfoModel class. * * @author dm * @version $Id: $Id @@ -13,9 +13,8 @@ import lombok.Getter; @AllArgsConstructor public class LessonInfoModel { - private String lessonTitle; - private boolean hasSource; - private boolean hasSolution; - private boolean hasPlan; - + private String lessonTitle; + private boolean hasSource; + private boolean hasSolution; + private boolean hasPlan; } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/LessonMenuItem.java b/src/main/java/org/owasp/webgoat/container/lessons/LessonMenuItem.java index 6133e8c06..2b956a6b7 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/LessonMenuItem.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/LessonMenuItem.java @@ -1,166 +1,162 @@ /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - *

- * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at - * https://github.com/WebGoat/WebGoat, a repository for free software projects. + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. */ - package org.owasp.webgoat.container.lessons; import java.util.ArrayList; import java.util.List; /** - *

LessonMenuItem class.

+ * LessonMenuItem class. * * @author rlawson * @version $Id: $Id */ public class LessonMenuItem { - private String name; - private LessonMenuItemType type; - private List children = new ArrayList<>(); - private boolean complete; - private String link; - private int ranking; + private String name; + private LessonMenuItemType type; + private List children = new ArrayList<>(); + private boolean complete; + private String link; + private int ranking; - /** - *

Getter for the field name.

- * - * @return the name - */ - public String getName() { - return name; - } + /** + * Getter for the field name. + * + * @return the name + */ + public String getName() { + return name; + } - /** - *

Setter for the field name.

- * - * @param name the name to set - */ - public void setName(String name) { - this.name = name; - } + /** + * Setter for the field name. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } - /** - *

Getter for the field children.

- * - * @return the children - */ - public List getChildren() { - return children; - } + /** + * Getter for the field children. + * + * @return the children + */ + public List getChildren() { + return children; + } - /** - *

Setter for the field children.

- * - * @param children the children to set - */ - public void setChildren(List children) { - this.children = children; - } + /** + * Setter for the field children. + * + * @param children the children to set + */ + public void setChildren(List children) { + this.children = children; + } - /** - *

Getter for the field type.

- * - * @return the type - */ - public LessonMenuItemType getType() { - return type; - } + /** + * Getter for the field type. + * + * @return the type + */ + public LessonMenuItemType getType() { + return type; + } - /** - *

Setter for the field type.

- * - * @param type the type to set - */ - public void setType(LessonMenuItemType type) { - this.type = type; - } + /** + * Setter for the field type. + * + * @param type the type to set + */ + public void setType(LessonMenuItemType type) { + this.type = type; + } - /** - *

addChild.

- * - * @param child a {@link LessonMenuItem} object. - */ - public void addChild(LessonMenuItem child) { - children.add(child); - } + /** + * addChild. + * + * @param child a {@link LessonMenuItem} object. + */ + public void addChild(LessonMenuItem child) { + children.add(child); + } - @Override - public String toString() { - StringBuilder bldr = new StringBuilder(); - bldr.append("Name: ").append(name).append(" | "); - bldr.append("Type: ").append(type).append(" | "); - return bldr.toString(); - } + @Override + public String toString() { + StringBuilder bldr = new StringBuilder(); + bldr.append("Name: ").append(name).append(" | "); + bldr.append("Type: ").append(type).append(" | "); + return bldr.toString(); + } - /** - *

isComplete.

- * - * @return the complete - */ - public boolean isComplete() { - return complete; - } + /** + * isComplete. + * + * @return the complete + */ + public boolean isComplete() { + return complete; + } - /** - *

Setter for the field complete.

- * - * @param complete the complete to set - */ - public void setComplete(boolean complete) { - this.complete = complete; - } + /** + * Setter for the field complete. + * + * @param complete the complete to set + */ + public void setComplete(boolean complete) { + this.complete = complete; + } - /** - *

Getter for the field link.

- * - * @return the link - */ - public String getLink() { - return link; - } + /** + * Getter for the field link. + * + * @return the link + */ + public String getLink() { + return link; + } - /** - *

Setter for the field link.

- * - * @param link the link to set - */ - public void setLink(String link) { - this.link = link; - } - - public void setRanking(int ranking) { - this.ranking = ranking; - } - - public int getRanking() { - return this.ranking; - } + /** + * Setter for the field link. + * + * @param link the link to set + */ + public void setLink(String link) { + this.link = link; + } + public void setRanking(int ranking) { + this.ranking = ranking; + } + public int getRanking() { + return this.ranking; + } } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/LessonMenuItemType.java b/src/main/java/org/owasp/webgoat/container/lessons/LessonMenuItemType.java index e29cce641..0ce6b660a 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/LessonMenuItemType.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/LessonMenuItemType.java @@ -1,40 +1,40 @@ /*************************************************************************************************** - * - * + * + * * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - * + * * Copyright (c) 2002 - 2014 Bruce Mayhew - * + * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + * * You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - * + * * Getting Source ============== - * + * * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software * projects. - * + * */ package org.owasp.webgoat.container.lessons; /** - *

LessonMenuItemType class.

+ * LessonMenuItemType class. * * @author rlawson * @version $Id: $Id */ public enum LessonMenuItemType { - CATEGORY, - LESSON, - STAGE + CATEGORY, + LESSON, + STAGE } diff --git a/src/main/java/org/owasp/webgoat/container/lessons/LessonScanner.java b/src/main/java/org/owasp/webgoat/container/lessons/LessonScanner.java index 5f9fb86af..e21baef30 100644 --- a/src/main/java/org/owasp/webgoat/container/lessons/LessonScanner.java +++ b/src/main/java/org/owasp/webgoat/container/lessons/LessonScanner.java @@ -1,46 +1,42 @@ package org.owasp.webgoat.container.lessons; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.stereotype.Component; - import java.io.IOException; -import java.util.ArrayList; 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/([^/]*)/.*$"); + private static final Pattern lessonPattern = Pattern.compile("^.*/lessons/([^/]*)/.*$"); - @Getter - private final Set lessons = new HashSet<>(); + @Getter private final Set 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 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 applyPattern(String pattern) { - return lessons.stream().map(lesson -> String.format(pattern, lesson)).toList(); - } + public List applyPattern(String pattern) { + return lessons.stream().map(lesson -> String.format(pattern, lesson)).toList(); + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/EnvironmentService.java b/src/main/java/org/owasp/webgoat/container/service/EnvironmentService.java index 4ab4967af..6393de391 100644 --- a/src/main/java/org/owasp/webgoat/container/service/EnvironmentService.java +++ b/src/main/java/org/owasp/webgoat/container/service/EnvironmentService.java @@ -9,11 +9,10 @@ import org.springframework.web.bind.annotation.RestController; @RequiredArgsConstructor public class EnvironmentService { - private final ApplicationContext context; - - @GetMapping("/server-directory") - public String homeDirectory() { - return context.getEnvironment().getProperty("webgoat.server.directory"); - } + private final ApplicationContext context; + @GetMapping("/server-directory") + public String homeDirectory() { + return context.getEnvironment().getProperty("webgoat.server.directory"); + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/HintService.java b/src/main/java/org/owasp/webgoat/container/service/HintService.java index a0fc4da83..d9ee5be25 100644 --- a/src/main/java/org/owasp/webgoat/container/service/HintService.java +++ b/src/main/java/org/owasp/webgoat/container/service/HintService.java @@ -6,6 +6,8 @@ package org.owasp.webgoat.container.service; +import java.util.Collection; +import java.util.List; import org.owasp.webgoat.container.lessons.Assignment; import org.owasp.webgoat.container.lessons.Hint; import org.owasp.webgoat.container.lessons.Lesson; @@ -14,11 +16,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.Collection; -import java.util.List; - /** - *

HintService class.

+ * HintService class. * * @author rlawson * @version $Id: $Id @@ -26,36 +25,33 @@ import java.util.List; @RestController public class HintService { - public static final String URL_HINTS_MVC = "/service/hint.mvc"; - private final WebSession webSession; + public static final String URL_HINTS_MVC = "/service/hint.mvc"; + private final WebSession webSession; - public HintService(WebSession webSession) { - this.webSession = webSession; - } + public HintService(WebSession webSession) { + this.webSession = webSession; + } - /** - * Returns hints for current lesson - * - * @return a {@link java.util.List} object. - */ - @GetMapping(path = URL_HINTS_MVC, produces = "application/json") - @ResponseBody - public List getHints() { - Lesson l = webSession.getCurrentLesson(); - return createAssignmentHints(l); - } + /** + * Returns hints for current lesson + * + * @return a {@link java.util.List} object. + */ + @GetMapping(path = URL_HINTS_MVC, produces = "application/json") + @ResponseBody + public List getHints() { + Lesson l = webSession.getCurrentLesson(); + return createAssignmentHints(l); + } - private List createAssignmentHints(Lesson l) { - if (l != null) { - return l.getAssignments().stream() - .map(this::createHint) - .flatMap(Collection::stream) - .toList(); - } - return List.of(); + private List createAssignmentHints(Lesson l) { + if (l != null) { + return l.getAssignments().stream().map(this::createHint).flatMap(Collection::stream).toList(); } + return List.of(); + } - private List createHint(Assignment a) { - return a.getHints().stream().map(h -> new Hint(h, a.getPath())).toList(); - } + private List createHint(Assignment a) { + return a.getHints().stream().map(h -> new Hint(h, a.getPath())).toList(); + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/LabelDebugService.java b/src/main/java/org/owasp/webgoat/container/service/LabelDebugService.java index 2c23ceac2..c91aeb1ae 100644 --- a/src/main/java/org/owasp/webgoat/container/service/LabelDebugService.java +++ b/src/main/java/org/owasp/webgoat/container/service/LabelDebugService.java @@ -1,34 +1,33 @@ /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - *

- * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at - * https://github.com/WebGoat/WebGoat, a repository for free software projects. + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. */ - package org.owasp.webgoat.container.service; +import java.util.Map; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.session.LabelDebugger; @@ -40,10 +39,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import java.util.Map; - /** - *

LabelDebugService class.

+ * LabelDebugService class. * * @author nbaars * @version $Id: $Id @@ -53,45 +50,47 @@ import java.util.Map; @AllArgsConstructor public class LabelDebugService { - private static final String URL_DEBUG_LABELS_MVC = "/service/debug/labels.mvc"; - private static final String KEY_ENABLED = "enabled"; - private static final String KEY_SUCCESS = "success"; + private static final String URL_DEBUG_LABELS_MVC = "/service/debug/labels.mvc"; + private static final String KEY_ENABLED = "enabled"; + private static final String KEY_SUCCESS = "success"; - private LabelDebugger labelDebugger; + private LabelDebugger labelDebugger; - /** - * Checks if debugging of labels is enabled or disabled - * - * @return a {@link org.springframework.http.ResponseEntity} object. - */ - @RequestMapping(path = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE) - public @ResponseBody - ResponseEntity> checkDebuggingStatus() { - log.debug("Checking label debugging, it is {}", labelDebugger.isEnabled()); - Map result = createResponse(labelDebugger.isEnabled()); - return new ResponseEntity<>(result, HttpStatus.OK); - } + /** + * Checks if debugging of labels is enabled or disabled + * + * @return a {@link org.springframework.http.ResponseEntity} object. + */ + @RequestMapping(path = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody ResponseEntity> checkDebuggingStatus() { + log.debug("Checking label debugging, it is {}", labelDebugger.isEnabled()); + Map result = createResponse(labelDebugger.isEnabled()); + return new ResponseEntity<>(result, HttpStatus.OK); + } - /** - * Sets the enabled flag on the label debugger to the given parameter - * - * @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object - * @return a {@link org.springframework.http.ResponseEntity} object. - */ - @RequestMapping(value = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE, params = KEY_ENABLED) - public @ResponseBody - ResponseEntity> setDebuggingStatus(@RequestParam("enabled") Boolean enabled) { - log.debug("Setting label debugging to {} ", labelDebugger.isEnabled()); - Map result = createResponse(enabled); - labelDebugger.setEnabled(enabled); - return new ResponseEntity<>(result, HttpStatus.OK); - } + /** + * Sets the enabled flag on the label debugger to the given parameter + * + * @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object + * @return a {@link org.springframework.http.ResponseEntity} object. + */ + @RequestMapping( + value = URL_DEBUG_LABELS_MVC, + produces = MediaType.APPLICATION_JSON_VALUE, + params = KEY_ENABLED) + public @ResponseBody ResponseEntity> setDebuggingStatus( + @RequestParam("enabled") Boolean enabled) { + log.debug("Setting label debugging to {} ", labelDebugger.isEnabled()); + Map result = createResponse(enabled); + labelDebugger.setEnabled(enabled); + return new ResponseEntity<>(result, HttpStatus.OK); + } - /** - * @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object - * @return a {@link java.util.Map} object. - */ - private Map createResponse(Boolean enabled) { - return Map.of(KEY_SUCCESS, Boolean.TRUE, KEY_ENABLED, enabled); - } + /** + * @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object + * @return a {@link java.util.Map} object. + */ + private Map createResponse(Boolean enabled) { + return Map.of(KEY_SUCCESS, Boolean.TRUE, KEY_ENABLED, enabled); + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/LabelService.java b/src/main/java/org/owasp/webgoat/container/service/LabelService.java index 5a6d06b95..1a8f96720 100644 --- a/src/main/java/org/owasp/webgoat/container/service/LabelService.java +++ b/src/main/java/org/owasp/webgoat/container/service/LabelService.java @@ -1,34 +1,33 @@ /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - *

- * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository * for free software projects. */ - package org.owasp.webgoat.container.service; +import java.util.Properties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.i18n.Messages; @@ -40,11 +39,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.Properties; - - /** - *

LabelService class.

+ * LabelService class. * * @author zupzup */ @@ -53,19 +49,19 @@ import java.util.Properties; @RequiredArgsConstructor public class LabelService { - public static final String URL_LABELS_MVC = "/service/labels.mvc"; - private final Messages messages; - private final PluginMessages pluginMessages; + public static final String URL_LABELS_MVC = "/service/labels.mvc"; + private final Messages messages; + private final PluginMessages pluginMessages; - /** - * @return a map of all the labels - */ - @GetMapping(path = URL_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public ResponseEntity fetchLabels() { - var allProperties = new Properties(); - allProperties.putAll(messages.getMessages()); - allProperties.putAll(pluginMessages.getMessages()); - return new ResponseEntity<>(allProperties, HttpStatus.OK); - } + /** + * @return a map of all the labels + */ + @GetMapping(path = URL_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public ResponseEntity fetchLabels() { + var allProperties = new Properties(); + allProperties.putAll(messages.getMessages()); + allProperties.putAll(pluginMessages.getMessages()); + return new ResponseEntity<>(allProperties, HttpStatus.OK); + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/LessonInfoService.java b/src/main/java/org/owasp/webgoat/container/service/LessonInfoService.java index ccbf77f40..fcface416 100644 --- a/src/main/java/org/owasp/webgoat/container/service/LessonInfoService.java +++ b/src/main/java/org/owasp/webgoat/container/service/LessonInfoService.java @@ -8,9 +8,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; - /** - *

LessonInfoService class.

+ * LessonInfoService class. * * @author dm * @version $Id: $Id @@ -19,18 +18,16 @@ import org.springframework.web.bind.annotation.RestController; @AllArgsConstructor public class LessonInfoService { - private final WebSession webSession; - - /** - *

getLessonInfo.

- * - * @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); - } + private final WebSession webSession; + /** + * getLessonInfo. + * + * @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); + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/LessonMenuService.java b/src/main/java/org/owasp/webgoat/container/service/LessonMenuService.java index 6fe6d32e3..961e10d47 100644 --- a/src/main/java/org/owasp/webgoat/container/service/LessonMenuService.java +++ b/src/main/java/org/owasp/webgoat/container/service/LessonMenuService.java @@ -1,34 +1,36 @@ /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - *

- * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at - * https://github.com/WebGoat/WebGoat, a repository for free software projects. + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. */ - package org.owasp.webgoat.container.service; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; import lombok.AllArgsConstructor; import org.owasp.webgoat.container.lessons.Assignment; import org.owasp.webgoat.container.lessons.Category; @@ -45,13 +47,8 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; - /** - *

LessonMenuService class.

+ * LessonMenuService class. * * @author rlawson * @version $Id: $Id @@ -60,72 +57,68 @@ import java.util.Map; @AllArgsConstructor public class LessonMenuService { - public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc"; - private final Course course; - private final WebSession webSession; - private UserTrackerRepository userTrackerRepository; + public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc"; + private final Course course; + private final WebSession webSession; + private UserTrackerRepository userTrackerRepository; - @Value("#{'${exclude.categories}'.split(',')}") - private List excludeCategories; + @Value("#{'${exclude.categories}'.split(',')}") + private List excludeCategories; - @Value("#{'${exclude.lessons}'.split(',')}") - private List excludeLessons; + @Value("#{'${exclude.lessons}'.split(',')}") + private List excludeLessons; - /** - * Returns the lesson menu which is used to build the left nav - * - * @return a {@link java.util.List} object. - */ - @RequestMapping(path = URL_LESSONMENU_MVC, produces = "application/json") - public - @ResponseBody - List showLeftNav() { - List menu = new ArrayList<>(); - List categories = course.getCategories(); - UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); + /** + * Returns the lesson menu which is used to build the left nav + * + * @return a {@link java.util.List} object. + */ + @RequestMapping(path = URL_LESSONMENU_MVC, produces = "application/json") + public @ResponseBody List showLeftNav() { + List menu = new ArrayList<>(); + List categories = course.getCategories(); + UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); - for (Category category : categories) { - if (excludeCategories.contains(category.name())) { - continue; - } - LessonMenuItem categoryItem = new LessonMenuItem(); - categoryItem.setName(category.getName()); - categoryItem.setType(LessonMenuItemType.CATEGORY); - // check for any lessons for this category - List lessons = course.getLessons(category); - lessons = lessons.stream().sorted(Comparator.comparing(Lesson::getTitle)).toList(); - for (Lesson lesson : lessons) { - if (excludeLessons.contains(lesson.getName())) { - continue; - } - LessonMenuItem lessonItem = new LessonMenuItem(); - lessonItem.setName(lesson.getTitle()); - lessonItem.setLink(lesson.getLink()); - lessonItem.setType(LessonMenuItemType.LESSON); - LessonTracker lessonTracker = userTracker.getLessonTracker(lesson); - boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson); - lessonItem.setComplete(lessonSolved); - categoryItem.addChild(lessonItem); - } - categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking()); - menu.add(categoryItem); + for (Category category : categories) { + if (excludeCategories.contains(category.name())) { + continue; + } + LessonMenuItem categoryItem = new LessonMenuItem(); + categoryItem.setName(category.getName()); + categoryItem.setType(LessonMenuItemType.CATEGORY); + // check for any lessons for this category + List lessons = course.getLessons(category); + lessons = lessons.stream().sorted(Comparator.comparing(Lesson::getTitle)).toList(); + for (Lesson lesson : lessons) { + if (excludeLessons.contains(lesson.getName())) { + continue; } - return menu; - + LessonMenuItem lessonItem = new LessonMenuItem(); + lessonItem.setName(lesson.getTitle()); + lessonItem.setLink(lesson.getLink()); + lessonItem.setType(LessonMenuItemType.LESSON); + LessonTracker lessonTracker = userTracker.getLessonTracker(lesson); + boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson); + lessonItem.setComplete(lessonSolved); + categoryItem.addChild(lessonItem); + } + categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking()); + menu.add(categoryItem); } + return menu; + } - private boolean lessonCompleted(Map map, Lesson currentLesson) { - boolean result = true; - for (Map.Entry entry : map.entrySet()) { - Assignment storedAssignment = entry.getKey(); - for (Assignment lessonAssignment : currentLesson.getAssignments()) { - if (lessonAssignment.getName().equals(storedAssignment.getName())) { - result = result && entry.getValue(); - break; - } - } - + private boolean lessonCompleted(Map map, Lesson currentLesson) { + boolean result = true; + for (Map.Entry 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; + } } + return result; + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/LessonProgressService.java b/src/main/java/org/owasp/webgoat/container/service/LessonProgressService.java index 73deb7b60..23fc38da5 100644 --- a/src/main/java/org/owasp/webgoat/container/service/LessonProgressService.java +++ b/src/main/java/org/owasp/webgoat/container/service/LessonProgressService.java @@ -1,5 +1,6 @@ package org.owasp.webgoat.container.service; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -10,11 +11,8 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import java.util.List; - - /** - *

LessonProgressService class.

+ * LessonProgressService class. * * @author webgoat */ @@ -22,38 +20,38 @@ import java.util.List; @RequiredArgsConstructor public class LessonProgressService { - private final UserTrackerRepository userTrackerRepository; - private final WebSession webSession; + private final UserTrackerRepository userTrackerRepository; + private final WebSession webSession; - /** - * Endpoint for fetching the complete lesson overview which informs the user about whether all the assignments are solved. - * Used as the last page of the lesson to generate a lesson overview. - * - * @return list of assignments - */ - @RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json") - @ResponseBody - public List lessonOverview() { - var userTracker = userTrackerRepository.findByUser(webSession.getUserName()); - var currentLesson = webSession.getCurrentLesson(); + /** + * Endpoint for fetching the complete lesson overview which informs the user about whether all the + * assignments are solved. Used as the last page of the lesson to generate a lesson overview. + * + * @return list of assignments + */ + @RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json") + @ResponseBody + public List lessonOverview() { + var userTracker = userTrackerRepository.findByUser(webSession.getUserName()); + var currentLesson = webSession.getCurrentLesson(); - if (currentLesson != null) { - var lessonTracker = userTracker.getLessonTracker(currentLesson); - return lessonTracker.getLessonOverview().entrySet().stream() - .map(entry -> new LessonOverview(entry.getKey(), entry.getValue())) - .toList(); - } - return List.of(); + if (currentLesson != null) { + var lessonTracker = userTracker.getLessonTracker(currentLesson); + return lessonTracker.getLessonOverview().entrySet().stream() + .map(entry -> new LessonOverview(entry.getKey(), entry.getValue())) + .toList(); } + return List.of(); + } - @AllArgsConstructor - @Getter - //Jackson does not really like returning a map of directly, see http://stackoverflow.com/questions/11628698/can-we-make-object-as-key-in-map-when-using-json - //so creating intermediate object is the easiest solution - private static class LessonOverview { + @AllArgsConstructor + @Getter + // Jackson does not really like returning a map of directly, see + // http://stackoverflow.com/questions/11628698/can-we-make-object-as-key-in-map-when-using-json + // so creating intermediate object is the easiest solution + private static class LessonOverview { - private Assignment assignment; - private Boolean solved; - - } + private Assignment assignment; + private Boolean solved; + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/LessonTitleService.java b/src/main/java/org/owasp/webgoat/container/service/LessonTitleService.java index 99006fa0a..d1c902880 100644 --- a/src/main/java/org/owasp/webgoat/container/service/LessonTitleService.java +++ b/src/main/java/org/owasp/webgoat/container/service/LessonTitleService.java @@ -6,9 +6,8 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; - /** - *

LessonTitleService class.

+ * LessonTitleService class. * * @author dm * @version $Id: $Id @@ -16,23 +15,20 @@ import org.springframework.web.bind.annotation.ResponseBody; @Controller public class LessonTitleService { - private final WebSession webSession; + 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() : ""; - } + 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() : ""; + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/ReportCardService.java b/src/main/java/org/owasp/webgoat/container/service/ReportCardService.java index 14c6c2fa9..a01bce5c1 100644 --- a/src/main/java/org/owasp/webgoat/container/service/ReportCardService.java +++ b/src/main/java/org/owasp/webgoat/container/service/ReportCardService.java @@ -1,34 +1,34 @@ /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - *

- * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at - * https://github.com/WebGoat/WebGoat, a repository for free software projects. + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. */ - package org.owasp.webgoat.container.service; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -43,11 +43,8 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; -import java.util.ArrayList; -import java.util.List; - /** - *

ReportCardService

+ * ReportCardService * * @author nbaars * @version $Id: $Id @@ -56,52 +53,53 @@ import java.util.List; @AllArgsConstructor public class ReportCardService { - private final WebSession webSession; - private final UserTrackerRepository userTrackerRepository; - private final Course course; - private final PluginMessages pluginMessages; + 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()); + /** + * 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; + 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 { + @Getter + @Setter + private final class ReportCard { - private int totalNumberOfLessons; - private int totalNumberOfAssignments; - private int solvedLessons; - private int numberOfAssignmentsSolved; - private int numberOfLessonsSolved; - private List lessonStatistics = new ArrayList<>(); - } + private int totalNumberOfLessons; + private int totalNumberOfAssignments; + private int solvedLessons; + private int numberOfAssignmentsSolved; + private int numberOfLessonsSolved; + private List lessonStatistics = new ArrayList<>(); + } - @Setter - @Getter - private final class LessonStatistics { - private String name; - private boolean solved; - private int numberOfAttempts; - } + @Setter + @Getter + private final class LessonStatistics { + private String name; + private boolean solved; + private int numberOfAttempts; + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/RestartLessonService.java b/src/main/java/org/owasp/webgoat/container/service/RestartLessonService.java index d14b4e11c..2f0450d9e 100644 --- a/src/main/java/org/owasp/webgoat/container/service/RestartLessonService.java +++ b/src/main/java/org/owasp/webgoat/container/service/RestartLessonService.java @@ -24,6 +24,8 @@ package org.owasp.webgoat.container.service; +import java.util.List; +import java.util.function.Function; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.flywaydb.core.Flyway; @@ -37,33 +39,30 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; -import java.util.List; -import java.util.function.Function; - @Controller @AllArgsConstructor @Slf4j public class RestartLessonService { - private final WebSession webSession; - private final UserTrackerRepository userTrackerRepository; - private final Function flywayLessons; - private final List lessonsToInitialize; + private final WebSession webSession; + private final UserTrackerRepository userTrackerRepository; + private final Function flywayLessons; + private final List lessonsToInitialize; - @RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text") - @ResponseStatus(value = HttpStatus.OK) - public void restartLesson() { - Lesson al = webSession.getCurrentLesson(); - log.debug("Restarting lesson: " + al); + @RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text") + @ResponseStatus(value = HttpStatus.OK) + public void restartLesson() { + Lesson al = webSession.getCurrentLesson(); + log.debug("Restarting lesson: " + al); - UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); - userTracker.reset(al); - userTrackerRepository.save(userTracker); + UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); + userTracker.reset(al); + userTrackerRepository.save(userTracker); - var flyway = flywayLessons.apply(webSession.getUserName()); - flyway.clean(); - flyway.migrate(); + var flyway = flywayLessons.apply(webSession.getUserName()); + flyway.clean(); + flyway.migrate(); - lessonsToInitialize.forEach(i -> i.initialize(webSession.getUser())); - } + lessonsToInitialize.forEach(i -> i.initialize(webSession.getUser())); + } } diff --git a/src/main/java/org/owasp/webgoat/container/service/SessionService.java b/src/main/java/org/owasp/webgoat/container/service/SessionService.java index 6352237e4..b1a14d2c2 100644 --- a/src/main/java/org/owasp/webgoat/container/service/SessionService.java +++ b/src/main/java/org/owasp/webgoat/container/service/SessionService.java @@ -17,17 +17,17 @@ import org.springframework.web.bind.annotation.ResponseBody; @RequiredArgsConstructor public class SessionService { - private final WebSession webSession; - private final RestartLessonService restartLessonService; - private final Messages messages; + private final WebSession webSession; + private final RestartLessonService restartLessonService; + private final Messages messages; - @RequestMapping(path = "/service/enable-security.mvc", produces = "application/json") - @ResponseBody - public String applySecurity() { - webSession.toggleSecurity(); - restartLessonService.restartLesson(); + @RequestMapping(path = "/service/enable-security.mvc", produces = "application/json") + @ResponseBody + public String applySecurity() { + webSession.toggleSecurity(); + restartLessonService.restartLesson(); - var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled"; - return messages.getMessage(msg); - } + var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled"; + return messages.getMessage(msg); + } } diff --git a/src/main/java/org/owasp/webgoat/container/session/Course.java b/src/main/java/org/owasp/webgoat/container/session/Course.java index 349150c4e..225af4053 100644 --- a/src/main/java/org/owasp/webgoat/container/session/Course.java +++ b/src/main/java/org/owasp/webgoat/container/session/Course.java @@ -1,36 +1,36 @@ package org.owasp.webgoat.container.session; +import java.util.List; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.lessons.Category; import org.owasp.webgoat.container.lessons.Lesson; -import java.util.List; - /** * ************************************************************************************************ + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author Bruce Mayhew WebGoat * @version $Id: $Id @@ -39,60 +39,61 @@ import java.util.List; @Slf4j public class Course { - private List lessons; + private List lessons; - public Course(List lessons) { - this.lessons = lessons; - } + public Course(List lessons) { + this.lessons = lessons; + } - /** - * Gets the categories attribute of the Course object - * - * @return The categories value - */ - public List getCategories() { - return lessons.parallelStream().map(Lesson::getCategory).distinct().sorted().toList(); - } + /** + * Gets the categories attribute of the Course object + * + * @return The categories value + */ + public List getCategories() { + return lessons.parallelStream().map(Lesson::getCategory).distinct().sorted().toList(); + } - /** - * Gets the firstLesson attribute of the Course object - * - * @return The firstLesson value - */ - public Lesson getFirstLesson() { - // Category 0 is the admin function. We want the first real category - // to be returned. This is normally the General category and the Http Basics lesson - return getLessons(getCategories().get(0)).get(0); - } + /** + * Gets the firstLesson attribute of the Course object + * + * @return The firstLesson value + */ + public Lesson getFirstLesson() { + // Category 0 is the admin function. We want the first real category + // to be returned. This is normally the General category and the Http Basics lesson + return getLessons(getCategories().get(0)).get(0); + } - /** - *

Getter for the field lessons.

- * - * @return a {@link java.util.List} object. - */ - public List getLessons() { - return this.lessons; - } + /** + * Getter for the field lessons. + * + * @return a {@link java.util.List} object. + */ + public List getLessons() { + return this.lessons; + } - /** - *

Getter for the field lessons.

- * - * @param category a {@link org.owasp.webgoat.container.lessons.Category} object. - * @return a {@link java.util.List} object. - */ - public List getLessons(Category category) { - return this.lessons.stream().filter(l -> l.getCategory() == category).toList(); - } + /** + * Getter for the field lessons. + * + * @param category a {@link org.owasp.webgoat.container.lessons.Category} object. + * @return a {@link java.util.List} object. + */ + public List getLessons(Category category) { + return this.lessons.stream().filter(l -> l.getCategory() == category).toList(); + } - public void setLessons(List lessons) { - this.lessons = lessons; - } + public void setLessons(List lessons) { + this.lessons = lessons; + } - public int getTotalOfLessons() { - return this.lessons.size(); - } + public int getTotalOfLessons() { + return this.lessons.size(); + } - public int getTotalOfAssignments() { - return this.lessons.stream().reduce(0, (total, lesson) -> lesson.getAssignments().size() + total, Integer::sum); - } + public int getTotalOfAssignments() { + return this.lessons.stream() + .reduce(0, (total, lesson) -> lesson.getAssignments().size() + total, Integer::sum); + } } diff --git a/src/main/java/org/owasp/webgoat/container/session/LabelDebugger.java b/src/main/java/org/owasp/webgoat/container/session/LabelDebugger.java index 69823e7b4..34e7b7111 100644 --- a/src/main/java/org/owasp/webgoat/container/session/LabelDebugger.java +++ b/src/main/java/org/owasp/webgoat/container/session/LabelDebugger.java @@ -3,44 +3,40 @@ package org.owasp.webgoat.container.session; import java.io.Serializable; /** - *

LabelDebugger class.

+ * LabelDebugger class. * * @author dm * @version $Id: $Id */ public class LabelDebugger implements Serializable { - private boolean enabled = false; + private boolean enabled = false; - /** - *

isEnabled.

- * - * @return a boolean. - */ - public boolean isEnabled() { - return enabled; - } + /** + * isEnabled. + * + * @return a boolean. + */ + public boolean isEnabled() { + return enabled; + } - /** - *

Enables label debugging

- */ - public void enable() { - this.enabled = true; - } + /** Enables label debugging */ + public void enable() { + this.enabled = true; + } - /** - *

Disables label debugging

- */ - public void disable() { - this.enabled = false; - } - - /** - *

Sets the status to enabled

- * @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } + /** Disables label debugging */ + public void disable() { + this.enabled = false; + } + /** + * Sets the status to enabled + * + * @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object + */ + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } } diff --git a/src/main/java/org/owasp/webgoat/container/session/UserSessionData.java b/src/main/java/org/owasp/webgoat/container/session/UserSessionData.java index 2e58caf0f..be55c3971 100644 --- a/src/main/java/org/owasp/webgoat/container/session/UserSessionData.java +++ b/src/main/java/org/owasp/webgoat/container/session/UserSessionData.java @@ -2,35 +2,31 @@ package org.owasp.webgoat.container.session; import java.util.HashMap; -/** - * Created by jason on 1/4/17. - */ +/** Created by jason on 1/4/17. */ public class UserSessionData { - private HashMap userSessionData = new HashMap<>(); + private HashMap userSessionData = new HashMap<>(); - public UserSessionData() { + 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 UserSessionData(String key, String value) { - setValue(key,value); + public void setValue(String key, Object value) { + if (userSessionData.containsKey(key)) { + userSessionData.replace(key, value); + } else { + userSessionData.put(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); - } - } - + } } diff --git a/src/main/java/org/owasp/webgoat/container/session/WebSession.java b/src/main/java/org/owasp/webgoat/container/session/WebSession.java index f8b2296d2..22b339db6 100644 --- a/src/main/java/org/owasp/webgoat/container/session/WebSession.java +++ b/src/main/java/org/owasp/webgoat/container/session/WebSession.java @@ -1,34 +1,36 @@ 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; -import java.io.Serializable; - /** * ************************************************************************************************* + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see - * http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later - * version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author Jeff Williams Aspect Security * @author Bruce Mayhew WebGoat @@ -37,51 +39,52 @@ import java.io.Serializable; */ public class WebSession implements Serializable { - private static final long serialVersionUID = -4270066103101711560L; - private final WebGoatUser currentUser; - private transient Lesson currentLesson; - private boolean securityEnabled; + 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(); - } + public WebSession() { + this.currentUser = + (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + } - /** - *

Setter for the field currentScreen.

- * - * @param lesson current lesson - */ - public void setCurrentLesson(Lesson lesson) { - this.currentLesson = lesson; - } + /** + * Setter for the field currentScreen. + * + * @param lesson current lesson + */ + public void setCurrentLesson(Lesson lesson) { + this.currentLesson = lesson; + } - /** - *

getCurrentLesson.

- * - * @return a {@link Lesson} object. - */ - public Lesson getCurrentLesson() { - return this.currentLesson; - } + /** + * 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(); - } + /** + * Gets the userName attribute of the WebSession object + * + * @return The userName value + */ + public String getUserName() { + return currentUser.getUsername(); + } - public WebGoatUser getUser() { - return currentUser; - } + public WebGoatUser getUser() { + return currentUser; + } - public void toggleSecurity() { - this.securityEnabled = !this.securityEnabled; - } + public void toggleSecurity() { + this.securityEnabled = !this.securityEnabled; + } - public boolean isSecurityEnabled() { - return securityEnabled; - } + public boolean isSecurityEnabled() { + return securityEnabled; + } } diff --git a/src/main/java/org/owasp/webgoat/container/users/LessonTracker.java b/src/main/java/org/owasp/webgoat/container/users/LessonTracker.java index ab882c29a..2cc0c58af 100644 --- a/src/main/java/org/owasp/webgoat/container/users/LessonTracker.java +++ b/src/main/java/org/owasp/webgoat/container/users/LessonTracker.java @@ -1,40 +1,38 @@ - package org.owasp.webgoat.container.users; -import lombok.Getter; -import org.owasp.webgoat.container.lessons.Lesson; -import org.owasp.webgoat.container.lessons.Assignment; - -import javax.persistence.*; import java.util.*; import java.util.stream.Collectors; - +import javax.persistence.*; +import lombok.Getter; +import org.owasp.webgoat.container.lessons.Assignment; +import org.owasp.webgoat.container.lessons.Lesson; /** * ************************************************************************************************ + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author Bruce Mayhew WebGoat * @version $Id: $Id @@ -43,72 +41,69 @@ import java.util.stream.Collectors; @Entity public class LessonTracker { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - @Getter - private String lessonName; - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - private final Set solvedAssignments = new HashSet<>(); - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - private final Set allAssignments = new HashSet<>(); - @Getter - private int numberOfAttempts = 0; - @Version - private Integer version; + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; - private LessonTracker() { - //JPA - } + @Getter private String lessonName; - public LessonTracker(Lesson lesson) { - lessonName = lesson.getId(); - allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments()); - } + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + private final Set solvedAssignments = new HashSet<>(); - public Optional getAssignment(String name) { - return allAssignments.stream().filter(a -> a.getName().equals(name)).findFirst(); - } + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + private final Set allAssignments = new HashSet<>(); - /** - * Mark an assignment as solved - * - * @param solvedAssignment the assignment which the user solved - */ - public void assignmentSolved(String solvedAssignment) { - getAssignment(solvedAssignment).ifPresent(solvedAssignments::add); - } + @Getter private int numberOfAttempts = 0; + @Version private Integer version; - /** - * @return did they user solved all solvedAssignments for the lesson? - */ - public boolean isLessonSolved() { - return allAssignments.size() == solvedAssignments.size(); - } + private LessonTracker() { + // JPA + } - /** - * Increase the number attempts to solve the lesson - */ - public void incrementAttempts() { - numberOfAttempts++; - } + public LessonTracker(Lesson lesson) { + lessonName = lesson.getId(); + allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments()); + } - /** - * Reset the tracker. We do not reset the number of attempts here! - */ - void reset() { - solvedAssignments.clear(); - } + public Optional getAssignment(String name) { + return allAssignments.stream().filter(a -> a.getName().equals(name)).findFirst(); + } - /** - * @return list containing all the assignments solved or not - */ - public Map getLessonOverview() { - List notSolved = allAssignments.stream() - .filter(i -> !solvedAssignments.contains(i)) - .toList(); - Map overview = notSolved.stream().collect(Collectors.toMap(a -> a, b -> false)); - overview.putAll(solvedAssignments.stream().collect(Collectors.toMap(a -> a, b -> true))); - return overview; - } + /** + * Mark an assignment as solved + * + * @param solvedAssignment the assignment which the user solved + */ + public void assignmentSolved(String solvedAssignment) { + getAssignment(solvedAssignment).ifPresent(solvedAssignments::add); + } + + /** + * @return did they user solved all solvedAssignments for the lesson? + */ + public boolean isLessonSolved() { + return allAssignments.size() == solvedAssignments.size(); + } + + /** Increase the number attempts to solve the lesson */ + public void incrementAttempts() { + numberOfAttempts++; + } + + /** Reset the tracker. We do not reset the number of attempts here! */ + void reset() { + solvedAssignments.clear(); + } + + /** + * @return list containing all the assignments solved or not + */ + public Map getLessonOverview() { + List notSolved = + allAssignments.stream().filter(i -> !solvedAssignments.contains(i)).toList(); + Map overview = + notSolved.stream().collect(Collectors.toMap(a -> a, b -> false)); + overview.putAll(solvedAssignments.stream().collect(Collectors.toMap(a -> a, b -> true))); + return overview; + } } diff --git a/src/main/java/org/owasp/webgoat/container/users/RegistrationController.java b/src/main/java/org/owasp/webgoat/container/users/RegistrationController.java index d3d645796..4dc628f86 100644 --- a/src/main/java/org/owasp/webgoat/container/users/RegistrationController.java +++ b/src/main/java/org/owasp/webgoat/container/users/RegistrationController.java @@ -1,5 +1,8 @@ package org.owasp.webgoat.container.users; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.AuthenticationManager; @@ -9,10 +12,6 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; - /** * @author nbaars * @since 3/19/17. @@ -22,25 +21,29 @@ import javax.validation.Valid; @Slf4j public class RegistrationController { - private UserValidator userValidator; - private UserService userService; - private AuthenticationManager authenticationManager; + private UserValidator userValidator; + private UserService userService; + private AuthenticationManager authenticationManager; - @GetMapping("/registration") - public String showForm(UserForm userForm) { - return "registration"; + @GetMapping("/registration") + public String showForm(UserForm userForm) { + return "registration"; + } + + @PostMapping("/register.mvc") + public String registration( + @ModelAttribute("userForm") @Valid UserForm userForm, + BindingResult bindingResult, + HttpServletRequest request) + throws ServletException { + userValidator.validate(userForm, bindingResult); + + if (bindingResult.hasErrors()) { + return "registration"; } + userService.addUser(userForm.getUsername(), userForm.getPassword()); + request.login(userForm.getUsername(), userForm.getPassword()); - @PostMapping("/register.mvc") - public String registration(@ModelAttribute("userForm") @Valid UserForm userForm, BindingResult bindingResult, HttpServletRequest request) throws ServletException { - userValidator.validate(userForm, bindingResult); - - if (bindingResult.hasErrors()) { - return "registration"; - } - userService.addUser(userForm.getUsername(), userForm.getPassword()); - request.login(userForm.getUsername(), userForm.getPassword()); - - return "redirect:/attack"; - } + return "redirect:/attack"; + } } diff --git a/src/main/java/org/owasp/webgoat/container/users/Scoreboard.java b/src/main/java/org/owasp/webgoat/container/users/Scoreboard.java index 6eb2e6508..2f5ddefe2 100644 --- a/src/main/java/org/owasp/webgoat/container/users/Scoreboard.java +++ b/src/main/java/org/owasp/webgoat/container/users/Scoreboard.java @@ -1,5 +1,8 @@ package org.owasp.webgoat.container.users; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import lombok.AllArgsConstructor; import lombok.Getter; import org.owasp.webgoat.container.i18n.PluginMessages; @@ -8,10 +11,6 @@ import org.owasp.webgoat.container.session.Course; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - /** * Temp endpoint just for the CTF. * @@ -22,52 +21,63 @@ import java.util.Optional; @AllArgsConstructor public class Scoreboard { - private final UserTrackerRepository userTrackerRepository; - private final UserRepository userRepository; - private final Course course; - private final PluginMessages pluginMessages; + private final UserTrackerRepository userTrackerRepository; + private final UserRepository userRepository; + private final Course course; + private final PluginMessages pluginMessages; - @AllArgsConstructor - @Getter - private class Ranking { - private String username; - private List flagsCaptured; - } + @AllArgsConstructor + @Getter + private class Ranking { + private String username; + private List flagsCaptured; + } - @GetMapping("/scoreboard-data") - public List getRankings() { - List allUsers = userRepository.findAll(); - List rankings = new ArrayList<>(); - for (WebGoatUser user : allUsers) { - if (user.getUsername().startsWith("csrf-")) { - //the csrf- assignment specific users do not need to be in the overview - continue; - } - UserTracker userTracker = userTrackerRepository.findByUser(user.getUsername()); - rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker))); - } - /* sort on number of captured flags to present an ordered ranking */ - rankings.sort((o1, o2) -> o2.getFlagsCaptured().size() - o1.getFlagsCaptured().size()); - return rankings; + @GetMapping("/scoreboard-data") + public List getRankings() { + List allUsers = userRepository.findAll(); + List rankings = new ArrayList<>(); + for (WebGoatUser user : allUsers) { + if (user.getUsername().startsWith("csrf-")) { + // the csrf- assignment specific users do not need to be in the overview + continue; + } + UserTracker userTracker = userTrackerRepository.findByUser(user.getUsername()); + rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker))); } + /* sort on number of captured flags to present an ordered ranking */ + rankings.sort((o1, o2) -> o2.getFlagsCaptured().size() - o1.getFlagsCaptured().size()); + return rankings; + } - private List challengesSolved(UserTracker userTracker) { - List challenges = List.of("Challenge1", "Challenge2", "Challenge3", "Challenge4", "Challenge5", "Challenge6", "Challenge7", "Challenge8", "Challenge9"); - return challenges.stream() - .map(userTracker::getLessonTracker) - .flatMap(Optional::stream) - .filter(LessonTracker::isLessonSolved) - .map(LessonTracker::getLessonName) - .map(this::toLessonTitle) - .toList(); - } + private List challengesSolved(UserTracker userTracker) { + List challenges = + List.of( + "Challenge1", + "Challenge2", + "Challenge3", + "Challenge4", + "Challenge5", + "Challenge6", + "Challenge7", + "Challenge8", + "Challenge9"); + return challenges.stream() + .map(userTracker::getLessonTracker) + .flatMap(Optional::stream) + .filter(LessonTracker::isLessonSolved) + .map(LessonTracker::getLessonName) + .map(this::toLessonTitle) + .toList(); + } - private String toLessonTitle(String id) { - String titleKey = course.getLessons().stream() - .filter(l -> l.getId().equals(id)) - .findFirst() - .map(Lesson::getTitle) - .orElse("No title"); - return pluginMessages.getMessage(titleKey, titleKey); - } + private String toLessonTitle(String id) { + String titleKey = + course.getLessons().stream() + .filter(l -> l.getId().equals(id)) + .findFirst() + .map(Lesson::getTitle) + .orElse("No title"); + return pluginMessages.getMessage(titleKey, titleKey); + } } diff --git a/src/main/java/org/owasp/webgoat/container/users/UserForm.java b/src/main/java/org/owasp/webgoat/container/users/UserForm.java index 2cc73ba62..416bba094 100644 --- a/src/main/java/org/owasp/webgoat/container/users/UserForm.java +++ b/src/main/java/org/owasp/webgoat/container/users/UserForm.java @@ -1,11 +1,10 @@ package org.owasp.webgoat.container.users; -import lombok.Getter; -import lombok.Setter; - import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; /** * @author nbaars @@ -15,16 +14,18 @@ import javax.validation.constraints.Size; @Setter public class UserForm { - @NotNull - @Size(min = 6, max = 45) - @Pattern(regexp = "[a-z0-9-]*", message = "can only contain lowercase letters, digits, and -") - private String username; - @NotNull - @Size(min = 6, max = 10) - private String password; - @NotNull - @Size(min = 6, max = 10) - private String matchingPassword; - @NotNull - private String agree; + @NotNull + @Size(min = 6, max = 45) + @Pattern(regexp = "[a-z0-9-]*", message = "can only contain lowercase letters, digits, and -") + private String username; + + @NotNull + @Size(min = 6, max = 10) + private String password; + + @NotNull + @Size(min = 6, max = 10) + private String matchingPassword; + + @NotNull private String agree; } diff --git a/src/main/java/org/owasp/webgoat/container/users/UserRepository.java b/src/main/java/org/owasp/webgoat/container/users/UserRepository.java index 322ff8e66..86d9b2cd4 100644 --- a/src/main/java/org/owasp/webgoat/container/users/UserRepository.java +++ b/src/main/java/org/owasp/webgoat/container/users/UserRepository.java @@ -1,8 +1,7 @@ package org.owasp.webgoat.container.users; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; /** * @author nbaars @@ -10,10 +9,9 @@ import java.util.List; */ public interface UserRepository extends JpaRepository { - WebGoatUser findByUsername(String username); + WebGoatUser findByUsername(String username); - List findAll(); - - boolean existsByUsername(String username); + List findAll(); + boolean existsByUsername(String username); } diff --git a/src/main/java/org/owasp/webgoat/container/users/UserService.java b/src/main/java/org/owasp/webgoat/container/users/UserService.java index a2b7566fe..e12668f00 100644 --- a/src/main/java/org/owasp/webgoat/container/users/UserService.java +++ b/src/main/java/org/owasp/webgoat/container/users/UserService.java @@ -1,5 +1,7 @@ package org.owasp.webgoat.container.users; +import java.util.List; +import java.util.function.Function; import lombok.AllArgsConstructor; import org.flywaydb.core.Flyway; import org.owasp.webgoat.container.lessons.Initializeable; @@ -8,9 +10,6 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.function.Function; - /** * @author nbaars * @since 3/19/17. @@ -19,42 +18,42 @@ import java.util.function.Function; @AllArgsConstructor public class UserService implements UserDetailsService { - private final UserRepository userRepository; - private final UserTrackerRepository userTrackerRepository; - private final JdbcTemplate jdbcTemplate; - private final Function flywayLessons; - private final List lessonInitializables; + private final UserRepository userRepository; + private final UserTrackerRepository userTrackerRepository; + private final JdbcTemplate jdbcTemplate; + private final Function flywayLessons; + private final List lessonInitializables; - @Override - public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException { - WebGoatUser webGoatUser = userRepository.findByUsername(username); - if (webGoatUser == null) { - throw new UsernameNotFoundException("User not found"); - } else { - webGoatUser.createUser(); - lessonInitializables.forEach(l -> l.initialize(webGoatUser)); - } - return webGoatUser; + @Override + public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException { + WebGoatUser webGoatUser = userRepository.findByUsername(username); + if (webGoatUser == null) { + throw new UsernameNotFoundException("User not found"); + } else { + webGoatUser.createUser(); + lessonInitializables.forEach(l -> l.initialize(webGoatUser)); } + return webGoatUser; + } - public void addUser(String username, String password) { - //get user if there exists one by the name - var userAlreadyExists = userRepository.existsByUsername(username); - var webGoatUser = userRepository.save(new WebGoatUser(username, password)); + public void addUser(String username, String password) { + // get user if there exists one by the name + var userAlreadyExists = userRepository.existsByUsername(username); + var webGoatUser = userRepository.save(new WebGoatUser(username, password)); - if (!userAlreadyExists) { - userTrackerRepository.save(new UserTracker(username)); //if user previously existed it will not get another tracker - createLessonsForUser(webGoatUser); - } + if (!userAlreadyExists) { + userTrackerRepository.save( + new UserTracker(username)); // if user previously existed it will not get another tracker + createLessonsForUser(webGoatUser); } + } - private void createLessonsForUser(WebGoatUser webGoatUser) { - jdbcTemplate.execute("CREATE SCHEMA \"" + webGoatUser.getUsername() + "\" authorization dba"); - flywayLessons.apply(webGoatUser.getUsername()).migrate(); - } - - public List getAllUsers() { - return userRepository.findAll(); - } + private void createLessonsForUser(WebGoatUser webGoatUser) { + jdbcTemplate.execute("CREATE SCHEMA \"" + webGoatUser.getUsername() + "\" authorization dba"); + flywayLessons.apply(webGoatUser.getUsername()).migrate(); + } + public List getAllUsers() { + return userRepository.findAll(); + } } diff --git a/src/main/java/org/owasp/webgoat/container/users/UserSession.java b/src/main/java/org/owasp/webgoat/container/users/UserSession.java index f742fd02e..5bf29a7f0 100644 --- a/src/main/java/org/owasp/webgoat/container/users/UserSession.java +++ b/src/main/java/org/owasp/webgoat/container/users/UserSession.java @@ -15,7 +15,6 @@ import org.springframework.data.annotation.Id; @NoArgsConstructor(access = AccessLevel.PROTECTED) public class UserSession { - private WebGoatUser webGoatUser; - @Id - private String sessionId; + private WebGoatUser webGoatUser; + @Id private String sessionId; } diff --git a/src/main/java/org/owasp/webgoat/container/users/UserTracker.java b/src/main/java/org/owasp/webgoat/container/users/UserTracker.java index 0850f0eac..86bdf4c14 100644 --- a/src/main/java/org/owasp/webgoat/container/users/UserTracker.java +++ b/src/main/java/org/owasp/webgoat/container/users/UserTracker.java @@ -1,43 +1,41 @@ - package org.owasp.webgoat.container.users; -import lombok.extern.slf4j.Slf4j; -import org.owasp.webgoat.container.lessons.Lesson; -import org.owasp.webgoat.container.lessons.Assignment; - -import javax.persistence.*; import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - +import javax.persistence.*; +import lombok.extern.slf4j.Slf4j; +import org.owasp.webgoat.container.lessons.Assignment; +import org.owasp.webgoat.container.lessons.Lesson; /** * ************************************************************************************************ + * *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * + *

This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. * * @author Bruce Mayhew WebGoat * @version $Id: $Id @@ -47,80 +45,83 @@ import java.util.stream.Collectors; @Entity public class UserTracker { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - @Column(name = "username") - private String user; - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) - private Set lessonTrackers = new HashSet<>(); + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; - private UserTracker() {} + @Column(name = "username") + private String user; - public UserTracker(final String user) { - this.user = user; + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + private Set lessonTrackers = new HashSet<>(); + + private UserTracker() {} + + public UserTracker(final String user) { + this.user = user; + } + + /** + * Returns an existing lesson tracker or create a new one based on the lesson + * + * @param lesson the lesson + * @return a lesson tracker created if not already present + */ + public LessonTracker getLessonTracker(Lesson lesson) { + Optional lessonTracker = + lessonTrackers.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst(); + if (!lessonTracker.isPresent()) { + LessonTracker newLessonTracker = new LessonTracker(lesson); + lessonTrackers.add(newLessonTracker); + return newLessonTracker; + } else { + return lessonTracker.get(); } + } - /** - * Returns an existing lesson tracker or create a new one based on the lesson - * - * @param lesson the lesson - * @return a lesson tracker created if not already present - */ - public LessonTracker getLessonTracker(Lesson lesson) { - Optional lessonTracker = lessonTrackers - .stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst(); - if (!lessonTracker.isPresent()) { - LessonTracker newLessonTracker = new LessonTracker(lesson); - lessonTrackers.add(newLessonTracker); - return newLessonTracker; - } else { - return lessonTracker.get(); - } - } + /** + * Query method for finding a specific lesson tracker based on id + * + * @param id the id of the lesson + * @return optional due to the fact we can only create a lesson tracker based on a lesson + */ + public Optional getLessonTracker(String id) { + return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst(); + } - /** - * Query method for finding a specific lesson tracker based on id - * - * @param id the id of the lesson - * @return optional due to the fact we can only create a lesson tracker based on a lesson - */ - public Optional getLessonTracker(String id) { - return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst(); - } + public void assignmentSolved(Lesson lesson, String assignmentName) { + LessonTracker lessonTracker = getLessonTracker(lesson); + lessonTracker.incrementAttempts(); + lessonTracker.assignmentSolved(assignmentName); + } - public void assignmentSolved(Lesson lesson, String assignmentName) { - LessonTracker lessonTracker = getLessonTracker(lesson); - lessonTracker.incrementAttempts(); - lessonTracker.assignmentSolved(assignmentName); - } + public void assignmentFailed(Lesson lesson) { + LessonTracker lessonTracker = getLessonTracker(lesson); + lessonTracker.incrementAttempts(); + } - public void assignmentFailed(Lesson lesson) { - LessonTracker lessonTracker = getLessonTracker(lesson); - lessonTracker.incrementAttempts(); - } + public void reset(Lesson al) { + LessonTracker lessonTracker = getLessonTracker(al); + lessonTracker.reset(); + } - public void reset(Lesson al) { - LessonTracker lessonTracker = getLessonTracker(al); - lessonTracker.reset(); + public int numberOfLessonsSolved() { + int numberOfLessonsSolved = 0; + for (LessonTracker lessonTracker : lessonTrackers) { + if (lessonTracker.isLessonSolved()) { + numberOfLessonsSolved = numberOfLessonsSolved + 1; + } } + return numberOfLessonsSolved; + } - public int numberOfLessonsSolved() { - int numberOfLessonsSolved = 0; - for (LessonTracker lessonTracker : lessonTrackers) { - if (lessonTracker.isLessonSolved()) { - numberOfLessonsSolved = numberOfLessonsSolved + 1; - } - } - return numberOfLessonsSolved; - } - - public int numberOfAssignmentsSolved() { - int numberOfAssignmentsSolved = 0; - for (LessonTracker lessonTracker : lessonTrackers) { - Map lessonOverview = lessonTracker.getLessonOverview(); - numberOfAssignmentsSolved = lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue(); - } - return numberOfAssignmentsSolved; + public int numberOfAssignmentsSolved() { + int numberOfAssignmentsSolved = 0; + for (LessonTracker lessonTracker : lessonTrackers) { + Map lessonOverview = lessonTracker.getLessonOverview(); + numberOfAssignmentsSolved = + lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue(); } + return numberOfAssignmentsSolved; + } } diff --git a/src/main/java/org/owasp/webgoat/container/users/UserTrackerRepository.java b/src/main/java/org/owasp/webgoat/container/users/UserTrackerRepository.java index c80db503c..154360c3e 100644 --- a/src/main/java/org/owasp/webgoat/container/users/UserTrackerRepository.java +++ b/src/main/java/org/owasp/webgoat/container/users/UserTrackerRepository.java @@ -8,6 +8,5 @@ import org.springframework.data.jpa.repository.JpaRepository; */ public interface UserTrackerRepository extends JpaRepository { - UserTracker findByUser(String user); - + UserTracker findByUser(String user); } diff --git a/src/main/java/org/owasp/webgoat/container/users/UserValidator.java b/src/main/java/org/owasp/webgoat/container/users/UserValidator.java index fc1d6691a..6301e08b3 100644 --- a/src/main/java/org/owasp/webgoat/container/users/UserValidator.java +++ b/src/main/java/org/owasp/webgoat/container/users/UserValidator.java @@ -13,23 +13,23 @@ import org.springframework.validation.Validator; @AllArgsConstructor public class UserValidator implements Validator { - private final UserRepository userRepository; + private final UserRepository userRepository; - @Override - public boolean supports(Class clazz) { - return UserForm.class.equals(clazz); + @Override + public boolean supports(Class clazz) { + return UserForm.class.equals(clazz); + } + + @Override + public void validate(Object o, Errors errors) { + UserForm userForm = (UserForm) o; + + if (userRepository.findByUsername(userForm.getUsername()) != null) { + errors.rejectValue("username", "username.duplicate"); } - @Override - public void validate(Object o, Errors errors) { - UserForm userForm = (UserForm) o; - - if (userRepository.findByUsername(userForm.getUsername()) != null) { - errors.rejectValue("username", "username.duplicate"); - } - - if (!userForm.getMatchingPassword().equals(userForm.getPassword())) { - errors.rejectValue("matchingPassword", "password.diff"); - } + if (!userForm.getMatchingPassword().equals(userForm.getPassword())) { + errors.rejectValue("matchingPassword", "password.diff"); } + } } diff --git a/src/main/java/org/owasp/webgoat/container/users/WebGoatUser.java b/src/main/java/org/owasp/webgoat/container/users/WebGoatUser.java index f64462348..517e50a60 100644 --- a/src/main/java/org/owasp/webgoat/container/users/WebGoatUser.java +++ b/src/main/java/org/owasp/webgoat/container/users/WebGoatUser.java @@ -1,17 +1,16 @@ package org.owasp.webgoat.container.users; +import java.util.Collection; +import java.util.Collections; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Transient; import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Transient; -import java.util.Collection; -import java.util.Collections; - /** * @author nbaars * @since 3/19/17. @@ -20,79 +19,72 @@ import java.util.Collections; @Entity public class WebGoatUser implements UserDetails { - public static final String ROLE_USER = "WEBGOAT_USER"; - public static final String ROLE_ADMIN = "WEBGOAT_ADMIN"; + public static final String ROLE_USER = "WEBGOAT_USER"; + public static final String ROLE_ADMIN = "WEBGOAT_ADMIN"; - @Id - private String username; - private String password; - private String role = ROLE_USER; - @Transient - private User user; + @Id private String username; + private String password; + private String role = ROLE_USER; + @Transient private User user; - protected WebGoatUser() { - } + protected WebGoatUser() {} - public WebGoatUser(String username, String password) { - this(username, password, ROLE_USER); - } + public WebGoatUser(String username, String password) { + this(username, password, ROLE_USER); + } - public WebGoatUser(String username, String password, String role) { - this.username = username; - this.password = password; - this.role = role; - createUser(); - } + public WebGoatUser(String username, String password, String role) { + this.username = username; + this.password = password; + this.role = role; + createUser(); + } + public void createUser() { + this.user = new User(username, password, getAuthorities()); + } - public void createUser() { - this.user = new User(username, password, getAuthorities()); - } + public Collection getAuthorities() { + return Collections.singleton(new SimpleGrantedAuthority(getRole())); + } - public Collection getAuthorities() { - return Collections.singleton(new SimpleGrantedAuthority(getRole())); - } + public String getRole() { + return this.role; + } - public String getRole() { - return this.role; - } + public String getUsername() { + return this.username; + } - public String getUsername() { - return this.username; - } + public String getPassword() { + return this.password; + } - public String getPassword() { - return this.password; - } + @Override + public boolean isAccountNonExpired() { + return this.user.isAccountNonExpired(); + } - @Override - public boolean isAccountNonExpired() { - return this.user.isAccountNonExpired(); - } + @Override + public boolean isAccountNonLocked() { + return this.user.isAccountNonLocked(); + } - @Override - public boolean isAccountNonLocked() { - return this.user.isAccountNonLocked(); - } + @Override + public boolean isCredentialsNonExpired() { + return this.user.isCredentialsNonExpired(); + } - @Override - public boolean isCredentialsNonExpired() { - return this.user.isCredentialsNonExpired(); - } + @Override + public boolean isEnabled() { + return this.user.isEnabled(); + } - @Override - public boolean isEnabled() { - return this.user.isEnabled(); - } - - public boolean equals(Object obj) { - return obj instanceof WebGoatUser webGoatUser && this.user.equals(webGoatUser.user); - } - - public int hashCode() { - return user.hashCode(); - } + public boolean equals(Object obj) { + return obj instanceof WebGoatUser webGoatUser && this.user.equals(webGoatUser.user); + } + public int hashCode() { + return user.hashCode(); + } } - - diff --git a/src/main/java/org/owasp/webgoat/lessons/authbypass/AccountVerificationHelper.java b/src/main/java/org/owasp/webgoat/lessons/authbypass/AccountVerificationHelper.java index bf11d0ce6..41b64d518 100644 --- a/src/main/java/org/owasp/webgoat/lessons/authbypass/AccountVerificationHelper.java +++ b/src/main/java/org/owasp/webgoat/lessons/authbypass/AccountVerificationHelper.java @@ -25,63 +25,72 @@ package org.owasp.webgoat.lessons.authbypass; import java.util.HashMap; import java.util.Map; -/** - * Created by appsec on 7/18/17. - */ +/** Created by appsec on 7/18/17. */ public class AccountVerificationHelper { - //simulating database storage of verification credentials - private static final Integer verifyUserId = 1223445; - private static final Map userSecQuestions = new HashMap<>(); + // simulating database storage of verification credentials + private static final Integer verifyUserId = 1223445; + private static final Map userSecQuestions = new HashMap<>(); - static { - userSecQuestions.put("secQuestion0", "Dr. Watson"); - userSecQuestions.put("secQuestion1", "Baker Street"); + static { + userSecQuestions.put("secQuestion0", "Dr. Watson"); + userSecQuestions.put("secQuestion1", "Baker Street"); + } + + private static final Map secQuestionStore = new HashMap<>(); + + static { + secQuestionStore.put(verifyUserId, userSecQuestions); + } + // end 'data store set up' + + // this is to aid feedback in the attack process and is not intended to be part of the + // 'vulnerable' code + public boolean didUserLikelylCheat(HashMap submittedAnswers) { + boolean likely = false; + + if (submittedAnswers.size() == secQuestionStore.get(verifyUserId).size()) { + likely = true; } - private static final Map secQuestionStore = new HashMap<>(); - - static { - secQuestionStore.put(verifyUserId, userSecQuestions); + if ((submittedAnswers.containsKey("secQuestion0") + && submittedAnswers + .get("secQuestion0") + .equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) + && (submittedAnswers.containsKey("secQuestion1") + && submittedAnswers + .get("secQuestion1") + .equals(secQuestionStore.get(verifyUserId).get("secQuestion1")))) { + likely = true; + } else { + likely = false; } - // end 'data store set up' - // this is to aid feedback in the attack process and is not intended to be part of the 'vulnerable' code - public boolean didUserLikelylCheat(HashMap submittedAnswers) { - boolean likely = false; - - if (submittedAnswers.size() == secQuestionStore.get(verifyUserId).size()) { - likely = true; - } - - if ((submittedAnswers.containsKey("secQuestion0") && submittedAnswers.get("secQuestion0").equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) - && (submittedAnswers.containsKey("secQuestion1") && submittedAnswers.get("secQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1")))) { - likely = true; - } else { - likely = false; - } - - return likely; + return likely; + } + // end of cheating check ... the method below is the one of real interest. Can you find the flaw? + public boolean verifyAccount(Integer userId, HashMap submittedQuestions) { + // short circuit if no questions are submitted + if (submittedQuestions.entrySet().size() != secQuestionStore.get(verifyUserId).size()) { + return false; } - //end of cheating check ... the method below is the one of real interest. Can you find the flaw? - - public boolean verifyAccount(Integer userId, HashMap submittedQuestions) { - //short circuit if no questions are submitted - if (submittedQuestions.entrySet().size() != secQuestionStore.get(verifyUserId).size()) { - return false; - } - - if (submittedQuestions.containsKey("secQuestion0") && !submittedQuestions.get("secQuestion0").equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) { - return false; - } - - if (submittedQuestions.containsKey("secQuestion1") && !submittedQuestions.get("secQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) { - return false; - } - - // else - return true; + if (submittedQuestions.containsKey("secQuestion0") + && !submittedQuestions + .get("secQuestion0") + .equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) { + return false; } + + if (submittedQuestions.containsKey("secQuestion1") + && !submittedQuestions + .get("secQuestion1") + .equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) { + return false; + } + + // else + return true; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/authbypass/AuthBypass.java b/src/main/java/org/owasp/webgoat/lessons/authbypass/AuthBypass.java index cb01d5a01..8680b47d7 100644 --- a/src/main/java/org/owasp/webgoat/lessons/authbypass/AuthBypass.java +++ b/src/main/java/org/owasp/webgoat/lessons/authbypass/AuthBypass.java @@ -29,13 +29,13 @@ import org.springframework.stereotype.Component; @Component public class AuthBypass extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A7; - } + @Override + public Category getDefaultCategory() { + return Category.A7; + } - @Override - public String getTitle() { - return "auth-bypass.title"; - } + @Override + public String getTitle() { + return "auth-bypass.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/authbypass/VerifyAccount.java b/src/main/java/org/owasp/webgoat/lessons/authbypass/VerifyAccount.java index 2ca6ee5f0..ed7988b13 100644 --- a/src/main/java/org/owasp/webgoat/lessons/authbypass/VerifyAccount.java +++ b/src/main/java/org/owasp/webgoat/lessons/authbypass/VerifyAccount.java @@ -22,6 +22,13 @@ package org.owasp.webgoat.lessons.authbypass; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -33,63 +40,54 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Created by jason on 1/5/17. - */ +/** Created by jason on 1/5/17. */ @RestController -@AssignmentHints({"auth-bypass.hints.verify.1", "auth-bypass.hints.verify.2", "auth-bypass.hints.verify.3", "auth-bypass.hints.verify.4"}) +@AssignmentHints({ + "auth-bypass.hints.verify.1", + "auth-bypass.hints.verify.2", + "auth-bypass.hints.verify.3", + "auth-bypass.hints.verify.4" +}) public class VerifyAccount extends AssignmentEndpoint { - @Autowired - private WebSession webSession; + @Autowired private WebSession webSession; - @Autowired - UserSessionData userSessionData; - - @PostMapping(path = "/auth-bypass/verify-account", produces = {"application/json"}) - @ResponseBody - public AttackResult completed(@RequestParam String userId, @RequestParam String verifyMethod, HttpServletRequest req) throws ServletException, IOException { - AccountVerificationHelper verificationHelper = new AccountVerificationHelper(); - Map submittedAnswers = parseSecQuestions(req); - if (verificationHelper.didUserLikelylCheat((HashMap) submittedAnswers)) { - return failed(this) - .feedback("verify-account.cheated") - .output("Yes, you guessed correctly, but see the feedback message") - .build(); - } - - // else - if (verificationHelper.verifyAccount(Integer.valueOf(userId), (HashMap) submittedAnswers)) { - userSessionData.setValue("account-verified-id", userId); - return success(this) - .feedback("verify-account.success") - .build(); - } else { - return failed(this) - .feedback("verify-account.failed") - .build(); - } + @Autowired UserSessionData userSessionData; + @PostMapping( + path = "/auth-bypass/verify-account", + produces = {"application/json"}) + @ResponseBody + public AttackResult completed( + @RequestParam String userId, @RequestParam String verifyMethod, HttpServletRequest req) + throws ServletException, IOException { + AccountVerificationHelper verificationHelper = new AccountVerificationHelper(); + Map submittedAnswers = parseSecQuestions(req); + if (verificationHelper.didUserLikelylCheat((HashMap) submittedAnswers)) { + return failed(this) + .feedback("verify-account.cheated") + .output("Yes, you guessed correctly, but see the feedback message") + .build(); } - private HashMap parseSecQuestions(HttpServletRequest req) { - Map userAnswers = new HashMap<>(); - List paramNames = Collections.list(req.getParameterNames()); - for (String paramName : paramNames) { - //String paramName = req.getParameterNames().nextElement(); - if (paramName.contains("secQuestion")) { - userAnswers.put(paramName, req.getParameter(paramName)); - } - } - return (HashMap) userAnswers; + // else + if (verificationHelper.verifyAccount(Integer.valueOf(userId), (HashMap) submittedAnswers)) { + userSessionData.setValue("account-verified-id", userId); + return success(this).feedback("verify-account.success").build(); + } else { + return failed(this).feedback("verify-account.failed").build(); } + } + private HashMap parseSecQuestions(HttpServletRequest req) { + Map userAnswers = new HashMap<>(); + List paramNames = Collections.list(req.getParameterNames()); + for (String paramName : paramNames) { + // String paramName = req.getParameterNames().nextElement(); + if (paramName.contains("secQuestion")) { + userAnswers.put(paramName, req.getParameter(paramName)); + } + } + return (HashMap) userAnswers; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictions.java b/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictions.java index 0b6d259b9..7aaa06c5c 100644 --- a/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictions.java +++ b/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictions.java @@ -28,13 +28,13 @@ import org.springframework.stereotype.Component; @Component public class BypassRestrictions extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CLIENT_SIDE; - } + @Override + public Category getDefaultCategory() { + return Category.CLIENT_SIDE; + } - @Override - public String getTitle() { - return "bypass-restrictions.title"; - } + @Override + public String getTitle() { + return "bypass-restrictions.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFieldRestrictions.java b/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFieldRestrictions.java index 6deeb3eca..2ea8db965 100644 --- a/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFieldRestrictions.java +++ b/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFieldRestrictions.java @@ -32,24 +32,29 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class BypassRestrictionsFieldRestrictions extends AssignmentEndpoint { - @PostMapping("/BypassRestrictions/FieldRestrictions") - @ResponseBody - public AttackResult completed(@RequestParam String select, @RequestParam String radio, @RequestParam String checkbox, @RequestParam String shortInput, @RequestParam String readOnlyInput) { - if (select.equals("option1") || select.equals("option2")) { - return failed(this).build(); - } - if (radio.equals("option1") || radio.equals("option2")) { - return failed(this).build(); - } - if (checkbox.equals("on") || checkbox.equals("off")) { - return failed(this).build(); - } - if (shortInput.length() <= 5) { - return failed(this).build(); - } - if ("change".equals(readOnlyInput)) { - return failed(this).build(); - } - return success(this).build(); + @PostMapping("/BypassRestrictions/FieldRestrictions") + @ResponseBody + public AttackResult completed( + @RequestParam String select, + @RequestParam String radio, + @RequestParam String checkbox, + @RequestParam String shortInput, + @RequestParam String readOnlyInput) { + if (select.equals("option1") || select.equals("option2")) { + return failed(this).build(); } + if (radio.equals("option1") || radio.equals("option2")) { + return failed(this).build(); + } + if (checkbox.equals("on") || checkbox.equals("off")) { + return failed(this).build(); + } + if (shortInput.length() <= 5) { + return failed(this).build(); + } + if ("change".equals(readOnlyInput)) { + return failed(this).build(); + } + return success(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFrontendValidation.java b/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFrontendValidation.java index f4bfd2230..9d2c048eb 100644 --- a/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFrontendValidation.java +++ b/src/main/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFrontendValidation.java @@ -32,40 +32,48 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class BypassRestrictionsFrontendValidation extends AssignmentEndpoint { - @PostMapping("/BypassRestrictions/frontendValidation") - @ResponseBody - public AttackResult completed(@RequestParam String field1, @RequestParam String field2, @RequestParam String field3, @RequestParam String field4, @RequestParam String field5, @RequestParam String field6, @RequestParam String field7, @RequestParam Integer error) { - final String regex1 = "^[a-z]{3}$"; - final String regex2 = "^[0-9]{3}$"; - final String regex3 = "^[a-zA-Z0-9 ]*$"; - final String regex4 = "^(one|two|three|four|five|six|seven|eight|nine)$"; - final String regex5 = "^\\d{5}$"; - final String regex6 = "^\\d{5}(-\\d{4})?$"; - final String regex7 = "^[2-9]\\d{2}-?\\d{3}-?\\d{4}$"; - if (error > 0) { - return failed(this).build(); - } - if (field1.matches(regex1)) { - return failed(this).build(); - } - if (field2.matches(regex2)) { - return failed(this).build(); - } - if (field3.matches(regex3)) { - return failed(this).build(); - } - if (field4.matches(regex4)) { - return failed(this).build(); - } - if (field5.matches(regex5)) { - return failed(this).build(); - } - if (field6.matches(regex6)) { - return failed(this).build(); - } - if (field7.matches(regex7)) { - return failed(this).build(); - } - return success(this).build(); + @PostMapping("/BypassRestrictions/frontendValidation") + @ResponseBody + public AttackResult completed( + @RequestParam String field1, + @RequestParam String field2, + @RequestParam String field3, + @RequestParam String field4, + @RequestParam String field5, + @RequestParam String field6, + @RequestParam String field7, + @RequestParam Integer error) { + final String regex1 = "^[a-z]{3}$"; + final String regex2 = "^[0-9]{3}$"; + final String regex3 = "^[a-zA-Z0-9 ]*$"; + final String regex4 = "^(one|two|three|four|five|six|seven|eight|nine)$"; + final String regex5 = "^\\d{5}$"; + final String regex6 = "^\\d{5}(-\\d{4})?$"; + final String regex7 = "^[2-9]\\d{2}-?\\d{3}-?\\d{4}$"; + if (error > 0) { + return failed(this).build(); } + if (field1.matches(regex1)) { + return failed(this).build(); + } + if (field2.matches(regex2)) { + return failed(this).build(); + } + if (field3.matches(regex3)) { + return failed(this).build(); + } + if (field4.matches(regex4)) { + return failed(this).build(); + } + if (field5.matches(regex5)) { + return failed(this).build(); + } + if (field6.matches(regex6)) { + return failed(this).build(); + } + if (field7.matches(regex7)) { + return failed(this).build(); + } + return success(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/ChallengeIntro.java b/src/main/java/org/owasp/webgoat/lessons/challenges/ChallengeIntro.java index c3e1b1c8e..1c6ba4c37 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/ChallengeIntro.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/ChallengeIntro.java @@ -9,13 +9,13 @@ import org.owasp.webgoat.container.lessons.Lesson; */ public class ChallengeIntro extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CHALLENGE; - } + @Override + public Category getDefaultCategory() { + return Category.CHALLENGE; + } - @Override - public String getTitle() { - return "challenge0.title"; - } + @Override + public String getTitle() { + return "challenge0.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/Email.java b/src/main/java/org/owasp/webgoat/lessons/challenges/Email.java index fe1eb40b2..81e105a9a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/Email.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/Email.java @@ -22,11 +22,10 @@ package org.owasp.webgoat.lessons.challenges; -import lombok.Builder; -import lombok.Data; - import java.io.Serializable; import java.time.LocalDateTime; +import lombok.Builder; +import lombok.Data; /** * @author nbaars @@ -36,9 +35,9 @@ import java.time.LocalDateTime; @Data public class Email implements Serializable { - private LocalDateTime time; - private String contents; - private String sender; - private String title; - private String recipient; + private LocalDateTime time; + private String contents; + private String sender; + private String title; + private String recipient; } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java b/src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java index fdeb5a85a..d78186585 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/Flag.java @@ -22,6 +22,11 @@ package org.owasp.webgoat.lessons.challenges; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.stream.IntStream; +import javax.annotation.PostConstruct; import lombok.AllArgsConstructor; import lombok.Getter; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -37,12 +42,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.PostConstruct; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.stream.IntStream; - /** * @author nbaars * @since 3/23/17. @@ -50,39 +49,41 @@ import java.util.stream.IntStream; @RestController public class Flag extends AssignmentEndpoint { - public static final Map FLAGS = new HashMap<>(); - @Autowired - private UserTrackerRepository userTrackerRepository; - @Autowired - private WebSession webSession; + public static final Map FLAGS = new HashMap<>(); + @Autowired private UserTrackerRepository userTrackerRepository; + @Autowired private WebSession webSession; - @AllArgsConstructor - private class FlagPosted { - @Getter - private boolean lessonCompleted; - } + @AllArgsConstructor + private class FlagPosted { + @Getter private boolean lessonCompleted; + } - @PostConstruct - public void initFlags() { - IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString())); - } + @PostConstruct + public void initFlags() { + IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString())); + } - @RequestMapping(path = "/challenge/flag", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public AttackResult postFlag(@RequestParam String flag) { - UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); - String currentChallenge = webSession.getCurrentLesson().getName(); - int challengeNumber = Integer.valueOf(currentChallenge.substring(currentChallenge.length() - 1, currentChallenge.length())); - String expectedFlag = FLAGS.get(challengeNumber); - final AttackResult attackResult; - if (expectedFlag.equals(flag)) { - userTracker.assignmentSolved(webSession.getCurrentLesson(), "Assignment" + challengeNumber); - attackResult = success(this).feedback("challenge.flag.correct").build(); - } else { - userTracker.assignmentFailed(webSession.getCurrentLesson()); - attackResult = failed(this).feedback("challenge.flag.incorrect").build(); - } - userTrackerRepository.save(userTracker); - return attackResult; + @RequestMapping( + path = "/challenge/flag", + method = RequestMethod.POST, + produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public AttackResult postFlag(@RequestParam String flag) { + UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); + String currentChallenge = webSession.getCurrentLesson().getName(); + int challengeNumber = + Integer.valueOf( + currentChallenge.substring(currentChallenge.length() - 1, currentChallenge.length())); + String expectedFlag = FLAGS.get(challengeNumber); + final AttackResult attackResult; + if (expectedFlag.equals(flag)) { + userTracker.assignmentSolved(webSession.getCurrentLesson(), "Assignment" + challengeNumber); + attackResult = success(this).feedback("challenge.flag.correct").build(); + } else { + userTracker.assignmentFailed(webSession.getCurrentLesson()); + attackResult = failed(this).feedback("challenge.flag.incorrect").build(); } + userTrackerRepository.save(userTracker); + return attackResult; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/SolutionConstants.java b/src/main/java/org/owasp/webgoat/lessons/challenges/SolutionConstants.java index c2ca6d849..890d80d06 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/SolutionConstants.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/SolutionConstants.java @@ -30,8 +30,8 @@ package org.owasp.webgoat.lessons.challenges; */ public interface SolutionConstants { - //TODO should be random generated when starting the server - String PASSWORD = "!!webgoat_admin_1234!!"; - String PASSWORD_TOM = "thisisasecretfortomonly"; - String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2"; + // TODO should be random generated when starting the server + String PASSWORD = "!!webgoat_admin_1234!!"; + String PASSWORD_TOM = "thisisasecretfortomonly"; + String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2"; } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Assignment1.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Assignment1.java index 62a865f63..0d07c7427 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Assignment1.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Assignment1.java @@ -1,5 +1,8 @@ package org.owasp.webgoat.lessons.challenges.challenge1; +import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD; + +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.owasp.webgoat.lessons.challenges.Flag; @@ -9,33 +12,30 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; - -import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD; - /** * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -45,20 +45,25 @@ import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD; @RestController public class Assignment1 extends AssignmentEndpoint { - @PostMapping("/challenge/1") - @ResponseBody - public AttackResult completed(@RequestParam String username, @RequestParam String password, HttpServletRequest request) { - boolean ipAddressKnown = true; - boolean passwordCorrect = "admin".equals(username) && PASSWORD.replace("1234", String.format("%04d",ImageServlet.PINCODE)).equals(password); - if (passwordCorrect && ipAddressKnown) { - return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(1)).build(); - } else if (passwordCorrect) { - return failed(this).feedback("ip.address.unknown").build(); - } - return failed(this).build(); + @PostMapping("/challenge/1") + @ResponseBody + public AttackResult completed( + @RequestParam String username, @RequestParam String password, HttpServletRequest request) { + boolean ipAddressKnown = true; + boolean passwordCorrect = + "admin".equals(username) + && PASSWORD + .replace("1234", String.format("%04d", ImageServlet.PINCODE)) + .equals(password); + if (passwordCorrect && ipAddressKnown) { + return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(1)).build(); + } else if (passwordCorrect) { + return failed(this).feedback("ip.address.unknown").build(); } + return failed(this).build(); + } - public static boolean containsHeader(HttpServletRequest request) { - return StringUtils.hasText(request.getHeader("X-Forwarded-For")); - } + public static boolean containsHeader(HttpServletRequest request) { + return StringUtils.hasText(request.getHeader("X-Forwarded-For")); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Challenge1.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Challenge1.java index 940568113..fa9129040 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Challenge1.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/Challenge1.java @@ -11,13 +11,13 @@ import org.springframework.stereotype.Component; @Component public class Challenge1 extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CHALLENGE; - } + @Override + public Category getDefaultCategory() { + return Category.CHALLENGE; + } - @Override - public String getTitle() { - return "challenge1.title"; - } + @Override + public String getTitle() { + return "challenge1.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/ImageServlet.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/ImageServlet.java index 925ddfd4d..1de00e012 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/ImageServlet.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge1/ImageServlet.java @@ -1,36 +1,41 @@ package org.owasp.webgoat.lessons.challenges.challenge1; +import static org.springframework.web.bind.annotation.RequestMethod.GET; +import static org.springframework.web.bind.annotation.RequestMethod.POST; + +import java.io.IOException; +import java.security.SecureRandom; +import javax.servlet.http.HttpServlet; import org.springframework.core.io.ClassPathResource; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServlet; -import java.io.IOException; -import java.security.SecureRandom; - -import static org.springframework.web.bind.annotation.RequestMethod.GET; -import static org.springframework.web.bind.annotation.RequestMethod.POST; - @RestController public class ImageServlet extends HttpServlet { - - private static final long serialVersionUID = 9132775506936676850L; - static final public int PINCODE = new SecureRandom().nextInt(10000); - @RequestMapping(method = {GET, POST}, value = "/challenge/logo", produces = MediaType.IMAGE_PNG_VALUE) - @ResponseBody - public byte[] logo() throws IOException { - byte[] in = new ClassPathResource("lessons/challenges/images/webgoat2.png").getInputStream().readAllBytes(); - - String pincode = String.format("%04d", PINCODE); - - in[81216]=(byte) pincode.charAt(0); - in[81217]=(byte) pincode.charAt(1); - in[81218]=(byte) pincode.charAt(2); - in[81219]=(byte) pincode.charAt(3); + private static final long serialVersionUID = 9132775506936676850L; + public static final int PINCODE = new SecureRandom().nextInt(10000); - return in; - } + @RequestMapping( + method = {GET, POST}, + value = "/challenge/logo", + produces = MediaType.IMAGE_PNG_VALUE) + @ResponseBody + public byte[] logo() throws IOException { + byte[] in = + new ClassPathResource("lessons/challenges/images/webgoat2.png") + .getInputStream() + .readAllBytes(); + + String pincode = String.format("%04d", PINCODE); + + in[81216] = (byte) pincode.charAt(0); + in[81217] = (byte) pincode.charAt(1); + in[81218] = (byte) pincode.charAt(2); + in[81219] = (byte) pincode.charAt(3); + + return in; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java index 48d6f85d2..d6b8dcceb 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Assignment5.java @@ -22,6 +22,8 @@ package org.owasp.webgoat.lessons.challenges.challenge5; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -33,38 +35,41 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.PreparedStatement; -import java.sql.ResultSet; - @RestController @Slf4j public class Assignment5 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public Assignment5(LessonDataSource dataSource) { - this.dataSource = dataSource; + public Assignment5(LessonDataSource dataSource) { + this.dataSource = dataSource; + } + + @PostMapping("/challenge/5") + @ResponseBody + public AttackResult login( + @RequestParam String username_login, @RequestParam String password_login) throws Exception { + if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) { + return failed(this).feedback("required4").build(); } - - @PostMapping("/challenge/5") - @ResponseBody - public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception { - if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) { - return failed(this).feedback("required4").build(); - } - if (!"Larry".equals(username_login)) { - return failed(this).feedback("user.not.larry").feedbackArgs(username_login).build(); - } - try (var connection = dataSource.getConnection()) { - PreparedStatement statement = connection.prepareStatement("select password from challenge_users where userid = '" + username_login + "' and password = '" + password_login + "'"); - ResultSet resultSet = statement.executeQuery(); - - if (resultSet.next()) { - return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(5)).build(); - } else { - return failed(this).feedback("challenge.close").build(); - } - } + if (!"Larry".equals(username_login)) { + return failed(this).feedback("user.not.larry").feedbackArgs(username_login).build(); } + try (var connection = dataSource.getConnection()) { + PreparedStatement statement = + connection.prepareStatement( + "select password from challenge_users where userid = '" + + username_login + + "' and password = '" + + password_login + + "'"); + ResultSet resultSet = statement.executeQuery(); + + if (resultSet.next()) { + return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(5)).build(); + } else { + return failed(this).feedback("challenge.close").build(); + } + } + } } - diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Challenge5.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Challenge5.java index 6f17215c2..7fe4cfa9c 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Challenge5.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge5/Challenge5.java @@ -33,13 +33,13 @@ import org.springframework.stereotype.Component; @Component public class Challenge5 extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CHALLENGE; - } + @Override + public Category getDefaultCategory() { + return Category.CHALLENGE; + } - @Override - public String getTitle() { - return "challenge5.title"; - } + @Override + public String getTitle() { + return "challenge5.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Assignment7.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Assignment7.java index fab634c08..30e17288c 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Assignment7.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Assignment7.java @@ -1,11 +1,15 @@ package org.owasp.webgoat.lessons.challenges.challenge7; +import java.net.URI; +import java.net.URISyntaxException; +import java.time.LocalDateTime; +import javax.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.owasp.webgoat.lessons.challenges.Email; -import org.owasp.webgoat.lessons.challenges.SolutionConstants; import org.owasp.webgoat.lessons.challenges.Flag; +import org.owasp.webgoat.lessons.challenges.SolutionConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; @@ -21,11 +25,6 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; -import javax.servlet.http.HttpServletRequest; -import java.net.URI; -import java.net.URISyntaxException; -import java.time.LocalDateTime; - /** * @author nbaars * @since 4/8/17. @@ -34,53 +33,67 @@ import java.time.LocalDateTime; @Slf4j public class Assignment7 extends AssignmentEndpoint { - private static final String TEMPLATE = "Hi, you requested a password reset link, please use this " - + "link to reset your password." - + "\n \n\n" - + "If you did not request this password change you can ignore this message." - + "\n" - + "If you have any comments or questions, please do not hesitate to reach us at support@webgoat-cloud.org" - + "\n\n" - + "Kind regards, \nTeam WebGoat"; + private static final String TEMPLATE = + "Hi, you requested a password reset link, please use this link to reset your" + + " password.\n" + + " \n\n" + + "If you did not request this password change you can ignore this message.\n" + + "If you have any comments or questions, please do not hesitate to reach us at" + + " support@webgoat-cloud.org\n\n" + + "Kind regards, \n" + + "Team WebGoat"; - @Autowired - private RestTemplate restTemplate; - @Value("${webwolf.mail.url}") - private String webWolfMailURL; + @Autowired private RestTemplate restTemplate; - @GetMapping("/challenge/7/reset-password/{link}") - public ResponseEntity resetPassword(@PathVariable(value = "link") String link) { - if (link.equals(SolutionConstants.ADMIN_PASSWORD_LINK)) { - return ResponseEntity.accepted().body("

Success!!

" - + "" - + "

Here is your flag: " + "" + Flag.FLAGS.get(7) + ""); - } - return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).body("That is not the reset link for admin"); + @Value("${webwolf.mail.url}") + private String webWolfMailURL; + + @GetMapping("/challenge/7/reset-password/{link}") + public ResponseEntity resetPassword(@PathVariable(value = "link") String link) { + if (link.equals(SolutionConstants.ADMIN_PASSWORD_LINK)) { + return ResponseEntity.accepted() + .body( + "

Success!!

" + + "" + + "

Here is your flag: " + + "" + + Flag.FLAGS.get(7) + + ""); } + return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT) + .body("That is not the reset link for admin"); + } - @PostMapping("/challenge/7") - @ResponseBody - public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request) throws URISyntaxException { - if (StringUtils.hasText(email)) { - String username = email.substring(0, email.indexOf("@")); - if (StringUtils.hasText(username)) { - URI uri = new URI(request.getRequestURL().toString()); - Email mail = Email.builder() - .title("Your password reset link for challenge 7") - .contents(String.format(TEMPLATE, uri.getScheme() + "://" + uri.getHost(), new PasswordResetLink().createPasswordReset(username, "webgoat"))) - .sender("password-reset@webgoat-cloud.net") - .recipient(username) - .time(LocalDateTime.now()).build(); - restTemplate.postForEntity(webWolfMailURL, mail, Object.class); - } - } - return success(this).feedback("email.send").feedbackArgs(email).build(); + @PostMapping("/challenge/7") + @ResponseBody + public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request) + throws URISyntaxException { + if (StringUtils.hasText(email)) { + String username = email.substring(0, email.indexOf("@")); + if (StringUtils.hasText(username)) { + URI uri = new URI(request.getRequestURL().toString()); + Email mail = + Email.builder() + .title("Your password reset link for challenge 7") + .contents( + String.format( + TEMPLATE, + uri.getScheme() + "://" + uri.getHost(), + new PasswordResetLink().createPasswordReset(username, "webgoat"))) + .sender("password-reset@webgoat-cloud.net") + .recipient(username) + .time(LocalDateTime.now()) + .build(); + restTemplate.postForEntity(webWolfMailURL, mail, Object.class); + } } + return success(this).feedback("email.send").feedbackArgs(email).build(); + } - @GetMapping(value = "/challenge/7/.git", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) - @ResponseBody - public ClassPathResource git() { - return new ClassPathResource("challenge7/git.zip"); - } + @GetMapping(value = "/challenge/7/.git", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + @ResponseBody + public ClassPathResource git() { + return new ClassPathResource("challenge7/git.zip"); + } } - diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Challenge7.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Challenge7.java index df621ac17..ee14c8325 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Challenge7.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/Challenge7.java @@ -11,13 +11,13 @@ import org.springframework.stereotype.Component; @Component public class Challenge7 extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CHALLENGE; - } + @Override + public Category getDefaultCategory() { + return Category.CHALLENGE; + } - @Override - public String getTitle() { - return "challenge7.title"; - } + @Override + public String getTitle() { + return "challenge7.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/MD5.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/MD5.java index 7b502c887..d523b6ba9 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/MD5.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/MD5.java @@ -7,21 +7,17 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; /** - * MD5 hash generator. - * More information about this class is available from ostermiller.org. - *

- * This class takes as input a message of arbitrary length and produces - * as output a 128-bit "fingerprint" or "message digest" of the input. - * It is conjectured that it is computationally infeasible to produce - * two messages having the same message digest, or to produce any - * message having a given pre-specified target message digest. The MD5 - * algorithm is intended for digital signature applications, where a - * large file must be "compressed" in a secure manner before being - * encrypted with a private (secret) key under a public-key cryptosystem - * such as RSA. - *

- * For more information see RFC1321. + * + *

This class takes as input a message of arbitrary length and produces as output a 128-bit + * "fingerprint" or "message digest" of the input. It is conjectured that it is computationally + * infeasible to produce two messages having the same message digest, or to produce any message + * having a given pre-specified target message digest. The MD5 algorithm is intended for digital + * signature applications, where a large file must be "compressed" in a secure manner before being + * encrypted with a private (secret) key under a public-key cryptosystem such as RSA. + * + *

For more information see RFC1321. * * @author Santeri Paavolainen http://santtu.iki.fi/md5/ * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities @@ -29,662 +25,701 @@ import java.io.UnsupportedEncodingException; */ public class MD5 { - /** - * Class constructor - * - * @since ostermillerutils 1.00.00 - */ - public MD5() { - reset(); - } + /** + * Class constructor + * + * @since ostermillerutils 1.00.00 + */ + public MD5() { + reset(); + } - /** - * Command line program that will take files as arguments - * and output the MD5 sum for each file. - * - * @param args command line arguments - * @since ostermillerutils 1.00.00 - */ - public static void main(String[] args) { - if (args.length == 0) { - System.err.println("Please specify a file."); - } else { - for (String element : args) { - try { - System.out.println(MD5.getHashString(new File(element)) + " " + element); - } catch (IOException x) { - System.err.println(x.getMessage()); - } - } + /** + * Command line program that will take files as arguments and output the MD5 sum for each file. + * + * @param args command line arguments + * @since ostermillerutils 1.00.00 + */ + public static void main(String[] args) { + if (args.length == 0) { + System.err.println("Please specify a file."); + } else { + for (String element : args) { + try { + System.out.println(MD5.getHashString(new File(element)) + " " + element); + } catch (IOException x) { + System.err.println(x.getMessage()); } + } + } + } + + /** + * Gets this hash sum as an array of 16 bytes. + * + * @return Array of 16 bytes, the hash of all updated bytes. + * @since ostermillerutils 1.00.00 + */ + public byte[] getHash() { + if (!finalState.valid) { + finalState.copy(workingState); + long bitCount = finalState.bitCount; + // Compute the number of left over bits + int leftOver = (int) (((bitCount >>> 3)) & 0x3f); + // Compute the amount of padding to add based on number of left over bits. + int padlen = (leftOver < 56) ? (56 - leftOver) : (120 - leftOver); + // add the padding + update(finalState, padding, 0, padlen); + // add the length (computed before padding was added) + update(finalState, encode(bitCount), 0, 8); + finalState.valid = true; + } + // make a copy of the hash before returning it. + return encode(finalState.state, 16); + } + + /** + * Returns 32-character hex representation of this hash. + * + * @return String representation of this object's hash. + * @since ostermillerutils 1.00.00 + */ + public String getHashString() { + return toHex(this.getHash()); + } + + /** + * Gets the MD5 hash of the given byte array. + * + * @param b byte array for which an MD5 hash is desired. + * @return Array of 16 bytes, the hash of all updated bytes. + * @since ostermillerutils 1.00.00 + */ + public static byte[] getHash(byte[] b) { + MD5 md5 = new MD5(); + md5.update(b); + return md5.getHash(); + } + + /** + * Gets the MD5 hash of the given byte array. + * + * @param b byte array for which an MD5 hash is desired. + * @return 32-character hex representation the data's MD5 hash. + * @since ostermillerutils 1.00.00 + */ + public static String getHashString(byte[] b) { + MD5 md5 = new MD5(); + md5.update(b); + return md5.getHashString(); + } + + /** + * Gets the MD5 hash the data on the given InputStream. + * + * @param in byte array for which an MD5 hash is desired. + * @return Array of 16 bytes, the hash of all updated bytes. + * @throws IOException if an I/O error occurs. + * @since ostermillerutils 1.00.00 + */ + public static byte[] getHash(InputStream in) throws IOException { + MD5 md5 = new MD5(); + byte[] buffer = new byte[1024]; + int read; + while ((read = in.read(buffer)) != -1) { + md5.update(buffer, read); + } + return md5.getHash(); + } + + /** + * Gets the MD5 hash the data on the given InputStream. + * + * @param in byte array for which an MD5 hash is desired. + * @return 32-character hex representation the data's MD5 hash. + * @throws IOException if an I/O error occurs. + * @since ostermillerutils 1.00.00 + */ + public static String getHashString(InputStream in) throws IOException { + MD5 md5 = new MD5(); + byte[] buffer = new byte[1024]; + int read; + while ((read = in.read(buffer)) != -1) { + md5.update(buffer, read); + } + return md5.getHashString(); + } + + /** + * Gets the MD5 hash of the given file. + * + * @param f file for which an MD5 hash is desired. + * @return Array of 16 bytes, the hash of all updated bytes. + * @throws IOException if an I/O error occurs. + * @since ostermillerutils 1.00.00 + */ + public static byte[] getHash(File f) throws IOException { + byte[] hash = null; + try (InputStream is = new FileInputStream(f)) { + hash = getHash(is); + } + return hash; + } + + /** + * Gets the MD5 hash of the given file. + * + * @param f file array for which an MD5 hash is desired. + * @return 32-character hex representation the data's MD5 hash. + * @throws IOException if an I/O error occurs. + * @since ostermillerutils 1.00.00 + */ + public static String getHashString(File f) throws IOException { + String hash = null; + try (InputStream is = new FileInputStream(f)) { + hash = getHashString(is); + } + return hash; + } + + /** + * Gets the MD5 hash of the given String. The string is converted to bytes using the current + * platform's default character encoding. + * + * @param s String for which an MD5 hash is desired. + * @return Array of 16 bytes, the hash of all updated bytes. + * @since ostermillerutils 1.00.00 + */ + public static byte[] getHash(String s) { + MD5 md5 = new MD5(); + md5.update(s); + return md5.getHash(); + } + + /** + * Gets the MD5 hash of the given String. The string is converted to bytes using the current + * platform's default character encoding. + * + * @param s String for which an MD5 hash is desired. + * @return 32-character hex representation the data's MD5 hash. + * @since ostermillerutils 1.00.00 + */ + public static String getHashString(String s) { + MD5 md5 = new MD5(); + md5.update(s); + return md5.getHashString(); + } + + /** + * Gets the MD5 hash of the given String. + * + * @param s String for which an MD5 hash is desired. + * @param enc The name of a supported character encoding. + * @return Array of 16 bytes, the hash of all updated bytes. + * @throws UnsupportedEncodingException If the named encoding is not supported. + * @since ostermillerutils 1.00.00 + */ + public static byte[] getHash(String s, String enc) throws UnsupportedEncodingException { + MD5 md5 = new MD5(); + md5.update(s, enc); + return md5.getHash(); + } + + /** + * Gets the MD5 hash of the given String. + * + * @param s String for which an MD5 hash is desired. + * @param enc The name of a supported character encoding. + * @return 32-character hex representation the data's MD5 hash. + * @throws UnsupportedEncodingException If the named encoding is not supported. + * @since ostermillerutils 1.00.00 + */ + public static String getHashString(String s, String enc) throws UnsupportedEncodingException { + MD5 md5 = new MD5(); + md5.update(s, enc); + return md5.getHashString(); + } + + /** + * Reset the MD5 sum to its initial state. + * + * @since ostermillerutils 1.00.00 + */ + public void reset() { + workingState.reset(); + finalState.valid = false; + } + + /** + * Returns 32-character hex representation of this hash. + * + * @return String representation of this object's hash. + * @since ostermillerutils 1.00.00 + */ + @Override + public String toString() { + return getHashString(); + } + + /** + * Update this hash with the given data. + * + *

A state may be passed into this method so that we can add padding and finalize a md5 hash + * without limiting our ability to update more data later. + * + *

If length bytes are not available to be hashed, as many bytes as possible will be hashed. + * + * @param state Which state is updated. + * @param buffer Array of bytes to be hashed. + * @param offset Offset to buffer array. + * @param length number of bytes to hash. + * @since ostermillerutils 1.00.00 + */ + private void update(MD5State state, byte buffer[], int offset, int length) { + + finalState.valid = false; + + // if length goes beyond the end of the buffer, cut it short. + if ((length + offset) > buffer.length) { + length = buffer.length - offset; } - /** - * Gets this hash sum as an array of 16 bytes. - * - * @return Array of 16 bytes, the hash of all updated bytes. - * @since ostermillerutils 1.00.00 - */ - public byte[] getHash() { - if (!finalState.valid) { - finalState.copy(workingState); - long bitCount = finalState.bitCount; - // Compute the number of left over bits - int leftOver = (int) (((bitCount >>> 3)) & 0x3f); - // Compute the amount of padding to add based on number of left over bits. - int padlen = (leftOver < 56) ? (56 - leftOver) : (120 - leftOver); - // add the padding - update(finalState, padding, 0, padlen); - // add the length (computed before padding was added) - update(finalState, encode(bitCount), 0, 8); - finalState.valid = true; - } - // make a copy of the hash before returning it. - return encode(finalState.state, 16); + // compute number of bytes mod 64 + // this is what we have sitting in a buffer + // that have not been hashed yet + int index = (int) (state.bitCount >>> 3) & 0x3f; + + // add the length to the count (translate bytes to bits) + state.bitCount += length << 3; + + int partlen = 64 - index; + + int i = 0; + if (length >= partlen) { + System.arraycopy(buffer, offset, state.buffer, index, partlen); + transform(state, decode(state.buffer, 64, 0)); + for (i = partlen; (i + 63) < length; i += 64) { + transform(state, decode(buffer, 64, i)); + } + index = 0; } - /** - * Returns 32-character hex representation of this hash. - * - * @return String representation of this object's hash. - * @since ostermillerutils 1.00.00 - */ - public String getHashString() { - return toHex(this.getHash()); + // buffer remaining input + if (i < length) { + for (int start = i; i < length; i++) { + state.buffer[index + i - start] = buffer[i + offset]; + } } + } + + /** + * Update this hash with the given data. + * + *

If length bytes are not available to be hashed, as many bytes as possible will be hashed. + * + * @param buffer Array of bytes to be hashed. + * @param offset Offset to buffer array. + * @param length number of bytes to hash. + * @since ostermillerutils 1.00.00 + */ + public void update(byte buffer[], int offset, int length) { + update(workingState, buffer, offset, length); + } + + /** + * Update this hash with the given data. + * + *

If length bytes are not available to be hashed, as many bytes as possible will be hashed. + * + * @param buffer Array of bytes to be hashed. + * @param length number of bytes to hash. + * @since ostermillerutils 1.00.00 + */ + public void update(byte buffer[], int length) { + update(buffer, 0, length); + } + + /** + * Update this hash with the given data. + * + * @param buffer Array of bytes to be hashed. + * @since ostermillerutils 1.00.00 + */ + public void update(byte buffer[]) { + update(buffer, 0, buffer.length); + } + + /** + * Updates this hash with a single byte. + * + * @param b byte to be hashed. + * @since ostermillerutils 1.00.00 + */ + public void update(byte b) { + byte buffer[] = new byte[1]; + buffer[0] = b; + update(buffer, 1); + } + + /** + * Update this hash with a String. The string is converted to bytes using the current platform's + * default character encoding. + * + * @param s String to be hashed. + * @since ostermillerutils 1.00.00 + */ + public void update(String s) { + update(s.getBytes()); + } + + /** + * Update this hash with a String. + * + * @param s String to be hashed. + * @param enc The name of a supported character encoding. + * @throws UnsupportedEncodingException If the named encoding is not supported. + * @since ostermillerutils 1.00.00 + */ + public void update(String s, String enc) throws UnsupportedEncodingException { + update(s.getBytes(enc)); + } + + /** + * The current state from which the hash sum can be computed or updated. + * + * @since ostermillerutils 1.00.00 + */ + private MD5State workingState = new MD5State(); + + /** + * Cached copy of the final MD5 hash sum. This is created when the hash is requested and it is + * invalidated when the hash is updated. + * + * @since ostermillerutils 1.00.00 + */ + private MD5State finalState = new MD5State(); + + /** + * Temporary buffer cached here for performance reasons. + * + * @since ostermillerutils 1.00.00 + */ + private int[] decodeBuffer = new int[16]; + + /** + * 64 bytes of padding that can be added if the length is not divisible by 64. + * + * @since ostermillerutils 1.00.00 + */ + private static final byte padding[] = { + (byte) 0x80, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }; + + /** + * Contains internal state of the MD5 class. Passes MD5 test suite as defined in RFC1321. + * + * @since ostermillerutils 1.00.00 + */ + private class MD5State { /** - * Gets the MD5 hash of the given byte array. - * - * @param b byte array for which an MD5 hash is desired. - * @return Array of 16 bytes, the hash of all updated bytes. - * @since ostermillerutils 1.00.00 - */ - public static byte[] getHash(byte[] b) { - MD5 md5 = new MD5(); - md5.update(b); - return md5.getHash(); - } - - /** - * Gets the MD5 hash of the given byte array. - * - * @param b byte array for which an MD5 hash is desired. - * @return 32-character hex representation the data's MD5 hash. - * @since ostermillerutils 1.00.00 - */ - public static String getHashString(byte[] b) { - MD5 md5 = new MD5(); - md5.update(b); - return md5.getHashString(); - } - - /** - * Gets the MD5 hash the data on the given InputStream. - * - * @param in byte array for which an MD5 hash is desired. - * @return Array of 16 bytes, the hash of all updated bytes. - * @throws IOException if an I/O error occurs. - * @since ostermillerutils 1.00.00 - */ - public static byte[] getHash(InputStream in) throws IOException { - MD5 md5 = new MD5(); - byte[] buffer = new byte[1024]; - int read; - while ((read = in.read(buffer)) != -1) { - md5.update(buffer, read); - } - return md5.getHash(); - } - - /** - * Gets the MD5 hash the data on the given InputStream. - * - * @param in byte array for which an MD5 hash is desired. - * @return 32-character hex representation the data's MD5 hash. - * @throws IOException if an I/O error occurs. - * @since ostermillerutils 1.00.00 - */ - public static String getHashString(InputStream in) throws IOException { - MD5 md5 = new MD5(); - byte[] buffer = new byte[1024]; - int read; - while ((read = in.read(buffer)) != -1) { - md5.update(buffer, read); - } - return md5.getHashString(); - } - - /** - * Gets the MD5 hash of the given file. - * - * @param f file for which an MD5 hash is desired. - * @return Array of 16 bytes, the hash of all updated bytes. - * @throws IOException if an I/O error occurs. - * @since ostermillerutils 1.00.00 - */ - public static byte[] getHash(File f) throws IOException { - byte[] hash = null; - try (InputStream is = new FileInputStream(f)) { - hash = getHash(is); - } - return hash; - } - - /** - * Gets the MD5 hash of the given file. - * - * @param f file array for which an MD5 hash is desired. - * @return 32-character hex representation the data's MD5 hash. - * @throws IOException if an I/O error occurs. - * @since ostermillerutils 1.00.00 - */ - public static String getHashString(File f) throws IOException { - String hash = null; - try (InputStream is = new FileInputStream(f)) { - hash = getHashString(is); - } - return hash; - } - - /** - * Gets the MD5 hash of the given String. - * The string is converted to bytes using the current - * platform's default character encoding. - * - * @param s String for which an MD5 hash is desired. - * @return Array of 16 bytes, the hash of all updated bytes. - * @since ostermillerutils 1.00.00 - */ - public static byte[] getHash(String s) { - MD5 md5 = new MD5(); - md5.update(s); - return md5.getHash(); - } - - /** - * Gets the MD5 hash of the given String. - * The string is converted to bytes using the current - * platform's default character encoding. - * - * @param s String for which an MD5 hash is desired. - * @return 32-character hex representation the data's MD5 hash. - * @since ostermillerutils 1.00.00 - */ - public static String getHashString(String s) { - MD5 md5 = new MD5(); - md5.update(s); - return md5.getHashString(); - } - - - /** - * Gets the MD5 hash of the given String. - * - * @param s String for which an MD5 hash is desired. - * @param enc The name of a supported character encoding. - * @return Array of 16 bytes, the hash of all updated bytes. - * @throws UnsupportedEncodingException If the named encoding is not supported. - * @since ostermillerutils 1.00.00 - */ - public static byte[] getHash(String s, String enc) throws UnsupportedEncodingException { - MD5 md5 = new MD5(); - md5.update(s, enc); - return md5.getHash(); - } - - /** - * Gets the MD5 hash of the given String. - * - * @param s String for which an MD5 hash is desired. - * @param enc The name of a supported character encoding. - * @return 32-character hex representation the data's MD5 hash. - * @throws UnsupportedEncodingException If the named encoding is not supported. - * @since ostermillerutils 1.00.00 - */ - public static String getHashString(String s, String enc) throws UnsupportedEncodingException { - MD5 md5 = new MD5(); - md5.update(s, enc); - return md5.getHashString(); - } - - - /** - * Reset the MD5 sum to its initial state. + * True if this state is valid. * * @since ostermillerutils 1.00.00 */ - public void reset() { - workingState.reset(); - finalState.valid = false; - } + private boolean valid = true; /** - * Returns 32-character hex representation of this hash. - * - * @return String representation of this object's hash. - * @since ostermillerutils 1.00.00 - */ - @Override - public String toString() { - return getHashString(); - } - - /** - * Update this hash with the given data. - *

- * A state may be passed into this method so that we can add padding - * and finalize a md5 hash without limiting our ability to update - * more data later. - *

- * If length bytes are not available to be hashed, as many bytes as - * possible will be hashed. - * - * @param state Which state is updated. - * @param buffer Array of bytes to be hashed. - * @param offset Offset to buffer array. - * @param length number of bytes to hash. - * @since ostermillerutils 1.00.00 - */ - private void update(MD5State state, byte buffer[], int offset, int length) { - - finalState.valid = false; - - // if length goes beyond the end of the buffer, cut it short. - if ((length + offset) > buffer.length) { - length = buffer.length - offset; - } - - // compute number of bytes mod 64 - // this is what we have sitting in a buffer - // that have not been hashed yet - int index = (int) (state.bitCount >>> 3) & 0x3f; - - // add the length to the count (translate bytes to bits) - state.bitCount += length << 3; - - int partlen = 64 - index; - - int i = 0; - if (length >= partlen) { - System.arraycopy(buffer, offset, state.buffer, index, partlen); - transform(state, decode(state.buffer, 64, 0)); - for (i = partlen; (i + 63) < length; i += 64) { - transform(state, decode(buffer, 64, i)); - } - index = 0; - } - - // buffer remaining input - if (i < length) { - for (int start = i; i < length; i++) { - state.buffer[index + i - start] = buffer[i + offset]; - } - } - } - - /** - * Update this hash with the given data. - *

- * If length bytes are not available to be hashed, as many bytes as - * possible will be hashed. - * - * @param buffer Array of bytes to be hashed. - * @param offset Offset to buffer array. - * @param length number of bytes to hash. - * @since ostermillerutils 1.00.00 - */ - public void update(byte buffer[], int offset, int length) { - update(workingState, buffer, offset, length); - } - - /** - * Update this hash with the given data. - *

- * If length bytes are not available to be hashed, as many bytes as - * possible will be hashed. - * - * @param buffer Array of bytes to be hashed. - * @param length number of bytes to hash. - * @since ostermillerutils 1.00.00 - */ - public void update(byte buffer[], int length) { - update(buffer, 0, length); - } - - /** - * Update this hash with the given data. - * - * @param buffer Array of bytes to be hashed. - * @since ostermillerutils 1.00.00 - */ - public void update(byte buffer[]) { - update(buffer, 0, buffer.length); - } - - /** - * Updates this hash with a single byte. - * - * @param b byte to be hashed. - * @since ostermillerutils 1.00.00 - */ - public void update(byte b) { - byte buffer[] = new byte[1]; - buffer[0] = b; - update(buffer, 1); - } - - /** - * Update this hash with a String. - * The string is converted to bytes using the current - * platform's default character encoding. - * - * @param s String to be hashed. - * @since ostermillerutils 1.00.00 - */ - public void update(String s) { - update(s.getBytes()); - } - - /** - * Update this hash with a String. - * - * @param s String to be hashed. - * @param enc The name of a supported character encoding. - * @throws UnsupportedEncodingException If the named encoding is not supported. - * @since ostermillerutils 1.00.00 - */ - public void update(String s, String enc) throws UnsupportedEncodingException { - update(s.getBytes(enc)); - } - - /** - * The current state from which the hash sum - * can be computed or updated. + * Reset to initial state. * * @since ostermillerutils 1.00.00 */ - private MD5State workingState = new MD5State(); + private void reset() { + state[0] = 0x67452301; + state[1] = 0xefcdab89; + state[2] = 0x98badcfe; + state[3] = 0x10325476; + + bitCount = 0; + } /** - * Cached copy of the final MD5 hash sum. This is created when - * the hash is requested and it is invalidated when the hash - * is updated. + * 128-byte state * * @since ostermillerutils 1.00.00 */ - private MD5State finalState = new MD5State(); + private int state[] = new int[4]; /** - * Temporary buffer cached here for performance reasons. + * 64-bit count of the number of bits that have been hashed. * * @since ostermillerutils 1.00.00 */ - private int[] decodeBuffer = new int[16]; + private long bitCount; /** - * 64 bytes of padding that can be added if the length - * is not divisible by 64. + * 64-byte buffer (512 bits) for storing to-be-hashed characters * * @since ostermillerutils 1.00.00 */ - private static final byte padding[] = { - (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - }; + private byte buffer[] = new byte[64]; + + private MD5State() { + reset(); + } /** - * Contains internal state of the MD5 class. - * Passes MD5 test suite as defined in RFC1321. + * Set this state to be exactly the same as some other. * + * @param from state to copy from. * @since ostermillerutils 1.00.00 */ - private class MD5State { - - /** - * True if this state is valid. - * - * @since ostermillerutils 1.00.00 - */ - private boolean valid = true; - - /** - * Reset to initial state. - * - * @since ostermillerutils 1.00.00 - */ - private void reset() { - state[0] = 0x67452301; - state[1] = 0xefcdab89; - state[2] = 0x98badcfe; - state[3] = 0x10325476; - - bitCount = 0; - } - - /** - * 128-byte state - * - * @since ostermillerutils 1.00.00 - */ - private int state[] = new int[4]; - - /** - * 64-bit count of the number of bits that have been hashed. - * - * @since ostermillerutils 1.00.00 - */ - private long bitCount; - - /** - * 64-byte buffer (512 bits) for storing to-be-hashed characters - * - * @since ostermillerutils 1.00.00 - */ - private byte buffer[] = new byte[64]; - - private MD5State() { - reset(); - } - - /** - * Set this state to be exactly the same as some other. - * - * @param from state to copy from. - * @since ostermillerutils 1.00.00 - */ - private void copy(MD5State from) { - System.arraycopy(from.buffer, 0, this.buffer, 0, this.buffer.length); - System.arraycopy(from.state, 0, this.state, 0, this.state.length); - this.valid = from.valid; - this.bitCount = from.bitCount; - } + private void copy(MD5State from) { + System.arraycopy(from.buffer, 0, this.buffer, 0, this.buffer.length); + System.arraycopy(from.state, 0, this.state, 0, this.state.length); + this.valid = from.valid; + this.bitCount = from.bitCount; } + } - - /** - * Turns array of bytes into string representing each byte as - * a two digit unsigned hex number. - * - * @param hash Array of bytes to convert to hex-string - * @return Generated hex string - * @since ostermillerutils 1.00.00 - */ - private static String toHex(byte hash[]) { - StringBuilder buf = new StringBuilder(hash.length * 2); - for (byte element : hash) { - int intVal = element & 0xff; - if (intVal < 0x10) { - // append a zero before a one digit hex - // number to make it two digits. - buf.append("0"); - } - buf.append(Integer.toHexString(intVal)); - } - return buf.toString(); + /** + * Turns array of bytes into string representing each byte as a two digit unsigned hex number. + * + * @param hash Array of bytes to convert to hex-string + * @return Generated hex string + * @since ostermillerutils 1.00.00 + */ + private static String toHex(byte hash[]) { + StringBuilder buf = new StringBuilder(hash.length * 2); + for (byte element : hash) { + int intVal = element & 0xff; + if (intVal < 0x10) { + // append a zero before a one digit hex + // number to make it two digits. + buf.append("0"); + } + buf.append(Integer.toHexString(intVal)); } + return buf.toString(); + } - private static int FF(int a, int b, int c, int d, int x, int s, int ac) { - a += ((b & c) | (~b & d)); - a += x; - a += ac; - //return rotateLeft(a, s) + b; - a = (a << s) | (a >>> (32 - s)); - return a + b; + private static int FF(int a, int b, int c, int d, int x, int s, int ac) { + a += ((b & c) | (~b & d)); + a += x; + a += ac; + // return rotateLeft(a, s) + b; + a = (a << s) | (a >>> (32 - s)); + return a + b; + } + + private static int GG(int a, int b, int c, int d, int x, int s, int ac) { + a += ((b & d) | (c & ~d)); + a += x; + a += ac; + // return rotateLeft(a, s) + b; + a = (a << s) | (a >>> (32 - s)); + return a + b; + } + + private static int HH(int a, int b, int c, int d, int x, int s, int ac) { + a += (b ^ c ^ d); + a += x; + a += ac; + // return rotateLeft(a, s) + b; + a = (a << s) | (a >>> (32 - s)); + return a + b; + } + + private static int II(int a, int b, int c, int d, int x, int s, int ac) { + a += (c ^ (b | ~d)); + a += x; + a += ac; + // return rotateLeft(a, s) + b; + a = (a << s) | (a >>> (32 - s)); + return a + b; + } + + private static byte[] encode(long l) { + byte[] out = new byte[8]; + out[0] = (byte) (l & 0xff); + out[1] = (byte) ((l >>> 8) & 0xff); + out[2] = (byte) ((l >>> 16) & 0xff); + out[3] = (byte) ((l >>> 24) & 0xff); + out[4] = (byte) ((l >>> 32) & 0xff); + out[5] = (byte) ((l >>> 40) & 0xff); + out[6] = (byte) ((l >>> 48) & 0xff); + out[7] = (byte) ((l >>> 56) & 0xff); + return out; + } + + private static byte[] encode(int input[], int len) { + byte[] out = new byte[len]; + int i, j; + for (i = j = 0; j < len; i++, j += 4) { + out[j] = (byte) (input[i] & 0xff); + out[j + 1] = (byte) ((input[i] >>> 8) & 0xff); + out[j + 2] = (byte) ((input[i] >>> 16) & 0xff); + out[j + 3] = (byte) ((input[i] >>> 24) & 0xff); } + return out; + } - private static int GG(int a, int b, int c, int d, int x, int s, int ac) { - a += ((b & d) | (c & ~d)); - a += x; - a += ac; - //return rotateLeft(a, s) + b; - a = (a << s) | (a >>> (32 - s)); - return a + b; + private int[] decode(byte buffer[], int len, int offset) { + int i, j; + for (i = j = 0; j < len; i++, j += 4) { + decodeBuffer[i] = + ((buffer[j + offset] & 0xff)) + | (((buffer[j + 1 + offset] & 0xff)) << 8) + | (((buffer[j + 2 + offset] & 0xff)) << 16) + | (((buffer[j + 3 + offset] & 0xff)) << 24); } + return decodeBuffer; + } - private static int HH(int a, int b, int c, int d, int x, int s, int ac) { - a += (b ^ c ^ d); - a += x; - a += ac; - //return rotateLeft(a, s) + b; - a = (a << s) | (a >>> (32 - s)); - return a + b; - } + private static void transform(MD5State state, int[] x) { + int a = state.state[0]; + int b = state.state[1]; + int c = state.state[2]; + int d = state.state[3]; - private static int II(int a, int b, int c, int d, int x, int s, int ac) { - a += (c ^ (b | ~d)); - a += x; - a += ac; - //return rotateLeft(a, s) + b; - a = (a << s) | (a >>> (32 - s)); - return a + b; - } + /* Round 1 */ + a = FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */ + d = FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */ + c = FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */ + b = FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */ + a = FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */ + d = FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */ + c = FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */ + b = FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */ + a = FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */ + d = FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */ + c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */ + b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */ + a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */ + d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */ + c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */ + b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */ - private static byte[] encode(long l) { - byte[] out = new byte[8]; - out[0] = (byte) (l & 0xff); - out[1] = (byte) ((l >>> 8) & 0xff); - out[2] = (byte) ((l >>> 16) & 0xff); - out[3] = (byte) ((l >>> 24) & 0xff); - out[4] = (byte) ((l >>> 32) & 0xff); - out[5] = (byte) ((l >>> 40) & 0xff); - out[6] = (byte) ((l >>> 48) & 0xff); - out[7] = (byte) ((l >>> 56) & 0xff); - return out; - } + /* Round 2 */ + a = GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */ + d = GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */ + c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */ + b = GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */ + a = GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */ + d = GG(d, a, b, c, x[10], 9, 0x02441453); /* 22 */ + c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */ + b = GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */ + a = GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */ + d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */ + c = GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */ + b = GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */ + a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */ + d = GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */ + c = GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */ + b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */ - private static byte[] encode(int input[], int len) { - byte[] out = new byte[len]; - int i, j; - for (i = j = 0; j < len; i++, j += 4) { - out[j] = (byte) (input[i] & 0xff); - out[j + 1] = (byte) ((input[i] >>> 8) & 0xff); - out[j + 2] = (byte) ((input[i] >>> 16) & 0xff); - out[j + 3] = (byte) ((input[i] >>> 24) & 0xff); - } - return out; - } + /* Round 3 */ + a = HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */ + d = HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */ + c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */ + b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */ + a = HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */ + d = HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */ + c = HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */ + b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */ + a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */ + d = HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */ + c = HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */ + b = HH(b, c, d, a, x[6], 23, 0x04881d05); /* 44 */ + a = HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */ + d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */ + c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */ + b = HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */ - private int[] decode(byte buffer[], int len, int offset) { - int i, j; - for (i = j = 0; j < len; i++, j += 4) { - decodeBuffer[i] = ( - (buffer[j + offset] & 0xff)) | - (((buffer[j + 1 + offset] & 0xff)) << 8) | - (((buffer[j + 2 + offset] & 0xff)) << 16) | - (((buffer[j + 3 + offset] & 0xff)) << 24 - ); - } - return decodeBuffer; - } + /* Round 4 */ + a = II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */ + d = II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */ + c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */ + b = II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */ + a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */ + d = II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */ + c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */ + b = II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */ + a = II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */ + d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */ + c = II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */ + b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */ + a = II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */ + d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */ + c = II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */ + b = II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */ - private static void transform(MD5State state, int[] x) { - int a = state.state[0]; - int b = state.state[1]; - int c = state.state[2]; - int d = state.state[3]; - - /* Round 1 */ - a = FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */ - d = FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */ - c = FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */ - b = FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */ - a = FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */ - d = FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */ - c = FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */ - b = FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */ - a = FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */ - d = FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */ - c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */ - b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */ - a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */ - d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */ - c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */ - b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */ - - /* Round 2 */ - a = GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */ - d = GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */ - c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */ - b = GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */ - a = GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */ - d = GG(d, a, b, c, x[10], 9, 0x02441453); /* 22 */ - c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */ - b = GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */ - a = GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */ - d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */ - c = GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */ - b = GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */ - a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */ - d = GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */ - c = GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */ - b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */ - - /* Round 3 */ - a = HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */ - d = HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */ - c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */ - b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */ - a = HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */ - d = HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */ - c = HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */ - b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */ - a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */ - d = HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */ - c = HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */ - b = HH(b, c, d, a, x[6], 23, 0x04881d05); /* 44 */ - a = HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */ - d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */ - c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */ - b = HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */ - - /* Round 4 */ - a = II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */ - d = II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */ - c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */ - b = II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */ - a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */ - d = II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */ - c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */ - b = II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */ - a = II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */ - d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */ - c = II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */ - b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */ - a = II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */ - d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */ - c = II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */ - b = II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */ - - state.state[0] += a; - state.state[1] += b; - state.state[2] += c; - state.state[3] += d; - } + state.state[0] += a; + state.state[1] += b; + state.state[2] += c; + state.state[3] += d; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/PasswordResetLink.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/PasswordResetLink.java index c890fc27c..ff00f06cb 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/PasswordResetLink.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge7/PasswordResetLink.java @@ -10,34 +10,36 @@ import java.util.Random; */ public class PasswordResetLink { - public String createPasswordReset(String username, String key) { - Random random = new Random(); - if (username.equalsIgnoreCase("admin")) { - //Admin has a fix reset link - random.setSeed(key.length()); - } - return scramble(random, scramble(random, scramble(random, MD5.getHashString(username)))); + public String createPasswordReset(String username, String key) { + Random random = new Random(); + if (username.equalsIgnoreCase("admin")) { + // Admin has a fix reset link + random.setSeed(key.length()); } + return scramble(random, scramble(random, scramble(random, MD5.getHashString(username)))); + } - public static String scramble(Random random, String inputString) { - char[] a = inputString.toCharArray(); - for (int i = 0; i < a.length; i++) { - int j = random.nextInt(a.length); - char temp = a[i]; - a[i] = a[j]; - a[j] = temp; - } - return new String(a); + public static String scramble(Random random, String inputString) { + char[] a = inputString.toCharArray(); + for (int i = 0; i < a.length; i++) { + int j = random.nextInt(a.length); + char temp = a[i]; + a[i] = a[j]; + a[j] = temp; } + return new String(a); + } - public static void main(String[] args) { - if (args == null || args.length != 2) { - System.out.println("Need a username and key"); - System.exit(1); - } - String username = args[0]; - String key = args[1]; - System.out.println("Generation password reset link for " + username); - System.out.println("Created password reset link: " + new PasswordResetLink().createPasswordReset(username, key)); + public static void main(String[] args) { + if (args == null || args.length != 2) { + System.out.println("Need a username and key"); + System.exit(1); } + String username = args[0]; + String key = args[1]; + System.out.println("Generation password reset link for " + username); + System.out.println( + "Created password reset link: " + + new PasswordResetLink().createPasswordReset(username, key)); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Assignment8.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Assignment8.java index e4f330899..535b92f18 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Assignment8.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Assignment8.java @@ -1,5 +1,9 @@ package org.owasp.webgoat.lessons.challenges.challenge8; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; @@ -11,11 +15,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - /** * @author nbaars * @since 4/8/17. @@ -24,46 +23,54 @@ import java.util.stream.Collectors; @Slf4j public class Assignment8 extends AssignmentEndpoint { - private static final Map votes = new HashMap<>(); + private static final Map votes = new HashMap<>(); - static { - votes.put(1, 400); - votes.put(2, 120); - votes.put(3, 140); - votes.put(4, 150); - votes.put(5, 300); - } + static { + votes.put(1, 400); + votes.put(2, 120); + votes.put(3, 140); + votes.put(4, 150); + votes.put(5, 300); + } - @GetMapping(value = "/challenge/8/vote/{stars}", produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public ResponseEntity vote(@PathVariable(value = "stars") int nrOfStars, HttpServletRequest request) { - //Simple implementation of VERB Based Authentication - String msg = ""; - if (request.getMethod().equals("GET")) { - var json = Map.of("error", true, "message", "Sorry but you need to login first in order to vote"); - return ResponseEntity.status(200).body(json); - } - Integer allVotesForStar = votes.getOrDefault(nrOfStars, 0); - votes.put(nrOfStars, allVotesForStar + 1); - return ResponseEntity.ok().header("X-Flag", "Thanks for voting, your flag is: " + Flag.FLAGS.get(8)).build(); + @GetMapping(value = "/challenge/8/vote/{stars}", produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public ResponseEntity vote( + @PathVariable(value = "stars") int nrOfStars, HttpServletRequest request) { + // Simple implementation of VERB Based Authentication + String msg = ""; + if (request.getMethod().equals("GET")) { + var json = + Map.of("error", true, "message", "Sorry but you need to login first in order to vote"); + return ResponseEntity.status(200).body(json); } + Integer allVotesForStar = votes.getOrDefault(nrOfStars, 0); + votes.put(nrOfStars, allVotesForStar + 1); + return ResponseEntity.ok() + .header("X-Flag", "Thanks for voting, your flag is: " + Flag.FLAGS.get(8)) + .build(); + } - @GetMapping("/challenge/8/votes/") - public ResponseEntity getVotes() { - return ResponseEntity.ok(votes.entrySet().stream().collect(Collectors.toMap(e -> "" + e.getKey(), e -> e.getValue()))); - } + @GetMapping("/challenge/8/votes/") + public ResponseEntity getVotes() { + return ResponseEntity.ok( + votes.entrySet().stream() + .collect(Collectors.toMap(e -> "" + e.getKey(), e -> e.getValue()))); + } - @GetMapping("/challenge/8/votes/average") - public ResponseEntity> average() { - int totalNumberOfVotes = votes.values().stream().mapToInt(i -> i.intValue()).sum(); - int categories = votes.entrySet().stream().mapToInt(e -> e.getKey() * e.getValue()).reduce(0, (a, b) -> a + b); - var json = Map.of("average", (int) Math.ceil((double) categories / totalNumberOfVotes)); - return ResponseEntity.ok(json); - } + @GetMapping("/challenge/8/votes/average") + public ResponseEntity> average() { + int totalNumberOfVotes = votes.values().stream().mapToInt(i -> i.intValue()).sum(); + int categories = + votes.entrySet().stream() + .mapToInt(e -> e.getKey() * e.getValue()) + .reduce(0, (a, b) -> a + b); + var json = Map.of("average", (int) Math.ceil((double) categories / totalNumberOfVotes)); + return ResponseEntity.ok(json); + } - @GetMapping("/challenge/8/notUsed") - public AttackResult notUsed() { - throw new IllegalStateException("Should never be called, challenge specific method"); - } + @GetMapping("/challenge/8/notUsed") + public AttackResult notUsed() { + throw new IllegalStateException("Should never be called, challenge specific method"); + } } - diff --git a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Challenge8.java b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Challenge8.java index bb0f9ac4e..c610a1bd9 100644 --- a/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Challenge8.java +++ b/src/main/java/org/owasp/webgoat/lessons/challenges/challenge8/Challenge8.java @@ -11,13 +11,13 @@ import org.springframework.stereotype.Component; @Component public class Challenge8 extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CHALLENGE; - } + @Override + public Category getDefaultCategory() { + return Category.CHALLENGE; + } - @Override - public String getTitle() { - return "challenge8.title"; - } + @Override + public String getTitle() { + return "challenge8.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/chromedevtools/ChromeDevTools.java b/src/main/java/org/owasp/webgoat/lessons/chromedevtools/ChromeDevTools.java index 8b5958c72..587761fc4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/chromedevtools/ChromeDevTools.java +++ b/src/main/java/org/owasp/webgoat/lessons/chromedevtools/ChromeDevTools.java @@ -33,13 +33,13 @@ import org.springframework.stereotype.Component; @Component public class ChromeDevTools extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.GENERAL; - } + @Override + public Category getDefaultCategory() { + return Category.GENERAL; + } - @Override - public String getTitle() { - return "3.chrome-dev-tools.title";//3rd lesson in General - } + @Override + public String getTitle() { + return "3.chrome-dev-tools.title"; // 3rd lesson in General + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/chromedevtools/NetworkDummy.java b/src/main/java/org/owasp/webgoat/lessons/chromedevtools/NetworkDummy.java index 78bdddbe2..97677e9a9 100644 --- a/src/main/java/org/owasp/webgoat/lessons/chromedevtools/NetworkDummy.java +++ b/src/main/java/org/owasp/webgoat/lessons/chromedevtools/NetworkDummy.java @@ -39,16 +39,16 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class NetworkDummy extends AssignmentEndpoint { - @PostMapping("/ChromeDevTools/dummy") - @ResponseBody - public AttackResult completed(@RequestParam String successMessage) { - UserSessionData userSessionData = getUserSessionData(); - String answer = (String) userSessionData.getValue("randValue"); + @PostMapping("/ChromeDevTools/dummy") + @ResponseBody + public AttackResult completed(@RequestParam String successMessage) { + UserSessionData userSessionData = getUserSessionData(); + String answer = (String) userSessionData.getValue("randValue"); - if (successMessage != null && successMessage.equals(answer)) { - return success(this).feedback("xss-dom-message-success").build(); - } else { - return failed(this).feedback("xss-dom-message-failure").build(); - } + if (successMessage != null && successMessage.equals(answer)) { + return success(this).feedback("xss-dom-message-success").build(); + } else { + return failed(this).feedback("xss-dom-message-failure").build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/chromedevtools/NetworkLesson.java b/src/main/java/org/owasp/webgoat/lessons/chromedevtools/NetworkLesson.java index ee7e87dcf..7441ab4a5 100644 --- a/src/main/java/org/owasp/webgoat/lessons/chromedevtools/NetworkLesson.java +++ b/src/main/java/org/owasp/webgoat/lessons/chromedevtools/NetworkLesson.java @@ -32,8 +32,8 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; /** - * Assignment where the user has to look through an HTTP Request - * using the Developer Tools and find a specific number. + * Assignment where the user has to look through an HTTP Request using the Developer Tools and find + * a specific number. * * @author TMelzer * @since 30.11.18 @@ -42,19 +42,21 @@ import org.springframework.web.bind.annotation.RestController; @AssignmentHints({"networkHint1", "networkHint2"}) public class NetworkLesson extends AssignmentEndpoint { - @PostMapping(value = "/ChromeDevTools/network", params = {"network_num", "number"}) - @ResponseBody - public AttackResult completed(@RequestParam String network_num, @RequestParam String number) { - if (network_num.equals(number)) { - return success(this).feedback("network.success").output("").build(); - } else { - return failed(this).feedback("network.failed").build(); - } + @PostMapping( + value = "/ChromeDevTools/network", + params = {"network_num", "number"}) + @ResponseBody + public AttackResult completed(@RequestParam String network_num, @RequestParam String number) { + if (network_num.equals(number)) { + return success(this).feedback("network.success").output("").build(); + } else { + return failed(this).feedback("network.failed").build(); } + } - @PostMapping(path = "/ChromeDevTools/network", params = "networkNum") - @ResponseBody - public ResponseEntity ok(@RequestParam String networkNum) { - return ResponseEntity.ok().build(); - } + @PostMapping(path = "/ChromeDevTools/network", params = "networkNum") + @ResponseBody + public ResponseEntity ok(@RequestParam String networkNum) { + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cia/CIA.java b/src/main/java/org/owasp/webgoat/lessons/cia/CIA.java index 03f5fd2bf..1754360b0 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cia/CIA.java +++ b/src/main/java/org/owasp/webgoat/lessons/cia/CIA.java @@ -11,13 +11,13 @@ import org.springframework.stereotype.Component; @Component public class CIA extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.GENERAL; - } + @Override + public Category getDefaultCategory() { + return Category.GENERAL; + } - @Override - public String getTitle() { - return "4.cia.title";//4th lesson in general - } + @Override + public String getTitle() { + return "4.cia.title"; // 4th lesson in general + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cia/CIAQuiz.java b/src/main/java/org/owasp/webgoat/lessons/cia/CIAQuiz.java index bc7a1b0a7..fa01b43e5 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cia/CIAQuiz.java +++ b/src/main/java/org/owasp/webgoat/lessons/cia/CIAQuiz.java @@ -11,38 +11,43 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class CIAQuiz extends AssignmentEndpoint { - String[] solutions = {"Solution 3", "Solution 1", "Solution 4", "Solution 2"}; - boolean[] guesses = new boolean[solutions.length]; + String[] solutions = {"Solution 3", "Solution 1", "Solution 4", "Solution 2"}; + boolean[] guesses = new boolean[solutions.length]; - @PostMapping("/cia/quiz") - @ResponseBody - public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution, @RequestParam String[] question_2_solution, @RequestParam String[] question_3_solution) { - int correctAnswers = 0; + @PostMapping("/cia/quiz") + @ResponseBody + public AttackResult completed( + @RequestParam String[] question_0_solution, + @RequestParam String[] question_1_solution, + @RequestParam String[] question_2_solution, + @RequestParam String[] question_3_solution) { + int correctAnswers = 0; - String[] givenAnswers = {question_0_solution[0], question_1_solution[0], question_2_solution[0], question_3_solution[0]}; + String[] givenAnswers = { + question_0_solution[0], question_1_solution[0], question_2_solution[0], question_3_solution[0] + }; - for (int i = 0; i < solutions.length; i++) { - if (givenAnswers[i].contains(solutions[i])) { - // answer correct - correctAnswers++; - guesses[i] = true; - } else { - // answer incorrect - guesses[i] = false; - } - } - - if (correctAnswers == solutions.length) { - return success(this).build(); - } else { - return failed(this).build(); - } + for (int i = 0; i < solutions.length; i++) { + if (givenAnswers[i].contains(solutions[i])) { + // answer correct + correctAnswers++; + guesses[i] = true; + } else { + // answer incorrect + guesses[i] = false; + } } - @GetMapping("/cia/quiz") - @ResponseBody - public boolean[] getResults() { - return this.guesses; + if (correctAnswers == solutions.length) { + return success(this).build(); + } else { + return failed(this).build(); } + } + @GetMapping("/cia/quiz") + @ResponseBody + public boolean[] getResults() { + return this.guesses; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFiltering.java b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFiltering.java index 219d29c52..31c0867be 100644 --- a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFiltering.java +++ b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFiltering.java @@ -8,25 +8,26 @@ import org.springframework.stereotype.Component; * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -36,13 +37,13 @@ import org.springframework.stereotype.Component; @Component public class ClientSideFiltering extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CLIENT_SIDE; - } + @Override + public Category getDefaultCategory() { + return Category.CLIENT_SIDE; + } - @Override - public String getTitle() { - return "client.side.filtering.title"; - } + @Override + public String getTitle() { + return "client.side.filtering.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringAssignment.java b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringAssignment.java index 2347697d5..fbe11da93 100644 --- a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringAssignment.java @@ -31,14 +31,19 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController -@AssignmentHints({"ClientSideFilteringHint1", "ClientSideFilteringHint2", "ClientSideFilteringHint3", "ClientSideFilteringHint4"}) +@AssignmentHints({ + "ClientSideFilteringHint1", + "ClientSideFilteringHint2", + "ClientSideFilteringHint3", + "ClientSideFilteringHint4" +}) public class ClientSideFilteringAssignment extends AssignmentEndpoint { - @PostMapping("/clientSideFiltering/attack1") - @ResponseBody - public AttackResult completed(@RequestParam String answer) { - return "450000".equals(answer) - ? success(this).feedback("assignment.solved").build() : - failed(this).feedback("ClientSideFiltering.incorrect").build(); - } + @PostMapping("/clientSideFiltering/attack1") + @ResponseBody + public AttackResult completed(@RequestParam String answer) { + return "450000".equals(answer) + ? success(this).feedback("assignment.solved").build() + : failed(this).feedback("ClientSideFiltering.incorrect").build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringFreeAssignment.java b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringFreeAssignment.java index aeb1ccb42..9db150279 100644 --- a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringFreeAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringFreeAssignment.java @@ -35,17 +35,21 @@ import org.springframework.web.bind.annotation.RestController; * @since 4/6/17. */ @RestController -@AssignmentHints({"client.side.filtering.free.hint1", "client.side.filtering.free.hint2", "client.side.filtering.free.hint3"}) +@AssignmentHints({ + "client.side.filtering.free.hint1", + "client.side.filtering.free.hint2", + "client.side.filtering.free.hint3" +}) public class ClientSideFilteringFreeAssignment extends AssignmentEndpoint { - public static final String SUPER_COUPON_CODE = "get_it_for_free"; + public static final String SUPER_COUPON_CODE = "get_it_for_free"; - @PostMapping("/clientSideFiltering/getItForFree") - @ResponseBody - public AttackResult completed(@RequestParam String checkoutCode) { - if (SUPER_COUPON_CODE.equals(checkoutCode)) { - return success(this).build(); - } - return failed(this).build(); + @PostMapping("/clientSideFiltering/getItForFree") + @ResponseBody + public AttackResult completed(@RequestParam String checkoutCode) { + if (SUPER_COUPON_CODE.equals(checkoutCode)) { + return success(this).build(); } + return failed(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/Salaries.java b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/Salaries.java index 0aa286103..bd4de62fc 100644 --- a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/Salaries.java +++ b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/Salaries.java @@ -22,6 +22,20 @@ package org.owasp.webgoat.lessons.clientsidefiltering; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.PostConstruct; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; @@ -33,79 +47,66 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; -import javax.annotation.PostConstruct; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - @RestController @Slf4j public class Salaries { - @Value("${webgoat.user.directory}") - private String webGoatHomeDirectory; + @Value("${webgoat.user.directory}") + private String webGoatHomeDirectory; - @PostConstruct - public void copyFiles() { - ClassPathResource classPathResource = new ClassPathResource("lessons/employees.xml"); - File targetDirectory = new File(webGoatHomeDirectory, "/ClientSideFiltering"); - if (!targetDirectory.exists()) { - targetDirectory.mkdir(); - } - try { - FileCopyUtils.copy(classPathResource.getInputStream(), new FileOutputStream(new File(targetDirectory, "employees.xml"))); - } catch (IOException e) { - throw new RuntimeException(e); - } + @PostConstruct + public void copyFiles() { + ClassPathResource classPathResource = new ClassPathResource("lessons/employees.xml"); + File targetDirectory = new File(webGoatHomeDirectory, "/ClientSideFiltering"); + if (!targetDirectory.exists()) { + targetDirectory.mkdir(); } - - @GetMapping("clientSideFiltering/salaries") - @ResponseBody - public List> invoke() { - NodeList nodes = null; - File d = new File(webGoatHomeDirectory, "ClientSideFiltering/employees.xml"); - XPathFactory factory = XPathFactory.newInstance(); - XPath path = factory.newXPath(); - int columns = 5; - List> json = new ArrayList<>(); - java.util.Map employeeJson = new HashMap<>(); - - try (InputStream is = new FileInputStream(d)) { - InputSource inputSource = new InputSource(is); - - StringBuilder sb = new StringBuilder(); - - sb.append("/Employees/Employee/UserID | "); - sb.append("/Employees/Employee/FirstName | "); - sb.append("/Employees/Employee/LastName | "); - sb.append("/Employees/Employee/SSN | "); - sb.append("/Employees/Employee/Salary "); - - String expression = sb.toString(); - nodes = (NodeList) path.evaluate(expression, inputSource, XPathConstants.NODESET); - for (int i = 0; i < nodes.getLength(); i++) { - if (i % columns == 0) { - employeeJson = new HashMap<>(); - json.add(employeeJson); - } - Node node = nodes.item(i); - employeeJson.put(node.getNodeName(), node.getTextContent()); - } - } catch (XPathExpressionException e) { - log.error("Unable to parse xml", e); - } catch (IOException e) { - log.error("Unable to read employees.xml at location: '{}'", d); - } - return json; + try { + FileCopyUtils.copy( + classPathResource.getInputStream(), + new FileOutputStream(new File(targetDirectory, "employees.xml"))); + } catch (IOException e) { + throw new RuntimeException(e); } + } + + @GetMapping("clientSideFiltering/salaries") + @ResponseBody + public List> invoke() { + NodeList nodes = null; + File d = new File(webGoatHomeDirectory, "ClientSideFiltering/employees.xml"); + XPathFactory factory = XPathFactory.newInstance(); + XPath path = factory.newXPath(); + int columns = 5; + List> json = new ArrayList<>(); + java.util.Map employeeJson = new HashMap<>(); + + try (InputStream is = new FileInputStream(d)) { + InputSource inputSource = new InputSource(is); + + StringBuilder sb = new StringBuilder(); + + sb.append("/Employees/Employee/UserID | "); + sb.append("/Employees/Employee/FirstName | "); + sb.append("/Employees/Employee/LastName | "); + sb.append("/Employees/Employee/SSN | "); + sb.append("/Employees/Employee/Salary "); + + String expression = sb.toString(); + nodes = (NodeList) path.evaluate(expression, inputSource, XPathConstants.NODESET); + for (int i = 0; i < nodes.getLength(); i++) { + if (i % columns == 0) { + employeeJson = new HashMap<>(); + json.add(employeeJson); + } + Node node = nodes.item(i); + employeeJson.put(node.getNodeName(), node.getTextContent()); + } + } catch (XPathExpressionException e) { + log.error("Unable to parse xml", e); + } catch (IOException e) { + log.error("Unable to read employees.xml at location: '{}'", d); + } + return json; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ShopEndpoint.java b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ShopEndpoint.java index f56d203b1..1a0f4fa92 100644 --- a/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ShopEndpoint.java +++ b/src/main/java/org/owasp/webgoat/lessons/clientsidefiltering/ShopEndpoint.java @@ -23,18 +23,16 @@ package org.owasp.webgoat.lessons.clientsidefiltering; import com.google.common.collect.Lists; +import java.util.List; +import java.util.Optional; import lombok.AllArgsConstructor; import lombok.Getter; - import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.List; -import java.util.Optional; - /** * @author nbaars * @since 4/6/17. @@ -43,47 +41,46 @@ import java.util.Optional; @RequestMapping("/clientSideFiltering/challenge-store") public class ShopEndpoint { - @AllArgsConstructor - private class CheckoutCodes { + @AllArgsConstructor + private class CheckoutCodes { - @Getter - private List codes; + @Getter private List codes; - public Optional get(String code) { - return codes.stream().filter(c -> c.getCode().equals(code)).findFirst(); - } + public Optional get(String code) { + return codes.stream().filter(c -> c.getCode().equals(code)).findFirst(); } + } - @AllArgsConstructor - @Getter - private class CheckoutCode { - private String code; - private int discount; + @AllArgsConstructor + @Getter + private class CheckoutCode { + private String code; + private int discount; + } + + private CheckoutCodes checkoutCodes; + + public ShopEndpoint() { + List codes = Lists.newArrayList(); + codes.add(new CheckoutCode("webgoat", 25)); + codes.add(new CheckoutCode("owasp", 25)); + codes.add(new CheckoutCode("owasp-webgoat", 50)); + this.checkoutCodes = new CheckoutCodes(codes); + } + + @GetMapping(value = "/coupons/{code}", produces = MediaType.APPLICATION_JSON_VALUE) + public CheckoutCode getDiscountCode(@PathVariable String code) { + if (ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE.equals(code)) { + return new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100); } + return checkoutCodes.get(code).orElse(new CheckoutCode("no", 0)); + } - private CheckoutCodes checkoutCodes; - - public ShopEndpoint() { - List codes = Lists.newArrayList(); - codes.add(new CheckoutCode("webgoat", 25)); - codes.add(new CheckoutCode("owasp", 25)); - codes.add(new CheckoutCode("owasp-webgoat", 50)); - this.checkoutCodes = new CheckoutCodes(codes); - } - - @GetMapping(value = "/coupons/{code}", produces = MediaType.APPLICATION_JSON_VALUE) - public CheckoutCode getDiscountCode(@PathVariable String code) { - if (ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE.equals(code)) { - return new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100); - } - return checkoutCodes.get(code).orElse(new CheckoutCode("no", 0)); - } - - @GetMapping(value = "/coupons", produces = MediaType.APPLICATION_JSON_VALUE) - public CheckoutCodes all() { - List all = Lists.newArrayList(); - all.addAll(this.checkoutCodes.getCodes()); - all.add(new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100)); - return new CheckoutCodes(all); - } + @GetMapping(value = "/coupons", produces = MediaType.APPLICATION_JSON_VALUE) + public CheckoutCodes all() { + List all = Lists.newArrayList(); + all.addAll(this.checkoutCodes.getCodes()); + all.add(new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100)); + return new CheckoutCodes(all); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cryptography/CryptoUtil.java b/src/main/java/org/owasp/webgoat/lessons/cryptography/CryptoUtil.java index d3bf9f2e4..6e13e57e3 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cryptography/CryptoUtil.java +++ b/src/main/java/org/owasp/webgoat/lessons/cryptography/CryptoUtil.java @@ -1,8 +1,5 @@ package org.owasp.webgoat.lessons.cryptography; -import lombok.extern.slf4j.Slf4j; - -import javax.xml.bind.DatatypeConverter; import java.math.BigInteger; import java.nio.charset.Charset; import java.security.InvalidAlgorithmParameterException; @@ -19,117 +16,128 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAKeyGenParameterSpec; import java.util.Base64; +import javax.xml.bind.DatatypeConverter; +import lombok.extern.slf4j.Slf4j; @Slf4j public class CryptoUtil { - private static final BigInteger[] FERMAT_PRIMES = - { BigInteger.valueOf(3), - BigInteger.valueOf(5), - BigInteger.valueOf(17), - BigInteger.valueOf(257), - BigInteger.valueOf(65537) }; + private static final BigInteger[] FERMAT_PRIMES = { + BigInteger.valueOf(3), + BigInteger.valueOf(5), + BigInteger.valueOf(17), + BigInteger.valueOf(257), + BigInteger.valueOf(65537) + }; - public static KeyPair generateKeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); - RSAKeyGenParameterSpec kpgSpec = new RSAKeyGenParameterSpec(2048, FERMAT_PRIMES[new SecureRandom().nextInt(FERMAT_PRIMES.length)]); - keyPairGenerator.initialize(kpgSpec); - //keyPairGenerator.initialize(2048); - return keyPairGenerator.generateKeyPair(); + public static KeyPair generateKeyPair() + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + RSAKeyGenParameterSpec kpgSpec = + new RSAKeyGenParameterSpec( + 2048, FERMAT_PRIMES[new SecureRandom().nextInt(FERMAT_PRIMES.length)]); + keyPairGenerator.initialize(kpgSpec); + // keyPairGenerator.initialize(2048); + return keyPairGenerator.generateKeyPair(); + } + + public static String getPrivateKeyInPEM(KeyPair keyPair) { + String encodedString = "-----BEGIN PRIVATE KEY-----\n"; + encodedString = + encodedString + + new String( + Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()), + Charset.forName("UTF-8")) + + "\n"; + encodedString = encodedString + "-----END PRIVATE KEY-----\n"; + return encodedString; + } + + public static String signMessage(String message, PrivateKey privateKey) { + + log.debug("start signMessage"); + String signature = null; + + try { + // Initiate signature verification + Signature instance = Signature.getInstance("SHA256withRSA"); + instance.initSign(privateKey); + instance.update(message.getBytes("UTF-8")); + + // actual verification against signature + signature = new String(Base64.getEncoder().encode(instance.sign()), Charset.forName("UTF-8")); + + log.info("signe the signature with result: {}", signature); + } catch (Exception e) { + log.error("Signature signing failed", e); } - public static String getPrivateKeyInPEM(KeyPair keyPair) { - String encodedString = "-----BEGIN PRIVATE KEY-----\n"; - encodedString = encodedString+new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()),Charset.forName("UTF-8"))+"\n"; - encodedString = encodedString+"-----END PRIVATE KEY-----\n"; - return encodedString; + log.debug("end signMessage"); + return signature; + } + + public static boolean verifyMessage( + String message, String base64EncSignature, PublicKey publicKey) { + + log.debug("start verifyMessage"); + boolean result = false; + + try { + + base64EncSignature = base64EncSignature.replace("\r", "").replace("\n", "").replace(" ", ""); + // get raw signature from base64 encrypted string in header + byte[] decodedSignature = Base64.getDecoder().decode(base64EncSignature); + + // Initiate signature verification + Signature instance = Signature.getInstance("SHA256withRSA"); + instance.initVerify(publicKey); + instance.update(message.getBytes("UTF-8")); + + // actual verification against signature + result = instance.verify(decodedSignature); + + log.info("Verified the signature with result: {}", result); + } catch (Exception e) { + log.error("Signature verification failed", e); } - public static String signMessage(String message, PrivateKey privateKey) { + log.debug("end verifyMessage"); + return result; + } - log.debug("start signMessage"); - String signature = null; - - try { - //Initiate signature verification - Signature instance = Signature.getInstance("SHA256withRSA"); - instance.initSign(privateKey); - instance.update(message.getBytes("UTF-8")); - - //actual verification against signature - signature = new String(Base64.getEncoder().encode(instance.sign()), Charset.forName("UTF-8")); + public static boolean verifyAssignment(String modulus, String signature, PublicKey publicKey) { - log.info("signe the signature with result: {}", signature); - } catch (Exception e) { - log.error("Signature signing failed", e); - } + /* first check if the signature is correct, i.e. right private key and right hash */ + boolean result = false; - log.debug("end signMessage"); - return signature; - } - - public static boolean verifyMessage(String message, String base64EncSignature, - PublicKey publicKey) { + if (modulus != null && signature != null) { + result = verifyMessage(modulus, signature, publicKey); - log.debug("start verifyMessage"); - boolean result = false; - - try { - - base64EncSignature = base64EncSignature.replace("\r", "").replace("\n", "") - .replace(" ", ""); - //get raw signature from base64 encrypted string in header - byte[] decodedSignature = Base64.getDecoder().decode(base64EncSignature); - - //Initiate signature verification - Signature instance = Signature.getInstance("SHA256withRSA"); - instance.initVerify(publicKey); - instance.update(message.getBytes("UTF-8")); - - //actual verification against signature - result = instance.verify(decodedSignature); + /* + * next check if the submitted modulus is the correct modulus of the public key + */ + RSAPublicKey rsaPubKey = (RSAPublicKey) publicKey; + if (modulus.length() == 512) { + modulus = "00".concat(modulus); + } + result = + result + && (DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()) + .equals(modulus.toUpperCase())); + } + return result; + } - log.info("Verified the signature with result: {}", result); - } catch (Exception e) { - log.error("Signature verification failed", e); - } + public static PrivateKey getPrivateKeyFromPEM(String privateKeyPem) + throws NoSuchAlgorithmException, InvalidKeySpecException { + privateKeyPem = privateKeyPem.replace("-----BEGIN PRIVATE KEY-----", ""); + privateKeyPem = privateKeyPem.replace("-----END PRIVATE KEY-----", ""); + privateKeyPem = privateKeyPem.replace("\n", "").replace("\r", ""); - log.debug("end verifyMessage"); - return result; - } - - public static boolean verifyAssignment(String modulus, String signature, PublicKey publicKey) { - - /* first check if the signature is correct, i.e. right private key and right hash */ - boolean result = false; - - if (modulus != null && signature != null) { - result = verifyMessage(modulus, signature, publicKey); - - /* - * next check if the submitted modulus is the correct modulus of the public key - */ - RSAPublicKey rsaPubKey = (RSAPublicKey) publicKey; - if (modulus.length()==512) { - modulus = "00".concat(modulus); - } - result = result && (DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()).equals(modulus.toUpperCase())); - } - return result; - - } - - public static PrivateKey getPrivateKeyFromPEM(String privateKeyPem) throws NoSuchAlgorithmException, InvalidKeySpecException { - privateKeyPem = privateKeyPem.replace("-----BEGIN PRIVATE KEY-----", ""); - privateKeyPem = privateKeyPem.replace("-----END PRIVATE KEY-----", ""); - privateKeyPem = privateKeyPem.replace("\n", "").replace("\r", ""); - - - byte [] decoded = Base64.getDecoder().decode(privateKeyPem); - - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded); - KeyFactory kf = KeyFactory.getInstance("RSA"); - return kf.generatePrivate(spec); - } + byte[] decoded = Base64.getDecoder().decode(privateKeyPem); + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded); + KeyFactory kf = KeyFactory.getInstance("RSA"); + return kf.generatePrivate(spec); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cryptography/Cryptography.java b/src/main/java/org/owasp/webgoat/lessons/cryptography/Cryptography.java index 6a805df21..5e00a3f5e 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cryptography/Cryptography.java +++ b/src/main/java/org/owasp/webgoat/lessons/cryptography/Cryptography.java @@ -28,14 +28,13 @@ import org.springframework.stereotype.Component; @Component public class Cryptography extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A2; - } - - @Override - public String getTitle() { - return "6.crypto.title";//first lesson in general - } + @Override + public Category getDefaultCategory() { + return Category.A2; + } + @Override + public String getTitle() { + return "6.crypto.title"; // first lesson in general + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cryptography/EncodingAssignment.java b/src/main/java/org/owasp/webgoat/lessons/cryptography/EncodingAssignment.java index 41d2d6421..65c115c41 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cryptography/EncodingAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/cryptography/EncodingAssignment.java @@ -22,6 +22,9 @@ package org.owasp.webgoat.lessons.cryptography; +import java.util.Base64; +import java.util.Random; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.http.MediaType; @@ -31,43 +34,42 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import java.util.Base64; -import java.util.Random; - @RestController public class EncodingAssignment extends AssignmentEndpoint { - public static String getBasicAuth(String username, String password) { - return Base64.getEncoder().encodeToString(username.concat(":").concat(password).getBytes()); + public static String getBasicAuth(String username, String password) { + return Base64.getEncoder().encodeToString(username.concat(":").concat(password).getBytes()); + } + + @GetMapping(path = "/crypto/encoding/basic", produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String getBasicAuth(HttpServletRequest request) { + + String basicAuth = (String) request.getSession().getAttribute("basicAuth"); + String username = request.getUserPrincipal().getName(); + if (basicAuth == null) { + String password = + HashingAssignment.SECRETS[new Random().nextInt(HashingAssignment.SECRETS.length)]; + basicAuth = getBasicAuth(username, password); + request.getSession().setAttribute("basicAuth", basicAuth); } - - @GetMapping(path="/crypto/encoding/basic",produces=MediaType.TEXT_HTML_VALUE) - @ResponseBody - public String getBasicAuth(HttpServletRequest request) { - - String basicAuth = (String) request.getSession().getAttribute("basicAuth"); - String username = request.getUserPrincipal().getName(); - if (basicAuth == null) { - String password = HashingAssignment.SECRETS[new Random().nextInt(HashingAssignment.SECRETS.length)]; - basicAuth = getBasicAuth(username, password); - request.getSession().setAttribute("basicAuth", basicAuth); - } - return "Authorization: Basic ".concat(basicAuth); - } - - @PostMapping("/crypto/encoding/basic-auth") - @ResponseBody - public AttackResult completed(HttpServletRequest request, @RequestParam String answer_user, @RequestParam String answer_pwd) { - String basicAuth = (String) request.getSession().getAttribute("basicAuth"); - if (basicAuth !=null && answer_user!=null && answer_pwd !=null - && basicAuth.equals(getBasicAuth(answer_user,answer_pwd))) - { - return success(this) - .feedback("crypto-encoding.success") - .build(); - } else { - return failed(this).feedback("crypto-encoding.empty").build(); - } + return "Authorization: Basic ".concat(basicAuth); + } + + @PostMapping("/crypto/encoding/basic-auth") + @ResponseBody + public AttackResult completed( + HttpServletRequest request, + @RequestParam String answer_user, + @RequestParam String answer_pwd) { + String basicAuth = (String) request.getSession().getAttribute("basicAuth"); + if (basicAuth != null + && answer_user != null + && answer_pwd != null + && basicAuth.equals(getBasicAuth(answer_user, answer_pwd))) { + return success(this).feedback("crypto-encoding.success").build(); + } else { + return failed(this).feedback("crypto-encoding.empty").build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cryptography/HashingAssignment.java b/src/main/java/org/owasp/webgoat/lessons/cryptography/HashingAssignment.java index 89cc05262..b83f931a8 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cryptography/HashingAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/cryptography/HashingAssignment.java @@ -22,6 +22,11 @@ package org.owasp.webgoat.lessons.cryptography; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Random; +import javax.servlet.http.HttpServletRequest; +import javax.xml.bind.DatatypeConverter; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -32,79 +37,69 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import javax.xml.bind.DatatypeConverter; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Random; - @RestController -@AssignmentHints({"crypto-hashing.hints.1","crypto-hashing.hints.2"}) +@AssignmentHints({"crypto-hashing.hints.1", "crypto-hashing.hints.2"}) public class HashingAssignment extends AssignmentEndpoint { - - public static final String[] SECRETS = {"secret","admin","password", "123456", "passw0rd"}; - @RequestMapping(path="/crypto/hashing/md5",produces=MediaType.TEXT_HTML_VALUE) - @ResponseBody - public String getMd5(HttpServletRequest request) throws NoSuchAlgorithmException { - - String md5Hash = (String) request.getSession().getAttribute("md5Hash"); - if (md5Hash == null) { - - String secret = SECRETS[new Random().nextInt(SECRETS.length)]; - - MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(secret.getBytes()); - byte[] digest = md.digest(); - md5Hash = DatatypeConverter - .printHexBinary(digest).toUpperCase(); - request.getSession().setAttribute("md5Hash", md5Hash); - request.getSession().setAttribute("md5Secret", secret); - } - return md5Hash; + public static final String[] SECRETS = {"secret", "admin", "password", "123456", "passw0rd"}; + + @RequestMapping(path = "/crypto/hashing/md5", produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String getMd5(HttpServletRequest request) throws NoSuchAlgorithmException { + + String md5Hash = (String) request.getSession().getAttribute("md5Hash"); + if (md5Hash == null) { + + String secret = SECRETS[new Random().nextInt(SECRETS.length)]; + + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(secret.getBytes()); + byte[] digest = md.digest(); + md5Hash = DatatypeConverter.printHexBinary(digest).toUpperCase(); + request.getSession().setAttribute("md5Hash", md5Hash); + request.getSession().setAttribute("md5Secret", secret); } - - @RequestMapping(path="/crypto/hashing/sha256",produces=MediaType.TEXT_HTML_VALUE) - @ResponseBody - public String getSha256(HttpServletRequest request) throws NoSuchAlgorithmException { - - String sha256 = (String) request.getSession().getAttribute("sha256"); - if (sha256 == null) { - String secret = SECRETS[new Random().nextInt(SECRETS.length)]; - sha256 = getHash(secret, "SHA-256"); - request.getSession().setAttribute("sha256Hash", sha256); - request.getSession().setAttribute("sha256Secret", secret); - } - return sha256; + return md5Hash; + } + + @RequestMapping(path = "/crypto/hashing/sha256", produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String getSha256(HttpServletRequest request) throws NoSuchAlgorithmException { + + String sha256 = (String) request.getSession().getAttribute("sha256"); + if (sha256 == null) { + String secret = SECRETS[new Random().nextInt(SECRETS.length)]; + sha256 = getHash(secret, "SHA-256"); + request.getSession().setAttribute("sha256Hash", sha256); + request.getSession().setAttribute("sha256Secret", secret); } - - @PostMapping("/crypto/hashing") - @ResponseBody - public AttackResult completed(HttpServletRequest request, @RequestParam String answer_pwd1, @RequestParam String answer_pwd2) { - - String md5Secret = (String) request.getSession().getAttribute("md5Secret"); - String sha256Secret = (String) request.getSession().getAttribute("sha256Secret"); - - if (answer_pwd1!=null && answer_pwd2 !=null) { - if (answer_pwd1.equals(md5Secret) - && answer_pwd2.equals(sha256Secret)) { - return success(this) - .feedback("crypto-hashing.success") - .build(); - } else if (answer_pwd1.equals(md5Secret) - || answer_pwd2.equals(sha256Secret)) { - return failed(this).feedback("crypto-hashing.oneok").build(); - } - } - return failed(this).feedback("crypto-hashing.empty").build(); + return sha256; + } + + @PostMapping("/crypto/hashing") + @ResponseBody + public AttackResult completed( + HttpServletRequest request, + @RequestParam String answer_pwd1, + @RequestParam String answer_pwd2) { + + String md5Secret = (String) request.getSession().getAttribute("md5Secret"); + String sha256Secret = (String) request.getSession().getAttribute("sha256Secret"); + + if (answer_pwd1 != null && answer_pwd2 != null) { + if (answer_pwd1.equals(md5Secret) && answer_pwd2.equals(sha256Secret)) { + return success(this).feedback("crypto-hashing.success").build(); + } else if (answer_pwd1.equals(md5Secret) || answer_pwd2.equals(sha256Secret)) { + return failed(this).feedback("crypto-hashing.oneok").build(); + } } - - public static String getHash(String secret, String algorithm) throws NoSuchAlgorithmException { - MessageDigest md = MessageDigest.getInstance(algorithm); - md.update(secret.getBytes()); - byte[] digest = md.digest(); - return DatatypeConverter - .printHexBinary(digest).toUpperCase(); - } - + return failed(this).feedback("crypto-hashing.empty").build(); + } + + public static String getHash(String secret, String algorithm) throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance(algorithm); + md.update(secret.getBytes()); + byte[] digest = md.digest(); + return DatatypeConverter.printHexBinary(digest).toUpperCase(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cryptography/SecureDefaultsAssignment.java b/src/main/java/org/owasp/webgoat/lessons/cryptography/SecureDefaultsAssignment.java index 90435e503..bb28f4202 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cryptography/SecureDefaultsAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/cryptography/SecureDefaultsAssignment.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.cryptography; +import java.security.NoSuchAlgorithmException; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -30,24 +31,29 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.security.NoSuchAlgorithmException; - @RestController -@AssignmentHints({"crypto-secure-defaults.hints.1", "crypto-secure-defaults.hints.2", "crypto-secure-defaults.hints.3"}) +@AssignmentHints({ + "crypto-secure-defaults.hints.1", + "crypto-secure-defaults.hints.2", + "crypto-secure-defaults.hints.3" +}) public class SecureDefaultsAssignment extends AssignmentEndpoint { - @PostMapping("/crypto/secure/defaults") - @ResponseBody - public AttackResult completed(@RequestParam String secretFileName, @RequestParam String secretText) throws NoSuchAlgorithmException { - if (secretFileName!=null && secretFileName.equals("default_secret")) { - if (secretText!=null && HashingAssignment.getHash(secretText, "SHA-256").equalsIgnoreCase("34de66e5caf2cb69ff2bebdc1f3091ecf6296852446c718e38ebfa60e4aa75d2")) { - return success(this) - .feedback("crypto-secure-defaults.success") - .build(); - } else { - return failed(this).feedback("crypto-secure-defaults.messagenotok").build(); - } - } - return failed(this).feedback("crypto-secure-defaults.notok").build(); + @PostMapping("/crypto/secure/defaults") + @ResponseBody + public AttackResult completed( + @RequestParam String secretFileName, @RequestParam String secretText) + throws NoSuchAlgorithmException { + if (secretFileName != null && secretFileName.equals("default_secret")) { + if (secretText != null + && HashingAssignment.getHash(secretText, "SHA-256") + .equalsIgnoreCase( + "34de66e5caf2cb69ff2bebdc1f3091ecf6296852446c718e38ebfa60e4aa75d2")) { + return success(this).feedback("crypto-secure-defaults.success").build(); + } else { + return failed(this).feedback("crypto-secure-defaults.messagenotok").build(); + } } + return failed(this).feedback("crypto-secure-defaults.notok").build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cryptography/SigningAssignment.java b/src/main/java/org/owasp/webgoat/lessons/cryptography/SigningAssignment.java index 40a910522..382ee3b16 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cryptography/SigningAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/cryptography/SigningAssignment.java @@ -22,6 +22,12 @@ package org.owasp.webgoat.lessons.cryptography; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPublicKey; +import javax.servlet.http.HttpServletRequest; +import javax.xml.bind.DatatypeConverter; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -33,54 +39,54 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import javax.xml.bind.DatatypeConverter; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.interfaces.RSAPublicKey; - @RestController -@AssignmentHints({"crypto-signing.hints.1","crypto-signing.hints.2", "crypto-signing.hints.3", "crypto-signing.hints.4"}) +@AssignmentHints({ + "crypto-signing.hints.1", + "crypto-signing.hints.2", + "crypto-signing.hints.3", + "crypto-signing.hints.4" +}) @Slf4j public class SigningAssignment extends AssignmentEndpoint { - - @RequestMapping(path="/crypto/signing/getprivate",produces=MediaType.TEXT_HTML_VALUE) - @ResponseBody - public String getPrivateKey(HttpServletRequest request) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { - - String privateKey = (String) request.getSession().getAttribute("privateKeyString"); - if (privateKey == null) { - KeyPair keyPair = CryptoUtil.generateKeyPair(); - privateKey = CryptoUtil.getPrivateKeyInPEM(keyPair); - request.getSession().setAttribute("privateKeyString", privateKey); - request.getSession().setAttribute("keyPair", keyPair); - } - return privateKey; + + @RequestMapping(path = "/crypto/signing/getprivate", produces = MediaType.TEXT_HTML_VALUE) + @ResponseBody + public String getPrivateKey(HttpServletRequest request) + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { + + String privateKey = (String) request.getSession().getAttribute("privateKeyString"); + if (privateKey == null) { + KeyPair keyPair = CryptoUtil.generateKeyPair(); + privateKey = CryptoUtil.getPrivateKeyInPEM(keyPair); + request.getSession().setAttribute("privateKeyString", privateKey); + request.getSession().setAttribute("keyPair", keyPair); } - - @PostMapping("/crypto/signing/verify") - @ResponseBody - public AttackResult completed(HttpServletRequest request, @RequestParam String modulus, @RequestParam String signature) { - - String tempModulus = modulus;/* used to validate the modulus of the public key but might need to be corrected */ - KeyPair keyPair = (KeyPair) request.getSession().getAttribute("keyPair"); - RSAPublicKey rsaPubKey = (RSAPublicKey) keyPair.getPublic(); - if (tempModulus.length() == 512) { - tempModulus = "00".concat(tempModulus); - } - if (!DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()).equals(tempModulus.toUpperCase())) { - log.warn("modulus {} incorrect", modulus); - return failed(this).feedback("crypto-signing.modulusnotok").build(); - } - /* orginal modulus must be used otherwise the signature would be invalid */ - if (CryptoUtil.verifyMessage(modulus, signature, keyPair.getPublic())) { - return success(this).feedback("crypto-signing.success").build(); - } else { - log.warn("signature incorrect"); - return failed(this).feedback("crypto-signing.notok").build(); - } - + return privateKey; + } + + @PostMapping("/crypto/signing/verify") + @ResponseBody + public AttackResult completed( + HttpServletRequest request, @RequestParam String modulus, @RequestParam String signature) { + + String tempModulus = + modulus; /* used to validate the modulus of the public key but might need to be corrected */ + KeyPair keyPair = (KeyPair) request.getSession().getAttribute("keyPair"); + RSAPublicKey rsaPubKey = (RSAPublicKey) keyPair.getPublic(); + if (tempModulus.length() == 512) { + tempModulus = "00".concat(tempModulus); } - + if (!DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()) + .equals(tempModulus.toUpperCase())) { + log.warn("modulus {} incorrect", modulus); + return failed(this).feedback("crypto-signing.modulusnotok").build(); + } + /* orginal modulus must be used otherwise the signature would be invalid */ + if (CryptoUtil.verifyMessage(modulus, signature, keyPair.getPublic())) { + return success(this).feedback("crypto-signing.success").build(); + } else { + log.warn("signature incorrect"); + return failed(this).feedback("crypto-signing.notok").build(); + } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/cryptography/XOREncodingAssignment.java b/src/main/java/org/owasp/webgoat/lessons/cryptography/XOREncodingAssignment.java index 68a8be8b5..d7e3ed94d 100644 --- a/src/main/java/org/owasp/webgoat/lessons/cryptography/XOREncodingAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/cryptography/XOREncodingAssignment.java @@ -34,14 +34,12 @@ import org.springframework.web.bind.annotation.RestController; @AssignmentHints({"crypto-encoding-xor.hints.1"}) public class XOREncodingAssignment extends AssignmentEndpoint { - @PostMapping("/crypto/encoding/xor") - @ResponseBody - public AttackResult completed(@RequestParam String answer_pwd1) { - if (answer_pwd1!=null && answer_pwd1.equals("databasepassword")) { - return success(this) - .feedback("crypto-encoding-xor.success") - .build(); - } - return failed(this).feedback("crypto-encoding-xor.empty").build(); + @PostMapping("/crypto/encoding/xor") + @ResponseBody + public AttackResult completed(@RequestParam String answer_pwd1) { + if (answer_pwd1 != null && answer_pwd1.equals("databasepassword")) { + return success(this).feedback("crypto-encoding-xor.success").build(); } + return failed(this).feedback("crypto-encoding-xor.empty").build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRF.java b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRF.java index 624797f66..73fa55bda 100644 --- a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRF.java +++ b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRF.java @@ -26,16 +26,16 @@ import org.owasp.webgoat.container.lessons.Category; import org.owasp.webgoat.container.lessons.Lesson; import org.springframework.stereotype.Component; -/** - * Created by jason on 9/29/17. - */ +/** Created by jason on 9/29/17. */ @Component public class CSRF extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A10; - } + @Override + public Category getDefaultCategory() { + return Category.A10; + } - @Override - public String getTitle() { return "csrf.title"; } + @Override + public String getTitle() { + return "csrf.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFConfirmFlag1.java b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFConfirmFlag1.java index ba012e56e..e4f52eb09 100644 --- a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFConfirmFlag1.java +++ b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFConfirmFlag1.java @@ -31,28 +31,26 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -/** - * Created by jason on 9/29/17. - */ - +/** Created by jason on 9/29/17. */ @RestController @AssignmentHints({"csrf-get.hint1", "csrf-get.hint2", "csrf-get.hint3", "csrf-get.hint4"}) public class CSRFConfirmFlag1 extends AssignmentEndpoint { - @Autowired - UserSessionData userSessionData; + @Autowired UserSessionData userSessionData; - @PostMapping(path = "/csrf/confirm-flag-1", produces = {"application/json"}) - @ResponseBody - public AttackResult completed(String confirmFlagVal) { - Object userSessionDataStr = userSessionData.getValue("csrf-get-success"); - if (userSessionDataStr != null && confirmFlagVal.equals(userSessionDataStr.toString())) { - return success(this) - .feedback("csrf-get-null-referer.success") - .output("Correct, the flag was " + userSessionData.getValue("csrf-get-success")) - .build(); - } - - return failed(this).build(); + @PostMapping( + path = "/csrf/confirm-flag-1", + produces = {"application/json"}) + @ResponseBody + public AttackResult completed(String confirmFlagVal) { + Object userSessionDataStr = userSessionData.getValue("csrf-get-success"); + if (userSessionDataStr != null && confirmFlagVal.equals(userSessionDataStr.toString())) { + return success(this) + .feedback("csrf-get-null-referer.success") + .output("Correct, the flag was " + userSessionData.getValue("csrf-get-success")) + .build(); } + + return failed(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFFeedback.java b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFFeedback.java index 3e5a0f109..a5387efd0 100644 --- a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFFeedback.java +++ b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFFeedback.java @@ -24,6 +24,11 @@ package org.owasp.webgoat.lessons.csrf; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.util.Map; +import java.util.UUID; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.exception.ExceptionUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -37,12 +42,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.util.Map; -import java.util.UUID; - /** * @author nbaars * @since 11/17/17. @@ -51,70 +50,72 @@ import java.util.UUID; @AssignmentHints({"csrf-feedback-hint1", "csrf-feedback-hint2", "csrf-feedback-hint3"}) public class CSRFFeedback extends AssignmentEndpoint { - @Autowired - private UserSessionData userSessionData; - @Autowired - private ObjectMapper objectMapper; + @Autowired private UserSessionData userSessionData; + @Autowired private ObjectMapper objectMapper; - @PostMapping(value = "/csrf/feedback/message", produces = {"application/json"}) - @ResponseBody - public AttackResult completed(HttpServletRequest request, @RequestBody String feedback) { - try { - objectMapper.enable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); - objectMapper.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); - objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS); - objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY); - objectMapper.enable(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES); - objectMapper.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS); - objectMapper.readValue(feedback.getBytes(), Map.class); - } catch (IOException e) { - return failed(this).feedback(ExceptionUtils.getStackTrace(e)).build(); - } - boolean correctCSRF = requestContainsWebGoatCookie(request.getCookies()) && request.getContentType().contains(MediaType.TEXT_PLAIN_VALUE); - correctCSRF &= hostOrRefererDifferentHost(request); - if (correctCSRF) { - String flag = UUID.randomUUID().toString(); - userSessionData.setValue("csrf-feedback", flag); - return success(this).feedback("csrf-feedback-success").feedbackArgs(flag).build(); - } - return failed(this).build(); + @PostMapping( + value = "/csrf/feedback/message", + produces = {"application/json"}) + @ResponseBody + public AttackResult completed(HttpServletRequest request, @RequestBody String feedback) { + try { + objectMapper.enable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); + objectMapper.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES); + objectMapper.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS); + objectMapper.enable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY); + objectMapper.enable(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES); + objectMapper.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS); + objectMapper.readValue(feedback.getBytes(), Map.class); + } catch (IOException e) { + return failed(this).feedback(ExceptionUtils.getStackTrace(e)).build(); } - - @PostMapping(path = "/csrf/feedback", produces = "application/json") - @ResponseBody - public AttackResult flag(@RequestParam("confirmFlagVal") String flag) { - if (flag.equals(userSessionData.getValue("csrf-feedback"))) { - return success(this).build(); - } else { - return failed(this).build(); - } + boolean correctCSRF = + requestContainsWebGoatCookie(request.getCookies()) + && request.getContentType().contains(MediaType.TEXT_PLAIN_VALUE); + correctCSRF &= hostOrRefererDifferentHost(request); + if (correctCSRF) { + String flag = UUID.randomUUID().toString(); + userSessionData.setValue("csrf-feedback", flag); + return success(this).feedback("csrf-feedback-success").feedbackArgs(flag).build(); } + return failed(this).build(); + } - private boolean hostOrRefererDifferentHost(HttpServletRequest request) { - String referer = request.getHeader("Referer"); - String host = request.getHeader("Host"); - if (referer != null) { - return !referer.contains(host); - } else { - return true; - } + @PostMapping(path = "/csrf/feedback", produces = "application/json") + @ResponseBody + public AttackResult flag(@RequestParam("confirmFlagVal") String flag) { + if (flag.equals(userSessionData.getValue("csrf-feedback"))) { + return success(this).build(); + } else { + return failed(this).build(); } + } - private boolean requestContainsWebGoatCookie(Cookie[] cookies) { - if (cookies != null) { - for (Cookie c : cookies) { - if (c.getName().equals("JSESSIONID")) { - return true; - } - } - } - return false; + private boolean hostOrRefererDifferentHost(HttpServletRequest request) { + String referer = request.getHeader("Referer"); + String host = request.getHeader("Host"); + if (referer != null) { + return !referer.contains(host); + } else { + return true; } + } - /** Solution -

- -
- - */ + private boolean requestContainsWebGoatCookie(Cookie[] cookies) { + if (cookies != null) { + for (Cookie c : cookies) { + if (c.getName().equals("JSESSIONID")) { + return true; + } + } + } + return false; + } + + /** + * Solution
+ */ } diff --git a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFGetFlag.java b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFGetFlag.java index 857df9997..e2cbc90c7 100644 --- a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFGetFlag.java +++ b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFGetFlag.java @@ -22,6 +22,10 @@ package org.owasp.webgoat.lessons.csrf; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.i18n.PluginMessages; import org.owasp.webgoat.container.session.UserSessionData; import org.springframework.beans.factory.annotation.Autowired; @@ -30,60 +34,52 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -/** - * Created by jason on 9/30/17. - */ +/** Created by jason on 9/30/17. */ @RestController public class CSRFGetFlag { - @Autowired - UserSessionData userSessionData; - @Autowired - private PluginMessages pluginMessages; + @Autowired UserSessionData userSessionData; + @Autowired private PluginMessages pluginMessages; - @RequestMapping(path = "/csrf/basic-get-flag", produces = {"application/json"}, method = RequestMethod.POST) - @ResponseBody - public Map invoke(HttpServletRequest req) { + @RequestMapping( + path = "/csrf/basic-get-flag", + produces = {"application/json"}, + method = RequestMethod.POST) + @ResponseBody + public Map invoke(HttpServletRequest req) { - Map response = new HashMap<>(); + Map response = new HashMap<>(); - String host = (req.getHeader("host") == null) ? "NULL" : req.getHeader("host"); - String referer = (req.getHeader("referer") == null) ? "NULL" : req.getHeader("referer"); - String[] refererArr = referer.split("/"); - - - if (referer.equals("NULL")) { - if ("true".equals(req.getParameter("csrf"))) { - Random random = new Random(); - userSessionData.setValue("csrf-get-success", random.nextInt(65536)); - response.put("success", true); - response.put("message", pluginMessages.getMessage("csrf-get-null-referer.success")); - response.put("flag", userSessionData.getValue("csrf-get-success")); - } else { - Random random = new Random(); - userSessionData.setValue("csrf-get-success", random.nextInt(65536)); - response.put("success", true); - response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success")); - response.put("flag", userSessionData.getValue("csrf-get-success")); - } - } else if (refererArr[2].equals(host)) { - response.put("success", false); - response.put("message", "Appears the request came from the original host"); - response.put("flag", null); - } else { - Random random = new Random(); - userSessionData.setValue("csrf-get-success", random.nextInt(65536)); - response.put("success", true); - response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success")); - response.put("flag", userSessionData.getValue("csrf-get-success")); - } - - return response; + String host = (req.getHeader("host") == null) ? "NULL" : req.getHeader("host"); + String referer = (req.getHeader("referer") == null) ? "NULL" : req.getHeader("referer"); + String[] refererArr = referer.split("/"); + if (referer.equals("NULL")) { + if ("true".equals(req.getParameter("csrf"))) { + Random random = new Random(); + userSessionData.setValue("csrf-get-success", random.nextInt(65536)); + response.put("success", true); + response.put("message", pluginMessages.getMessage("csrf-get-null-referer.success")); + response.put("flag", userSessionData.getValue("csrf-get-success")); + } else { + Random random = new Random(); + userSessionData.setValue("csrf-get-success", random.nextInt(65536)); + response.put("success", true); + response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success")); + response.put("flag", userSessionData.getValue("csrf-get-success")); + } + } else if (refererArr[2].equals(host)) { + response.put("success", false); + response.put("message", "Appears the request came from the original host"); + response.put("flag", null); + } else { + Random random = new Random(); + userSessionData.setValue("csrf-get-success", random.nextInt(65536)); + response.put("success", true); + response.put("message", pluginMessages.getMessage("csrf-get-other-referer.success")); + response.put("flag", userSessionData.getValue("csrf-get-success")); } + + return response; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFLogin.java b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFLogin.java index 238886b23..08d226245 100644 --- a/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFLogin.java +++ b/src/main/java/org/owasp/webgoat/lessons/csrf/CSRFLogin.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.csrf; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -31,8 +32,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; - /** * @author nbaars * @since 11/17/17. @@ -41,26 +40,29 @@ import javax.servlet.http.HttpServletRequest; @AssignmentHints({"csrf-login-hint1", "csrf-login-hint2", "csrf-login-hint3"}) public class CSRFLogin extends AssignmentEndpoint { - private final UserTrackerRepository userTrackerRepository; + private final UserTrackerRepository userTrackerRepository; - public CSRFLogin(UserTrackerRepository userTrackerRepository) { - this.userTrackerRepository = userTrackerRepository; - } + public CSRFLogin(UserTrackerRepository userTrackerRepository) { + this.userTrackerRepository = userTrackerRepository; + } - @PostMapping(path = "/csrf/login", produces = {"application/json"}) - @ResponseBody - public AttackResult completed(HttpServletRequest request) { - String userName = request.getUserPrincipal().getName(); - if (userName.startsWith("csrf")) { - markAssignmentSolvedWithRealUser(userName.substring("csrf-".length())); - return success(this).feedback("csrf-login-success").build(); - } - return failed(this).feedback("csrf-login-failed").feedbackArgs(userName).build(); + @PostMapping( + path = "/csrf/login", + produces = {"application/json"}) + @ResponseBody + public AttackResult completed(HttpServletRequest request) { + String userName = request.getUserPrincipal().getName(); + if (userName.startsWith("csrf")) { + markAssignmentSolvedWithRealUser(userName.substring("csrf-".length())); + return success(this).feedback("csrf-login-success").build(); } + return failed(this).feedback("csrf-login-failed").feedbackArgs(userName).build(); + } - private void markAssignmentSolvedWithRealUser(String username) { - UserTracker userTracker = userTrackerRepository.findByUser(username); - userTracker.assignmentSolved(getWebSession().getCurrentLesson(), this.getClass().getSimpleName()); - userTrackerRepository.save(userTracker); - } + private void markAssignmentSolvedWithRealUser(String username) { + UserTracker userTracker = userTrackerRepository.findByUser(username); + userTracker.assignmentSolved( + getWebSession().getCurrentLesson(), this.getClass().getSimpleName()); + userTrackerRepository.save(userTracker); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/csrf/ForgedReviews.java b/src/main/java/org/owasp/webgoat/lessons/csrf/ForgedReviews.java index b65691ac2..c11d43c5e 100644 --- a/src/main/java/org/owasp/webgoat/lessons/csrf/ForgedReviews.java +++ b/src/main/java/org/owasp/webgoat/lessons/csrf/ForgedReviews.java @@ -22,7 +22,17 @@ package org.owasp.webgoat.lessons.csrf; +import static org.springframework.http.MediaType.ALL_VALUE; + import com.google.common.collect.Lists; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -34,80 +44,75 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.springframework.http.MediaType.ALL_VALUE; - @RestController @AssignmentHints({"csrf-review-hint1", "csrf-review-hint2", "csrf-review-hint3"}) public class ForgedReviews extends AssignmentEndpoint { - @Autowired - private WebSession webSession; - private static DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd, HH:mm:ss"); + @Autowired private WebSession webSession; + private static DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd, HH:mm:ss"); - private static final Map> userReviews = new HashMap<>(); - private static final List REVIEWS = new ArrayList<>(); - private static final String weakAntiCSRF = "2aa14227b9a13d0bede0388a7fba9aa9"; + private static final Map> userReviews = new HashMap<>(); + private static final List REVIEWS = new ArrayList<>(); + private static final String weakAntiCSRF = "2aa14227b9a13d0bede0388a7fba9aa9"; + static { + REVIEWS.add( + new Review("secUriTy", LocalDateTime.now().format(fmt), "This is like swiss cheese", 0)); + REVIEWS.add(new Review("webgoat", LocalDateTime.now().format(fmt), "It works, sorta", 2)); + REVIEWS.add(new Review("guest", LocalDateTime.now().format(fmt), "Best, App, Ever", 5)); + REVIEWS.add( + new Review( + "guest", + LocalDateTime.now().format(fmt), + "This app is so insecure, I didn't even post this review, can you pull that off too?", + 1)); + } - static { - REVIEWS.add(new Review("secUriTy", LocalDateTime.now().format(fmt), "This is like swiss cheese", 0)); - REVIEWS.add(new Review("webgoat", LocalDateTime.now().format(fmt), "It works, sorta", 2)); - REVIEWS.add(new Review("guest", LocalDateTime.now().format(fmt), "Best, App, Ever", 5)); - REVIEWS.add(new Review("guest", LocalDateTime.now().format(fmt), "This app is so insecure, I didn't even post this review, can you pull that off too?", 1)); + @GetMapping( + path = "/csrf/review", + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = ALL_VALUE) + @ResponseBody + public Collection retrieveReviews() { + Collection allReviews = Lists.newArrayList(); + Collection newReviews = userReviews.get(webSession.getUserName()); + if (newReviews != null) { + allReviews.addAll(newReviews); } - @GetMapping(path = "/csrf/review", produces = MediaType.APPLICATION_JSON_VALUE, consumes = ALL_VALUE) - @ResponseBody - public Collection retrieveReviews() { - Collection allReviews = Lists.newArrayList(); - Collection newReviews = userReviews.get(webSession.getUserName()); - if (newReviews != null) { - allReviews.addAll(newReviews); - } + allReviews.addAll(REVIEWS); - allReviews.addAll(REVIEWS); + return allReviews; + } - return allReviews; + @PostMapping("/csrf/review") + @ResponseBody + public AttackResult createNewReview( + String reviewText, Integer stars, String validateReq, HttpServletRequest request) { + final String host = (request.getHeader("host") == null) ? "NULL" : request.getHeader("host"); + final String referer = + (request.getHeader("referer") == null) ? "NULL" : request.getHeader("referer"); + final String[] refererArr = referer.split("/"); + + Review review = new Review(); + review.setText(reviewText); + review.setDateTime(LocalDateTime.now().format(fmt)); + review.setUser(webSession.getUserName()); + review.setStars(stars); + var reviews = userReviews.getOrDefault(webSession.getUserName(), new ArrayList<>()); + reviews.add(review); + userReviews.put(webSession.getUserName(), reviews); + // short-circuit + if (validateReq == null || !validateReq.equals(weakAntiCSRF)) { + return failed(this).feedback("csrf-you-forgot-something").build(); } - - @PostMapping("/csrf/review") - @ResponseBody - public AttackResult createNewReview(String reviewText, Integer stars, String validateReq, HttpServletRequest request) { - final String host = (request.getHeader("host") == null) ? "NULL" : request.getHeader("host"); - final String referer = (request.getHeader("referer") == null) ? "NULL" : request.getHeader("referer"); - final String[] refererArr = referer.split("/"); - - Review review = new Review(); - review.setText(reviewText); - review.setDateTime(LocalDateTime.now().format(fmt)); - review.setUser(webSession.getUserName()); - review.setStars(stars); - var reviews = userReviews.getOrDefault(webSession.getUserName(), new ArrayList<>()); - reviews.add(review); - userReviews.put(webSession.getUserName(), reviews); - //short-circuit - if (validateReq == null || !validateReq.equals(weakAntiCSRF)) { - return failed(this).feedback("csrf-you-forgot-something").build(); - } - //we have the spoofed files - if (referer != "NULL" && refererArr[2].equals(host)) { - return failed(this).feedback("csrf-same-host").build(); - } else { - return success(this).feedback("csrf-review.success").build(); //feedback("xss-stored-comment-failure") - } + // we have the spoofed files + if (referer != "NULL" && refererArr[2].equals(host)) { + return failed(this).feedback("csrf-same-host").build(); + } else { + return success(this) + .feedback("csrf-review.success") + .build(); // feedback("xss-stored-comment-failure") } + } } - - - - - diff --git a/src/main/java/org/owasp/webgoat/lessons/csrf/Review.java b/src/main/java/org/owasp/webgoat/lessons/csrf/Review.java index 06e623791..0cb2a5ce1 100644 --- a/src/main/java/org/owasp/webgoat/lessons/csrf/Review.java +++ b/src/main/java/org/owasp/webgoat/lessons/csrf/Review.java @@ -22,13 +22,12 @@ package org.owasp.webgoat.lessons.csrf; +import javax.xml.bind.annotation.XmlRootElement; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import javax.xml.bind.annotation.XmlRootElement; - /** * @author nbaars * @since 4/8/17. @@ -39,9 +38,8 @@ import javax.xml.bind.annotation.XmlRootElement; @NoArgsConstructor @XmlRootElement public class Review { - private String user; - private String dateTime; - private String text; - private Integer stars; + private String user; + private String dateTime; + private String text; + private Integer stars; } - diff --git a/src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserialization.java b/src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserialization.java index 008fb90a2..39083406a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserialization.java +++ b/src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserialization.java @@ -8,25 +8,26 @@ import org.springframework.stereotype.Component; * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -35,13 +36,13 @@ import org.springframework.stereotype.Component; */ @Component public class InsecureDeserialization extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A8; - } + @Override + public Category getDefaultCategory() { + return Category.A8; + } - @Override - public String getTitle() { - return "insecure-deserialization.title"; - } + @Override + public String getTitle() { + return "insecure-deserialization.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserializationTask.java b/src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserializationTask.java index f207b45ef..d44823fdc 100644 --- a/src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserializationTask.java +++ b/src/main/java/org/owasp/webgoat/lessons/deserialization/InsecureDeserializationTask.java @@ -22,6 +22,11 @@ package org.owasp.webgoat.lessons.deserialization; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.util.Base64; import org.dummy.insecure.framework.VulnerableTaskHolder; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -31,51 +36,50 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InvalidClassException; -import java.io.ObjectInputStream; -import java.util.Base64; - @RestController -@AssignmentHints({"insecure-deserialization.hints.1", "insecure-deserialization.hints.2", "insecure-deserialization.hints.3"}) +@AssignmentHints({ + "insecure-deserialization.hints.1", + "insecure-deserialization.hints.2", + "insecure-deserialization.hints.3" +}) public class InsecureDeserializationTask extends AssignmentEndpoint { - @PostMapping("/InsecureDeserialization/task") - @ResponseBody - public AttackResult completed(@RequestParam String token) throws IOException { - String b64token; - long before; - long after; - int delay; + @PostMapping("/InsecureDeserialization/task") + @ResponseBody + public AttackResult completed(@RequestParam String token) throws IOException { + String b64token; + long before; + long after; + int delay; - b64token = token.replace('-', '+').replace('_', '/'); + b64token = token.replace('-', '+').replace('_', '/'); - try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(b64token)))) { - before = System.currentTimeMillis(); - Object o = ois.readObject(); - if (!(o instanceof VulnerableTaskHolder)) { - if (o instanceof String) { - return failed(this).feedback("insecure-deserialization.stringobject").build(); - } - return failed(this).feedback("insecure-deserialization.wrongobject").build(); - } - after = System.currentTimeMillis(); - } catch (InvalidClassException e) { - return failed(this).feedback("insecure-deserialization.invalidversion").build(); - } catch (IllegalArgumentException e) { - return failed(this).feedback("insecure-deserialization.expired").build(); - } catch (Exception e) { - return failed(this).feedback("insecure-deserialization.invalidversion").build(); + try (ObjectInputStream ois = + new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(b64token)))) { + before = System.currentTimeMillis(); + Object o = ois.readObject(); + if (!(o instanceof VulnerableTaskHolder)) { + if (o instanceof String) { + return failed(this).feedback("insecure-deserialization.stringobject").build(); } - - delay = (int) (after - before); - if (delay > 7000) { - return failed(this).build(); - } - if (delay < 3000) { - return failed(this).build(); - } - return success(this).build(); + return failed(this).feedback("insecure-deserialization.wrongobject").build(); + } + after = System.currentTimeMillis(); + } catch (InvalidClassException e) { + return failed(this).feedback("insecure-deserialization.invalidversion").build(); + } catch (IllegalArgumentException e) { + return failed(this).feedback("insecure-deserialization.expired").build(); + } catch (Exception e) { + return failed(this).feedback("insecure-deserialization.invalidversion").build(); } + + delay = (int) (after - before); + if (delay > 7000) { + return failed(this).build(); + } + if (delay < 3000) { + return failed(this).build(); + } + return success(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/deserialization/SerializationHelper.java b/src/main/java/org/owasp/webgoat/lessons/deserialization/SerializationHelper.java index f6ac82bb3..a8b55ab40 100644 --- a/src/main/java/org/owasp/webgoat/lessons/deserialization/SerializationHelper.java +++ b/src/main/java/org/owasp/webgoat/lessons/deserialization/SerializationHelper.java @@ -11,44 +11,41 @@ import java.util.Base64; public class SerializationHelper { - private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); - public static Object fromString(String s) throws IOException, - ClassNotFoundException { - byte[] data = Base64.getDecoder().decode(s); - ObjectInputStream ois = new ObjectInputStream( - new ByteArrayInputStream(data)); - Object o = ois.readObject(); - ois.close(); - return o; + public static Object fromString(String s) throws IOException, ClassNotFoundException { + byte[] data = Base64.getDecoder().decode(s); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data)); + Object o = ois.readObject(); + ois.close(); + return o; + } + + public static String toString(Serializable o) throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.close(); + return Base64.getEncoder().encodeToString(baos.toByteArray()); + } + + public static String show() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeLong(-8699352886133051976L); + dos.close(); + byte[] longBytes = baos.toByteArray(); + return bytesToHex(longBytes); + } + + public static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } - - public static String toString(Serializable o) throws IOException { - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(o); - oos.close(); - return Base64.getEncoder().encodeToString(baos.toByteArray()); - } - - public static String show() throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - DataOutputStream dos = new DataOutputStream(baos); - dos.writeLong(-8699352886133051976L); - dos.close(); - byte[] longBytes = baos.toByteArray(); - return bytesToHex(longBytes); - } - - public static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; - } - return new String(hexChars); - } - + return new String(hexChars); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/hijacksession/HijackSession.java b/src/main/java/org/owasp/webgoat/lessons/hijacksession/HijackSession.java index c233a1d23..c43ece76b 100644 --- a/src/main/java/org/owasp/webgoat/lessons/hijacksession/HijackSession.java +++ b/src/main/java/org/owasp/webgoat/lessons/hijacksession/HijackSession.java @@ -36,13 +36,13 @@ import org.springframework.stereotype.Component; @Component public class HijackSession extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A1; - } + @Override + public Category getDefaultCategory() { + return Category.A1; + } - @Override - public String getTitle() { - return "hijacksession.title"; - } + @Override + public String getTitle() { + return "hijacksession.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/hijacksession/HijackSessionAssignment.java b/src/main/java/org/owasp/webgoat/lessons/hijacksession/HijackSessionAssignment.java index bc18ca680..00416b964 100644 --- a/src/main/java/org/owasp/webgoat/lessons/hijacksession/HijackSessionAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/hijacksession/HijackSessionAssignment.java @@ -24,7 +24,6 @@ package org.owasp.webgoat.lessons.hijacksession; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; - import org.apache.commons.lang3.StringUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -46,47 +45,47 @@ import org.springframework.web.bind.annotation.RestController; @RestController @AssignmentHints({ - "hijacksession.hints.1", - "hijacksession.hints.2", - "hijacksession.hints.3", - "hijacksession.hints.4", - "hijacksession.hints.5" + "hijacksession.hints.1", + "hijacksession.hints.2", + "hijacksession.hints.3", + "hijacksession.hints.4", + "hijacksession.hints.5" }) public class HijackSessionAssignment extends AssignmentEndpoint { - private static final String COOKIE_NAME = "hijack_cookie"; + private static final String COOKIE_NAME = "hijack_cookie"; - @Autowired - HijackSessionAuthenticationProvider provider; + @Autowired HijackSessionAuthenticationProvider provider; - @PostMapping(path = "/HijackSession/login") - @ResponseBody - public AttackResult login( - @RequestParam String username, - @RequestParam String password, - @CookieValue(value = COOKIE_NAME, required = false) String cookieValue, - HttpServletResponse response) { + @PostMapping(path = "/HijackSession/login") + @ResponseBody + public AttackResult login( + @RequestParam String username, + @RequestParam String password, + @CookieValue(value = COOKIE_NAME, required = false) String cookieValue, + HttpServletResponse response) { - Authentication authentication; - if (StringUtils.isEmpty(cookieValue)) { - authentication = provider.authenticate(Authentication.builder().name(username).credentials(password).build()); - setCookie(response, authentication.getId()); - } else { - authentication = provider.authenticate(Authentication.builder().id(cookieValue).build()); - } - - if (authentication.isAuthenticated()) { - return success(this).build(); - } - - return failed(this).build(); + Authentication authentication; + if (StringUtils.isEmpty(cookieValue)) { + authentication = + provider.authenticate( + Authentication.builder().name(username).credentials(password).build()); + setCookie(response, authentication.getId()); + } else { + authentication = provider.authenticate(Authentication.builder().id(cookieValue).build()); } - private void setCookie(HttpServletResponse response, String cookieValue) { - Cookie cookie = new Cookie(COOKIE_NAME, cookieValue); - cookie.setPath("/WebGoat"); - cookie.setSecure(true); - response.addCookie(cookie); + if (authentication.isAuthenticated()) { + return success(this).build(); } + return failed(this).build(); + } + + private void setCookie(HttpServletResponse response, String cookieValue) { + Cookie cookie = new Cookie(COOKIE_NAME, cookieValue); + cookie.setPath("/WebGoat"); + cookie.setSecure(true); + response.addCookie(cookie); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/Authentication.java b/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/Authentication.java index 72bfae5ec..7931028a3 100644 --- a/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/Authentication.java +++ b/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/Authentication.java @@ -24,44 +24,39 @@ package org.owasp.webgoat.lessons.hijacksession.cas; import java.security.Principal; - import lombok.Builder; import lombok.Getter; import lombok.ToString; /** - * * @author Angel Olle Blazquez - * */ - @Getter @ToString public class Authentication implements Principal { - private boolean authenticated = false; - private String name; - private Object credentials; - private String id; + private boolean authenticated = false; + private String name; + private Object credentials; + private String id; - @Builder - public Authentication(String name, Object credentials, String id) { - this.name = name; - this.credentials = credentials; - this.id = id; - } + @Builder + public Authentication(String name, Object credentials, String id) { + this.name = name; + this.credentials = credentials; + this.id = id; + } - @Override - public String getName() { - return name; - } + @Override + public String getName() { + return name; + } - protected void setAuthenticated(boolean authenticated) { - this.authenticated = authenticated; - } - - protected void setId(String id) { - this.id = id; - } + protected void setAuthenticated(boolean authenticated) { + this.authenticated = authenticated; + } + protected void setId(String id) { + this.id = id; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/AuthenticationProvider.java b/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/AuthenticationProvider.java index 9d5447296..55af2c53c 100644 --- a/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/AuthenticationProvider.java +++ b/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/AuthenticationProvider.java @@ -26,14 +26,10 @@ package org.owasp.webgoat.lessons.hijacksession.cas; import java.security.Principal; /** - * * @author Angel Olle Blazquez - * */ - @FunctionalInterface public interface AuthenticationProvider { - T authenticate(T t); - + T authenticate(T t); } diff --git a/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/HijackSessionAuthenticationProvider.java b/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/HijackSessionAuthenticationProvider.java index b59720bfc..018dd8bf1 100644 --- a/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/HijackSessionAuthenticationProvider.java +++ b/src/main/java/org/owasp/webgoat/lessons/hijacksession/cas/HijackSessionAuthenticationProvider.java @@ -30,15 +30,12 @@ import java.util.Random; import java.util.concurrent.ThreadLocalRandom; import java.util.function.DoublePredicate; import java.util.function.Supplier; - import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.web.context.annotation.ApplicationScope; /** - * * @author Angel Olle Blazquez - * */ // weak id value and mechanism @@ -47,54 +44,53 @@ import org.springframework.web.context.annotation.ApplicationScope; @Component public class HijackSessionAuthenticationProvider implements AuthenticationProvider { - private Queue sessions = new LinkedList<>(); - private static long id = new Random().nextLong() & Long.MAX_VALUE; - protected static final int MAX_SESSIONS = 50; + private Queue sessions = new LinkedList<>(); + private static long id = new Random().nextLong() & Long.MAX_VALUE; + protected static final int MAX_SESSIONS = 50; - private static final DoublePredicate PROBABILITY_DOUBLE_PREDICATE = pr -> pr < 0.75; - private static final Supplier GENERATE_SESSION_ID = () -> ++id + "-" + Instant.now().toEpochMilli(); - public static final Supplier AUTHENTICATION_SUPPLIER = () -> Authentication - .builder() - .id(GENERATE_SESSION_ID.get()) - .build(); + private static final DoublePredicate PROBABILITY_DOUBLE_PREDICATE = pr -> pr < 0.75; + private static final Supplier GENERATE_SESSION_ID = + () -> ++id + "-" + Instant.now().toEpochMilli(); + public static final Supplier AUTHENTICATION_SUPPLIER = + () -> Authentication.builder().id(GENERATE_SESSION_ID.get()).build(); - @Override - public Authentication authenticate(Authentication authentication) { - if (authentication == null) { - return AUTHENTICATION_SUPPLIER.get(); - } - - if (StringUtils.isNotEmpty(authentication.getId()) && sessions.contains(authentication.getId())) { - authentication.setAuthenticated(true); - return authentication; - } - - if (StringUtils.isEmpty(authentication.getId())) { - authentication.setId(GENERATE_SESSION_ID.get()); - } - - authorizedUserAutoLogin(); - - return authentication; + @Override + public Authentication authenticate(Authentication authentication) { + if (authentication == null) { + return AUTHENTICATION_SUPPLIER.get(); } - protected void authorizedUserAutoLogin() { - if (!PROBABILITY_DOUBLE_PREDICATE.test(ThreadLocalRandom.current().nextDouble())) { - Authentication authentication = AUTHENTICATION_SUPPLIER.get(); - authentication.setAuthenticated(true); - addSession(authentication.getId()); - } + if (StringUtils.isNotEmpty(authentication.getId()) + && sessions.contains(authentication.getId())) { + authentication.setAuthenticated(true); + return authentication; } - protected boolean addSession(String sessionId) { - if (sessions.size() >= MAX_SESSIONS) { - sessions.remove(); - } - return sessions.add(sessionId); + if (StringUtils.isEmpty(authentication.getId())) { + authentication.setId(GENERATE_SESSION_ID.get()); } - protected int getSessionsSize() { - return sessions.size(); - } + authorizedUserAutoLogin(); + return authentication; + } + + protected void authorizedUserAutoLogin() { + if (!PROBABILITY_DOUBLE_PREDICATE.test(ThreadLocalRandom.current().nextDouble())) { + Authentication authentication = AUTHENTICATION_SUPPLIER.get(); + authentication.setAuthenticated(true); + addSession(authentication.getId()); + } + } + + protected boolean addSession(String sessionId) { + if (sessions.size() >= MAX_SESSIONS) { + sessions.remove(); + } + return sessions.add(sessionId); + } + + protected int getSessionsSize() { + return sessions.size(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/htmltampering/HtmlTampering.java b/src/main/java/org/owasp/webgoat/lessons/htmltampering/HtmlTampering.java index 6c63c6cc1..0302c0b4f 100644 --- a/src/main/java/org/owasp/webgoat/lessons/htmltampering/HtmlTampering.java +++ b/src/main/java/org/owasp/webgoat/lessons/htmltampering/HtmlTampering.java @@ -8,25 +8,26 @@ import org.springframework.stereotype.Component; * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -35,13 +36,13 @@ import org.springframework.stereotype.Component; */ @Component public class HtmlTampering extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CLIENT_SIDE; - } + @Override + public Category getDefaultCategory() { + return Category.CLIENT_SIDE; + } - @Override - public String getTitle() { - return "html-tampering.title"; - } + @Override + public String getTitle() { + return "html-tampering.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/htmltampering/HtmlTamperingTask.java b/src/main/java/org/owasp/webgoat/lessons/htmltampering/HtmlTamperingTask.java index c34d3c69b..8a0ba7103 100644 --- a/src/main/java/org/owasp/webgoat/lessons/htmltampering/HtmlTamperingTask.java +++ b/src/main/java/org/owasp/webgoat/lessons/htmltampering/HtmlTamperingTask.java @@ -34,12 +34,12 @@ import org.springframework.web.bind.annotation.RestController; @AssignmentHints({"hint1", "hint2", "hint3"}) public class HtmlTamperingTask extends AssignmentEndpoint { - @PostMapping("/HtmlTampering/task") - @ResponseBody - public AttackResult completed(@RequestParam String QTY, @RequestParam String Total) { - if (Float.parseFloat(QTY) * 2999.99 > Float.parseFloat(Total) + 1) { - return success(this).feedback("html-tampering.tamper.success").build(); - } - return failed(this).feedback("html-tampering.tamper.failure").build(); + @PostMapping("/HtmlTampering/task") + @ResponseBody + public AttackResult completed(@RequestParam String QTY, @RequestParam String Total) { + if (Float.parseFloat(QTY) * 2999.99 > Float.parseFloat(Total) + 1) { + return success(this).feedback("html-tampering.tamper.success").build(); } + return failed(this).feedback("html-tampering.tamper.failure").build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasics.java b/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasics.java index eaecf1839..d70aaebb4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasics.java +++ b/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasics.java @@ -28,13 +28,13 @@ import org.springframework.stereotype.Component; @Component public class HttpBasics extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.GENERAL; - } + @Override + public Category getDefaultCategory() { + return Category.GENERAL; + } - @Override - public String getTitle() { - return "1.http-basics.title";//first lesson in general - } + @Override + public String getTitle() { + return "1.http-basics.title"; // first lesson in general + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasicsLesson.java b/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasicsLesson.java index af7e80416..883f14f31 100644 --- a/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasicsLesson.java +++ b/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasicsLesson.java @@ -34,16 +34,16 @@ import org.springframework.web.bind.annotation.RestController; @AssignmentHints({"http-basics.hints.http_basics_lesson.1"}) public class HttpBasicsLesson extends AssignmentEndpoint { - @PostMapping("/HttpBasics/attack1") - @ResponseBody - public AttackResult completed(@RequestParam String person) { - if (!person.isBlank()) { - return success(this) - .feedback("http-basics.reversed") - .feedbackArgs(new StringBuilder(person).reverse().toString()) - .build(); - } else { - return failed(this).feedback("http-basics.empty").build(); - } + @PostMapping("/HttpBasics/attack1") + @ResponseBody + public AttackResult completed(@RequestParam String person) { + if (!person.isBlank()) { + return success(this) + .feedback("http-basics.reversed") + .feedbackArgs(new StringBuilder(person).reverse().toString()) + .build(); + } else { + return failed(this).feedback("http-basics.empty").build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasicsQuiz.java b/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasicsQuiz.java index ae9bcebce..c6c14ad73 100644 --- a/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasicsQuiz.java +++ b/src/main/java/org/owasp/webgoat/lessons/httpbasics/HttpBasicsQuiz.java @@ -36,19 +36,22 @@ import org.springframework.web.bind.annotation.RestController; @AssignmentPath("HttpBasics/attack2") public class HttpBasicsQuiz extends AssignmentEndpoint { - @PostMapping("/HttpBasics/attack2") - @ResponseBody - public AttackResult completed(@RequestParam String answer, @RequestParam String magic_answer, @RequestParam String magic_num) { - if ("POST".equalsIgnoreCase(answer) && magic_answer.equals(magic_num)) { - return success(this).build(); - } else { - if (!"POST".equalsIgnoreCase(answer)) { - return failed(this).feedback("http-basics.incorrect").build(); - } - if (!magic_answer.equals(magic_num)) { - return failed(this).feedback("http-basics.magic").build(); - } - } - return failed(this).build(); + @PostMapping("/HttpBasics/attack2") + @ResponseBody + public AttackResult completed( + @RequestParam String answer, + @RequestParam String magic_answer, + @RequestParam String magic_num) { + if ("POST".equalsIgnoreCase(answer) && magic_answer.equals(magic_num)) { + return success(this).build(); + } else { + if (!"POST".equalsIgnoreCase(answer)) { + return failed(this).feedback("http-basics.incorrect").build(); + } + if (!magic_answer.equals(magic_num)) { + return failed(this).feedback("http-basics.magic").build(); + } } + return failed(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/httpproxies/HttpBasicsInterceptRequest.java b/src/main/java/org/owasp/webgoat/lessons/httpproxies/HttpBasicsInterceptRequest.java index 0550018a7..b3ad85e95 100644 --- a/src/main/java/org/owasp/webgoat/lessons/httpproxies/HttpBasicsInterceptRequest.java +++ b/src/main/java/org/owasp/webgoat/lessons/httpproxies/HttpBasicsInterceptRequest.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.httpproxies; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.http.HttpMethod; @@ -32,22 +33,27 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; - @RestController public class HttpBasicsInterceptRequest extends AssignmentEndpoint { - @RequestMapping(path = "/HttpProxies/intercept-request", method = {RequestMethod.POST, RequestMethod.GET}) - @ResponseBody - public AttackResult completed(@RequestHeader(value = "x-request-intercepted", required = false) Boolean headerValue, - @RequestParam(value = "changeMe", required = false) String paramValue, HttpServletRequest request) { - if (HttpMethod.POST.matches(request.getMethod())) { - return failed(this).feedback("http-proxies.intercept.failure").build(); - } - if (headerValue != null && paramValue != null && headerValue && "Requests are tampered easily".equalsIgnoreCase(paramValue)) { - return success(this).feedback("http-proxies.intercept.success").build(); - } else { - return failed(this).feedback("http-proxies.intercept.failure").build(); - } + @RequestMapping( + path = "/HttpProxies/intercept-request", + method = {RequestMethod.POST, RequestMethod.GET}) + @ResponseBody + public AttackResult completed( + @RequestHeader(value = "x-request-intercepted", required = false) Boolean headerValue, + @RequestParam(value = "changeMe", required = false) String paramValue, + HttpServletRequest request) { + if (HttpMethod.POST.matches(request.getMethod())) { + return failed(this).feedback("http-proxies.intercept.failure").build(); } + if (headerValue != null + && paramValue != null + && headerValue + && "Requests are tampered easily".equalsIgnoreCase(paramValue)) { + return success(this).feedback("http-proxies.intercept.success").build(); + } else { + return failed(this).feedback("http-proxies.intercept.failure").build(); + } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/httpproxies/HttpProxies.java b/src/main/java/org/owasp/webgoat/lessons/httpproxies/HttpProxies.java index a111e1223..1d9326426 100644 --- a/src/main/java/org/owasp/webgoat/lessons/httpproxies/HttpProxies.java +++ b/src/main/java/org/owasp/webgoat/lessons/httpproxies/HttpProxies.java @@ -8,25 +8,26 @@ import org.springframework.stereotype.Component; * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -35,13 +36,13 @@ import org.springframework.stereotype.Component; */ @Component public class HttpProxies extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.GENERAL; - } + @Override + public Category getDefaultCategory() { + return Category.GENERAL; + } - @Override - public String getTitle() { - return "2.http-proxies.title";//second lesson in GENERAL - } + @Override + public String getTitle() { + return "2.http-proxies.title"; // second lesson in GENERAL + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/idor/IDOR.java b/src/main/java/org/owasp/webgoat/lessons/idor/IDOR.java index 38dc2a9eb..0adeeb25f 100644 --- a/src/main/java/org/owasp/webgoat/lessons/idor/IDOR.java +++ b/src/main/java/org/owasp/webgoat/lessons/idor/IDOR.java @@ -8,25 +8,26 @@ import org.springframework.stereotype.Component; * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author misfir3 @@ -36,13 +37,13 @@ import org.springframework.stereotype.Component; @Component public class IDOR extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A1; - } + @Override + public Category getDefaultCategory() { + return Category.A1; + } - @Override - public String getTitle() { - return "idor.title"; - } + @Override + public String getTitle() { + return "idor.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/idor/IDORDiffAttributes.java b/src/main/java/org/owasp/webgoat/lessons/idor/IDORDiffAttributes.java index 0b0dcca3d..f145ca1f9 100644 --- a/src/main/java/org/owasp/webgoat/lessons/idor/IDORDiffAttributes.java +++ b/src/main/java/org/owasp/webgoat/lessons/idor/IDORDiffAttributes.java @@ -31,22 +31,28 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController -@AssignmentHints({"idor.hints.idorDiffAttributes1", "idor.hints.idorDiffAttributes2", "idor.hints.idorDiffAttributes3"}) +@AssignmentHints({ + "idor.hints.idorDiffAttributes1", + "idor.hints.idorDiffAttributes2", + "idor.hints.idorDiffAttributes3" +}) public class IDORDiffAttributes extends AssignmentEndpoint { - @PostMapping("/IDOR/diff-attributes") - @ResponseBody - public AttackResult completed(@RequestParam String attributes) { - attributes = attributes.trim(); - String[] diffAttribs = attributes.split(","); - if (diffAttribs.length < 2) { - return failed(this).feedback("idor.diff.attributes.missing").build(); - } - if (diffAttribs[0].toLowerCase().trim().equals("userid") && diffAttribs[1].toLowerCase().trim().equals("role") - || diffAttribs[1].toLowerCase().trim().equals("userid") && diffAttribs[0].toLowerCase().trim().equals("role")) { - return success(this).feedback("idor.diff.success").build(); - } else { - return failed(this).feedback("idor.diff.failure").build(); - } + @PostMapping("/IDOR/diff-attributes") + @ResponseBody + public AttackResult completed(@RequestParam String attributes) { + attributes = attributes.trim(); + String[] diffAttribs = attributes.split(","); + if (diffAttribs.length < 2) { + return failed(this).feedback("idor.diff.attributes.missing").build(); } + if (diffAttribs[0].toLowerCase().trim().equals("userid") + && diffAttribs[1].toLowerCase().trim().equals("role") + || diffAttribs[1].toLowerCase().trim().equals("userid") + && diffAttribs[0].toLowerCase().trim().equals("role")) { + return success(this).feedback("idor.diff.success").build(); + } else { + return failed(this).feedback("idor.diff.failure").build(); + } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/idor/IDOREditOtherProfiile.java b/src/main/java/org/owasp/webgoat/lessons/idor/IDOREditOtherProfiile.java index d142c5ec9..404d0aeb4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/idor/IDOREditOtherProfiile.java +++ b/src/main/java/org/owasp/webgoat/lessons/idor/IDOREditOtherProfiile.java @@ -34,66 +34,80 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController -@AssignmentHints({"idor.hints.otherProfile1", "idor.hints.otherProfile2", "idor.hints.otherProfile3", "idor.hints.otherProfile4", "idor.hints.otherProfile5", "idor.hints.otherProfile6", "idor.hints.otherProfile7", "idor.hints.otherProfile8", "idor.hints.otherProfile9"}) +@AssignmentHints({ + "idor.hints.otherProfile1", + "idor.hints.otherProfile2", + "idor.hints.otherProfile3", + "idor.hints.otherProfile4", + "idor.hints.otherProfile5", + "idor.hints.otherProfile6", + "idor.hints.otherProfile7", + "idor.hints.otherProfile8", + "idor.hints.otherProfile9" +}) public class IDOREditOtherProfiile extends AssignmentEndpoint { - @Autowired - private UserSessionData userSessionData; + @Autowired private UserSessionData userSessionData; - @PutMapping(path = "/IDOR/profile/{userId}", consumes = "application/json") - @ResponseBody - public AttackResult completed(@PathVariable("userId") String userId, @RequestBody UserProfile userSubmittedProfile) { + @PutMapping(path = "/IDOR/profile/{userId}", consumes = "application/json") + @ResponseBody + public AttackResult completed( + @PathVariable("userId") String userId, @RequestBody UserProfile userSubmittedProfile) { - String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id"); - // this is where it starts ... accepting the user submitted ID and assuming it will be the same as the logged in userId and not checking for proper authorization - // Certain roles can sometimes edit others' profiles, but we shouldn't just assume that and let everyone, right? - // Except that this is a vulnerable app ... so we will - UserProfile currentUserProfile = new UserProfile(userId); - if (userSubmittedProfile.getUserId() != null && !userSubmittedProfile.getUserId().equals(authUserId)) { - // let's get this started ... - currentUserProfile.setColor(userSubmittedProfile.getColor()); - currentUserProfile.setRole(userSubmittedProfile.getRole()); - // we will persist in the session object for now in case we want to refer back or use it later - userSessionData.setValue("idor-updated-other-profile", currentUserProfile); - if (currentUserProfile.getRole() <= 1 && currentUserProfile.getColor().toLowerCase().equals("red")) { - return success(this) - .feedback("idor.edit.profile.success1") - .output(currentUserProfile.profileToMap().toString()) - .build(); - } + String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id"); + // this is where it starts ... accepting the user submitted ID and assuming it will be the same + // as the logged in userId and not checking for proper authorization + // Certain roles can sometimes edit others' profiles, but we shouldn't just assume that and let + // everyone, right? + // Except that this is a vulnerable app ... so we will + UserProfile currentUserProfile = new UserProfile(userId); + if (userSubmittedProfile.getUserId() != null + && !userSubmittedProfile.getUserId().equals(authUserId)) { + // let's get this started ... + currentUserProfile.setColor(userSubmittedProfile.getColor()); + currentUserProfile.setRole(userSubmittedProfile.getRole()); + // we will persist in the session object for now in case we want to refer back or use it later + userSessionData.setValue("idor-updated-other-profile", currentUserProfile); + if (currentUserProfile.getRole() <= 1 + && currentUserProfile.getColor().toLowerCase().equals("red")) { + return success(this) + .feedback("idor.edit.profile.success1") + .output(currentUserProfile.profileToMap().toString()) + .build(); + } - if (currentUserProfile.getRole() > 1 && currentUserProfile.getColor().toLowerCase().equals("red")) { - return success(this) - .feedback("idor.edit.profile.failure1") - .output(currentUserProfile.profileToMap().toString()) - .build(); - } + if (currentUserProfile.getRole() > 1 + && currentUserProfile.getColor().toLowerCase().equals("red")) { + return success(this) + .feedback("idor.edit.profile.failure1") + .output(currentUserProfile.profileToMap().toString()) + .build(); + } - if (currentUserProfile.getRole() <= 1 && !currentUserProfile.getColor().toLowerCase().equals("red")) { - return success(this) - .feedback("idor.edit.profile.failure2") - .output(currentUserProfile.profileToMap().toString()) - .build(); - } - - // else - return failed(this) - .feedback("idor.edit.profile.failure3") - .output(currentUserProfile.profileToMap().toString()) - .build(); - } else if (userSubmittedProfile.getUserId().equals(authUserId)) { - return failed(this).feedback("idor.edit.profile.failure4").build(); - } - - if (currentUserProfile.getColor().equals("black") && currentUserProfile.getRole() <= 1) { - return success(this) - .feedback("idor.edit.profile.success2") - .output(userSessionData.getValue("idor-updated-own-profile").toString()) - .build(); - } else { - return failed(this).feedback("idor.edit.profile.failure3").build(); - } + if (currentUserProfile.getRole() <= 1 + && !currentUserProfile.getColor().toLowerCase().equals("red")) { + return success(this) + .feedback("idor.edit.profile.failure2") + .output(currentUserProfile.profileToMap().toString()) + .build(); + } + // else + return failed(this) + .feedback("idor.edit.profile.failure3") + .output(currentUserProfile.profileToMap().toString()) + .build(); + } else if (userSubmittedProfile.getUserId().equals(authUserId)) { + return failed(this).feedback("idor.edit.profile.failure4").build(); } + if (currentUserProfile.getColor().equals("black") && currentUserProfile.getRole() <= 1) { + return success(this) + .feedback("idor.edit.profile.success2") + .output(userSessionData.getValue("idor-updated-own-profile").toString()) + .build(); + } else { + return failed(this).feedback("idor.edit.profile.failure3").build(); + } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/idor/IDORLogin.java b/src/main/java/org/owasp/webgoat/lessons/idor/IDORLogin.java index 89e3b139d..1b656c0cf 100644 --- a/src/main/java/org/owasp/webgoat/lessons/idor/IDORLogin.java +++ b/src/main/java/org/owasp/webgoat/lessons/idor/IDORLogin.java @@ -22,6 +22,8 @@ package org.owasp.webgoat.lessons.idor; +import java.util.HashMap; +import java.util.Map; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -31,47 +33,44 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; -import java.util.Map; - @RestController @AssignmentHints({"idor.hints.idor_login"}) public class IDORLogin extends AssignmentEndpoint { - private Map> idorUserInfo = new HashMap<>(); + private Map> idorUserInfo = new HashMap<>(); - public void initIDORInfo() { + public void initIDORInfo() { - idorUserInfo.put("tom", new HashMap()); - idorUserInfo.get("tom").put("password", "cat"); - idorUserInfo.get("tom").put("id", "2342384"); - idorUserInfo.get("tom").put("color", "yellow"); - idorUserInfo.get("tom").put("size", "small"); + idorUserInfo.put("tom", new HashMap()); + idorUserInfo.get("tom").put("password", "cat"); + idorUserInfo.get("tom").put("id", "2342384"); + idorUserInfo.get("tom").put("color", "yellow"); + idorUserInfo.get("tom").put("size", "small"); - idorUserInfo.put("bill", new HashMap()); - idorUserInfo.get("bill").put("password", "buffalo"); - idorUserInfo.get("bill").put("id", "2342388"); - idorUserInfo.get("bill").put("color", "brown"); - idorUserInfo.get("bill").put("size", "large"); + idorUserInfo.put("bill", new HashMap()); + idorUserInfo.get("bill").put("password", "buffalo"); + idorUserInfo.get("bill").put("id", "2342388"); + idorUserInfo.get("bill").put("color", "brown"); + idorUserInfo.get("bill").put("size", "large"); + } + @PostMapping("/IDOR/login") + @ResponseBody + public AttackResult completed(@RequestParam String username, @RequestParam String password) { + initIDORInfo(); + UserSessionData userSessionData = getUserSessionData(); + + if (idorUserInfo.containsKey(username)) { + if ("tom".equals(username) && idorUserInfo.get("tom").get("password").equals(password)) { + userSessionData.setValue("idor-authenticated-as", username); + userSessionData.setValue( + "idor-authenticated-user-id", idorUserInfo.get(username).get("id")); + return success(this).feedback("idor.login.success").feedbackArgs(username).build(); + } else { + return failed(this).feedback("idor.login.failure").build(); + } + } else { + return failed(this).feedback("idor.login.failure").build(); } - - @PostMapping("/IDOR/login") - @ResponseBody - public AttackResult completed(@RequestParam String username, @RequestParam String password) { - initIDORInfo(); - UserSessionData userSessionData = getUserSessionData(); - - if (idorUserInfo.containsKey(username)) { - if ("tom".equals(username) && idorUserInfo.get("tom").get("password").equals(password)) { - userSessionData.setValue("idor-authenticated-as", username); - userSessionData.setValue("idor-authenticated-user-id", idorUserInfo.get(username).get("id")); - return success(this).feedback("idor.login.success").feedbackArgs(username).build(); - } else { - return failed(this).feedback("idor.login.failure").build(); - } - } else { - return failed(this).feedback("idor.login.failure").build(); - } - } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOtherProfile.java b/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOtherProfile.java index 1710655fd..f216cb580 100644 --- a/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOtherProfile.java +++ b/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOtherProfile.java @@ -22,6 +22,9 @@ package org.owasp.webgoat.lessons.idor; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -32,38 +35,49 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletResponse; -import java.util.HashMap; -import java.util.Map; - @RestController -@AssignmentHints({"idor.hints.otherProfile1", "idor.hints.otherProfile2", "idor.hints.otherProfile3", "idor.hints.otherProfile4", "idor.hints.otherProfile5", "idor.hints.otherProfile6", "idor.hints.otherProfile7", "idor.hints.otherProfile8", "idor.hints.otherProfile9"}) +@AssignmentHints({ + "idor.hints.otherProfile1", + "idor.hints.otherProfile2", + "idor.hints.otherProfile3", + "idor.hints.otherProfile4", + "idor.hints.otherProfile5", + "idor.hints.otherProfile6", + "idor.hints.otherProfile7", + "idor.hints.otherProfile8", + "idor.hints.otherProfile9" +}) public class IDORViewOtherProfile extends AssignmentEndpoint { - @Autowired - UserSessionData userSessionData; + @Autowired UserSessionData userSessionData; - @GetMapping(path = "/IDOR/profile/{userId}", produces = {"application/json"}) - @ResponseBody - public AttackResult completed(@PathVariable("userId") String userId, HttpServletResponse resp) { - Map details = new HashMap<>(); + @GetMapping( + path = "/IDOR/profile/{userId}", + produces = {"application/json"}) + @ResponseBody + public AttackResult completed(@PathVariable("userId") String userId, HttpServletResponse resp) { + Map details = new HashMap<>(); - if (userSessionData.getValue("idor-authenticated-as").equals("tom")) { - //going to use session auth to view this one - String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id"); - if (userId != null && !userId.equals(authUserId)) { - //on the right track - UserProfile requestedProfile = new UserProfile(userId); - // secure code would ensure there was a horizontal access control check prior to dishing up the requested profile - if (requestedProfile.getUserId().equals("2342388")) { - return success(this).feedback("idor.view.profile.success").output(requestedProfile.profileToMap().toString()).build(); - } else { - return failed(this).feedback("idor.view.profile.close1").build(); - } - } else { - return failed(this).feedback("idor.view.profile.close2").build(); - } + if (userSessionData.getValue("idor-authenticated-as").equals("tom")) { + // going to use session auth to view this one + String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id"); + if (userId != null && !userId.equals(authUserId)) { + // on the right track + UserProfile requestedProfile = new UserProfile(userId); + // secure code would ensure there was a horizontal access control check prior to dishing up + // the requested profile + if (requestedProfile.getUserId().equals("2342388")) { + return success(this) + .feedback("idor.view.profile.success") + .output(requestedProfile.profileToMap().toString()) + .build(); + } else { + return failed(this).feedback("idor.view.profile.close1").build(); } - return failed(this).build(); + } else { + return failed(this).feedback("idor.view.profile.close2").build(); + } } + return failed(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfile.java b/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfile.java index c4a4f0e9d..ec78df0bd 100644 --- a/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfile.java +++ b/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfile.java @@ -22,7 +22,8 @@ package org.owasp.webgoat.lessons.idor; - +import java.util.HashMap; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.session.UserSessionData; import org.springframework.beans.factory.annotation.Autowired; @@ -30,36 +31,36 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; -import java.util.Map; - @RestController @Slf4j public class IDORViewOwnProfile { - @Autowired - UserSessionData userSessionData; + @Autowired UserSessionData userSessionData; - @GetMapping(path = {"/IDOR/own", "/IDOR/profile"}, produces = {"application/json"}) - @ResponseBody - public Map invoke() { - Map details = new HashMap<>(); - try { - if (userSessionData.getValue("idor-authenticated-as").equals("tom")) { - //going to use session auth to view this one - String authUserId = (String)userSessionData.getValue("idor-authenticated-user-id"); - UserProfile userProfile = new UserProfile(authUserId); - details.put("userId",userProfile.getUserId()); - details.put("name",userProfile.getName()); - details.put("color",userProfile.getColor()); - details.put("size",userProfile.getSize()); - details.put("role",userProfile.getRole()); - } else { - details.put("error","You do not have privileges to view the profile. Authenticate as tom first please."); - } - }catch (Exception ex) { - log.error("something went wrong", ex.getMessage()); - } - return details; + @GetMapping( + path = {"/IDOR/own", "/IDOR/profile"}, + produces = {"application/json"}) + @ResponseBody + public Map invoke() { + Map details = new HashMap<>(); + try { + if (userSessionData.getValue("idor-authenticated-as").equals("tom")) { + // going to use session auth to view this one + String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id"); + UserProfile userProfile = new UserProfile(authUserId); + details.put("userId", userProfile.getUserId()); + details.put("name", userProfile.getName()); + details.put("color", userProfile.getColor()); + details.put("size", userProfile.getSize()); + details.put("role", userProfile.getRole()); + } else { + details.put( + "error", + "You do not have privileges to view the profile. Authenticate as tom first please."); + } + } catch (Exception ex) { + log.error("something went wrong", ex.getMessage()); } + return details; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfileAltUrl.java b/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfileAltUrl.java index 38a8ba5f0..a2fe4cb9c 100644 --- a/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfileAltUrl.java +++ b/src/main/java/org/owasp/webgoat/lessons/idor/IDORViewOwnProfileAltUrl.java @@ -22,7 +22,6 @@ package org.owasp.webgoat.lessons.idor; - import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -34,33 +33,42 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController -@AssignmentHints({"idor.hints.ownProfileAltUrl1", "idor.hints.ownProfileAltUrl2", "idor.hints.ownProfileAltUrl3"}) +@AssignmentHints({ + "idor.hints.ownProfileAltUrl1", + "idor.hints.ownProfileAltUrl2", + "idor.hints.ownProfileAltUrl3" +}) public class IDORViewOwnProfileAltUrl extends AssignmentEndpoint { - @Autowired - UserSessionData userSessionData; + @Autowired UserSessionData userSessionData; - @PostMapping("/IDOR/profile/alt-path") - @ResponseBody - public AttackResult completed(@RequestParam String url) { - try { - if (userSessionData.getValue("idor-authenticated-as").equals("tom")) { - //going to use session auth to view this one - String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id"); - //don't care about http://localhost:8080 ... just want WebGoat/ - String[] urlParts = url.split("/"); - if (urlParts[0].equals("WebGoat") && urlParts[1].equals("IDOR") && urlParts[2].equals("profile") && urlParts[3].equals(authUserId)) { - UserProfile userProfile = new UserProfile(authUserId); - return success(this).feedback("idor.view.own.profile.success").output(userProfile.profileToMap().toString()).build(); - } else { - return failed(this).feedback("idor.view.own.profile.failure1").build(); - } - - } else { - return failed(this).feedback("idor.view.own.profile.failure2").build(); - } - } catch (Exception ex) { - return failed(this).feedback("an error occurred with your request").build(); + @PostMapping("/IDOR/profile/alt-path") + @ResponseBody + public AttackResult completed(@RequestParam String url) { + try { + if (userSessionData.getValue("idor-authenticated-as").equals("tom")) { + // going to use session auth to view this one + String authUserId = (String) userSessionData.getValue("idor-authenticated-user-id"); + // don't care about http://localhost:8080 ... just want WebGoat/ + String[] urlParts = url.split("/"); + if (urlParts[0].equals("WebGoat") + && urlParts[1].equals("IDOR") + && urlParts[2].equals("profile") + && urlParts[3].equals(authUserId)) { + UserProfile userProfile = new UserProfile(authUserId); + return success(this) + .feedback("idor.view.own.profile.success") + .output(userProfile.profileToMap().toString()) + .build(); + } else { + return failed(this).feedback("idor.view.own.profile.failure1").build(); } + + } else { + return failed(this).feedback("idor.view.own.profile.failure2").build(); + } + } catch (Exception ex) { + return failed(this).feedback("an error occurred with your request").build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/idor/UserProfile.java b/src/main/java/org/owasp/webgoat/lessons/idor/UserProfile.java index 569119fcf..f1490b2a5 100644 --- a/src/main/java/org/owasp/webgoat/lessons/idor/UserProfile.java +++ b/src/main/java/org/owasp/webgoat/lessons/idor/UserProfile.java @@ -25,112 +25,117 @@ package org.owasp.webgoat.lessons.idor; import java.util.HashMap; import java.util.Map; -/** - * Created by jason on 1/5/17. - */ +/** Created by jason on 1/5/17. */ public class UserProfile { - private String userId; - private String name; - private String color; - private String size; - private boolean isAdmin; - private int role; + private String userId; + private String name; + private String color; + private String size; + private boolean isAdmin; + private int role; - public UserProfile() {} + public UserProfile() {} - public UserProfile(String id) { - setProfileFromId(id); + public UserProfile(String id) { + setProfileFromId(id); + } + + // + private void setProfileFromId(String id) { + // emulate look up from database + if (id.equals("2342384")) { + this.userId = id; + this.color = "yellow"; + this.name = "Tom Cat"; + this.size = "small"; + this.isAdmin = false; + this.role = 3; + } else if (id.equals("2342388")) { + this.userId = id; + this.color = "brown"; + this.name = "Buffalo Bill"; + this.size = "large"; + this.isAdmin = false; + this.role = 3; + } else { + // not found } + } - // - private void setProfileFromId(String id) { - // emulate look up from database - if (id.equals("2342384")) { - this.userId = id; - this.color = "yellow"; - this.name = "Tom Cat"; - this.size = "small"; - this.isAdmin = false; - this.role = 3; - } else if (id.equals("2342388")) { - this.userId = id; - this.color = "brown"; - this.name = "Buffalo Bill"; - this.size = "large"; - this.isAdmin = false; - this.role = 3; - } else { - //not found - } + public Map profileToMap() { + Map profileMap = new HashMap<>(); + profileMap.put("userId", this.userId); + profileMap.put("name", this.name); + profileMap.put("color", this.color); + profileMap.put("size", this.size); + profileMap.put("role", this.role); + return profileMap; + } - } + public String toHTMLString() { + String htmlBreak = "
"; + return "userId" + + this.userId + + htmlBreak + + "name" + + this.name + + htmlBreak + + "size" + + this.size + + htmlBreak + + "role" + + this.role + + htmlBreak + + "isAdmin" + + this.isAdmin; + } - public Map profileToMap () { - Map profileMap = new HashMap<>(); - profileMap.put("userId", this.userId); - profileMap.put("name", this.name); - profileMap.put("color", this.color); - profileMap.put("size", this.size); - profileMap.put("role", this.role); - return profileMap; - } + // + public String getUserId() { + return userId; + } - public String toHTMLString() { - String htmlBreak = "
"; - return "userId" + this.userId + htmlBreak + - "name" + this.name + htmlBreak + - "size" + this.size + htmlBreak + - "role" + this.role + htmlBreak + - "isAdmin" + this.isAdmin; - } + public void setUserId(String userId) { + this.userId = userId; + } - // - public String getUserId() { - return userId; - } + public String getName() { + return name; + } - public void setUserId(String userId) { - this.userId = userId; - } + public void setName(String name) { + this.name = name; + } - public String getName() { - return name; - } + public String getColor() { + return color; + } - public void setName(String name) { - this.name = name; - } + public void setColor(String color) { + this.color = color; + } - public String getColor() { - return color; - } + public String getSize() { + return size; + } - public void setColor(String color) { - this.color = color; - } + public void setSize(String size) { + this.size = size; + } - public String getSize() { - return size; - } + public boolean isAdmin() { + return isAdmin; + } - public void setSize(String size) { - this.size = size; - } + public void setAdmin(boolean admin) { + isAdmin = admin; + } - public boolean isAdmin() { - return isAdmin; - } - - public void setAdmin(boolean admin) { - isAdmin = admin; - } - - public int getRole() { - return role; - } - - public void setRole(int role) { - this.role = role; - } + public int getRole() { + return role; + } + public void setRole(int role) { + this.role = role; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/insecurelogin/InsecureLogin.java b/src/main/java/org/owasp/webgoat/lessons/insecurelogin/InsecureLogin.java index dc04e2969..d017421e2 100644 --- a/src/main/java/org/owasp/webgoat/lessons/insecurelogin/InsecureLogin.java +++ b/src/main/java/org/owasp/webgoat/lessons/insecurelogin/InsecureLogin.java @@ -8,25 +8,26 @@ import org.springframework.stereotype.Component; * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -35,13 +36,13 @@ import org.springframework.stereotype.Component; */ @Component public class InsecureLogin extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A7; - } + @Override + public Category getDefaultCategory() { + return Category.A7; + } - @Override - public String getTitle() { - return "insecure-login.title"; - } + @Override + public String getTitle() { + return "insecure-login.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/insecurelogin/InsecureLoginTask.java b/src/main/java/org/owasp/webgoat/lessons/insecurelogin/InsecureLoginTask.java index 72faf5a6f..8d39a594d 100644 --- a/src/main/java/org/owasp/webgoat/lessons/insecurelogin/InsecureLoginTask.java +++ b/src/main/java/org/owasp/webgoat/lessons/insecurelogin/InsecureLoginTask.java @@ -30,18 +30,18 @@ import org.springframework.web.bind.annotation.*; @RestController public class InsecureLoginTask extends AssignmentEndpoint { - @PostMapping("/InsecureLogin/task") - @ResponseBody - public AttackResult completed(@RequestParam String username, @RequestParam String password) { - if ("CaptainJack".equals(username) && "BlackPearl".equals(password)) { - return success(this).build(); - } - return failed(this).build(); + @PostMapping("/InsecureLogin/task") + @ResponseBody + public AttackResult completed(@RequestParam String username, @RequestParam String password) { + if ("CaptainJack".equals(username) && "BlackPearl".equals(password)) { + return success(this).build(); } + return failed(this).build(); + } - @PostMapping("/InsecureLogin/login") - @ResponseStatus(HttpStatus.ACCEPTED) - public void login() { - //only need to exists as the JS needs to call an existing endpoint - } + @PostMapping("/InsecureLogin/login") + @ResponseStatus(HttpStatus.ACCEPTED) + public void login() { + // only need to exists as the JS needs to call an existing endpoint + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/JWT.java b/src/main/java/org/owasp/webgoat/lessons/jwt/JWT.java index d65b566c1..31dee5ef5 100644 --- a/src/main/java/org/owasp/webgoat/lessons/jwt/JWT.java +++ b/src/main/java/org/owasp/webgoat/lessons/jwt/JWT.java @@ -33,13 +33,13 @@ import org.springframework.stereotype.Component; @Component public class JWT extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A7; - } + @Override + public Category getDefaultCategory() { + return Category.A7; + } - @Override - public String getTitle() { - return "jwt.title"; - } + @Override + public String getTitle() { + return "jwt.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTDecodeEndpoint.java b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTDecodeEndpoint.java index 0d2f06c6f..9b27236cb 100644 --- a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTDecodeEndpoint.java +++ b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTDecodeEndpoint.java @@ -10,13 +10,13 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class JWTDecodeEndpoint extends AssignmentEndpoint { - @PostMapping("/JWT/decode") - @ResponseBody - public AttackResult decode(@RequestParam("jwt-encode-user") String user) { - if ("user".equals(user)) { - return success(this).build(); - } else { - return failed(this).build(); - } + @PostMapping("/JWT/decode") + @ResponseBody + public AttackResult decode(@RequestParam("jwt-encode-user") String user) { + if ("user".equals(user)) { + return success(this).build(); + } else { + return failed(this).build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpoint.java b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpoint.java index 67d2a87b9..e84bbf809 100644 --- a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpoint.java +++ b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpoint.java @@ -24,6 +24,8 @@ package org.owasp.webgoat.lessons.jwt; import io.jsonwebtoken.*; import io.jsonwebtoken.impl.TextCodec; +import java.sql.ResultSet; +import java.sql.SQLException; import org.apache.commons.lang3.StringUtils; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -31,10 +33,9 @@ import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.web.bind.annotation.*; -import java.sql.ResultSet; -import java.sql.SQLException; - /** + * + * *

  *  {
  *      "typ": "JWT",
@@ -59,64 +60,77 @@ import java.sql.SQLException;
  * @since 4/23/17.
  */
 @RestController
-@AssignmentHints({"jwt-final-hint1", "jwt-final-hint2", "jwt-final-hint3", "jwt-final-hint4", "jwt-final-hint5", "jwt-final-hint6"})
+@AssignmentHints({
+  "jwt-final-hint1",
+  "jwt-final-hint2",
+  "jwt-final-hint3",
+  "jwt-final-hint4",
+  "jwt-final-hint5",
+  "jwt-final-hint6"
+})
 public class JWTFinalEndpoint extends AssignmentEndpoint {
 
-    private final LessonDataSource dataSource;
+  private final LessonDataSource dataSource;
 
-    private JWTFinalEndpoint(LessonDataSource dataSource) {
-        this.dataSource = dataSource;
-    }
-    
-    @PostMapping("/JWT/final/follow/{user}")
-    public @ResponseBody
-    String follow(@PathVariable("user") String user) {
-        if ("Jerry".equals(user)) {
-            return "Following yourself seems redundant";
-        } else {
-            return "You are now following Tom";
-        }
-    }
+  private JWTFinalEndpoint(LessonDataSource dataSource) {
+    this.dataSource = dataSource;
+  }
 
-    @PostMapping("/JWT/final/delete")
-    public @ResponseBody
-    AttackResult resetVotes(@RequestParam("token") String token) {
-        if (StringUtils.isEmpty(token)) {
-            return failed(this).feedback("jwt-invalid-token").build();
-        } else {
-            try {
-                final String[] errorMessage = {null};
-                Jwt jwt = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
-                    @Override
-                    public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
+  @PostMapping("/JWT/final/follow/{user}")
+  public @ResponseBody String follow(@PathVariable("user") String user) {
+    if ("Jerry".equals(user)) {
+      return "Following yourself seems redundant";
+    } else {
+      return "You are now following Tom";
+    }
+  }
+
+  @PostMapping("/JWT/final/delete")
+  public @ResponseBody AttackResult resetVotes(@RequestParam("token") String token) {
+    if (StringUtils.isEmpty(token)) {
+      return failed(this).feedback("jwt-invalid-token").build();
+    } else {
+      try {
+        final String[] errorMessage = {null};
+        Jwt jwt =
+            Jwts.parser()
+                .setSigningKeyResolver(
+                    new SigningKeyResolverAdapter() {
+                      @Override
+                      public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
                         final String kid = (String) header.get("kid");
                         try (var connection = dataSource.getConnection()) {
-                            ResultSet rs = connection.createStatement().executeQuery("SELECT key FROM jwt_keys WHERE id = '" + kid + "'");
-                            while (rs.next()) {
-                                return TextCodec.BASE64.decode(rs.getString(1));
-                            }
+                          ResultSet rs =
+                              connection
+                                  .createStatement()
+                                  .executeQuery(
+                                      "SELECT key FROM jwt_keys WHERE id = '" + kid + "'");
+                          while (rs.next()) {
+                            return TextCodec.BASE64.decode(rs.getString(1));
+                          }
                         } catch (SQLException e) {
-                            errorMessage[0] = e.getMessage();
+                          errorMessage[0] = e.getMessage();
                         }
                         return null;
-                    }
-                }).parseClaimsJws(token);
-                if (errorMessage[0] != null) {
-                    return failed(this).output(errorMessage[0]).build();
-                }
-                Claims claims = (Claims) jwt.getBody();
-                String username = (String) claims.get("username");
-                if ("Jerry".equals(username)) {
-                    return failed(this).feedback("jwt-final-jerry-account").build();
-                }
-                if ("Tom".equals(username)) {
-                    return success(this).build();
-                } else {
-                    return failed(this).feedback("jwt-final-not-tom").build();
-                }
-            } catch (JwtException e) {
-                return failed(this).feedback("jwt-invalid-token").output(e.toString()).build();
-            }
+                      }
+                    })
+                .parseClaimsJws(token);
+        if (errorMessage[0] != null) {
+          return failed(this).output(errorMessage[0]).build();
         }
+        Claims claims = (Claims) jwt.getBody();
+        String username = (String) claims.get("username");
+        if ("Jerry".equals(username)) {
+          return failed(this).feedback("jwt-final-jerry-account").build();
+        }
+        if ("Tom".equals(username)) {
+          return success(this).build();
+        } else {
+          return failed(this).feedback("jwt-final-not-tom").build();
+        }
+      } catch (JwtException e) {
+        return failed(this).feedback("jwt-invalid-token").output(e.toString()).build();
+      }
     }
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTQuiz.java b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTQuiz.java
index 26f544cd4..abcd08edd 100644
--- a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTQuiz.java
+++ b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTQuiz.java
@@ -8,42 +8,41 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
-
 @RestController
 public class JWTQuiz extends AssignmentEndpoint {
 
-    private final String[] solutions = {"Solution 1", "Solution 2"};
-    private final boolean[] guesses = new boolean[solutions.length];
+  private final String[] solutions = {"Solution 1", "Solution 2"};
+  private final boolean[] guesses = new boolean[solutions.length];
 
-    @PostMapping("/JWT/quiz")
-    @ResponseBody
-    public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution) {
-        int correctAnswers = 0;
+  @PostMapping("/JWT/quiz")
+  @ResponseBody
+  public AttackResult completed(
+      @RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution) {
+    int correctAnswers = 0;
 
-        String[] givenAnswers = {question_0_solution[0], question_1_solution[0]};
+    String[] givenAnswers = {question_0_solution[0], question_1_solution[0]};
 
-        for (int i = 0; i < solutions.length; i++) {
-            if (givenAnswers[i].contains(solutions[i])) {
-                // answer correct
-                correctAnswers++;
-                guesses[i] = true;
-            } else {
-                // answer incorrect
-                guesses[i] = false;
-            }
-        }
-
-        if (correctAnswers == solutions.length) {
-            return success(this).build();
-        } else {
-            return failed(this).build();
-        }
+    for (int i = 0; i < solutions.length; i++) {
+      if (givenAnswers[i].contains(solutions[i])) {
+        // answer correct
+        correctAnswers++;
+        guesses[i] = true;
+      } else {
+        // answer incorrect
+        guesses[i] = false;
+      }
     }
 
-    @GetMapping("/JWT/quiz")
-    @ResponseBody
-    public boolean[] getResults() {
-        return this.guesses;
+    if (correctAnswers == solutions.length) {
+      return success(this).build();
+    } else {
+      return failed(this).build();
     }
+  }
 
+  @GetMapping("/JWT/quiz")
+  @ResponseBody
+  public boolean[] getResults() {
+    return this.guesses;
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpoint.java b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpoint.java
index 675dcd449..945bb57da 100644
--- a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpoint.java
+++ b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpoint.java
@@ -22,12 +22,20 @@
 
 package org.owasp.webgoat.lessons.jwt;
 
+import static org.springframework.http.ResponseEntity.ok;
+
 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.ExpiredJwtException;
 import io.jsonwebtoken.Header;
 import io.jsonwebtoken.Jwt;
 import io.jsonwebtoken.JwtException;
 import io.jsonwebtoken.Jwts;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
 import org.owasp.webgoat.container.assignments.AssignmentHints;
@@ -41,106 +49,109 @@ import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import static org.springframework.http.ResponseEntity.ok;
-
 /**
  * @author nbaars
  * @since 4/23/17.
  */
 @RestController
-@AssignmentHints({"jwt-refresh-hint1", "jwt-refresh-hint2", "jwt-refresh-hint3", "jwt-refresh-hint4"})
+@AssignmentHints({
+  "jwt-refresh-hint1",
+  "jwt-refresh-hint2",
+  "jwt-refresh-hint3",
+  "jwt-refresh-hint4"
+})
 public class JWTRefreshEndpoint extends AssignmentEndpoint {
 
-    public static final String PASSWORD = "bm5nhSkxCXZkKRy4";
-    private static final String JWT_PASSWORD = "bm5n3SkxCX4kKRy4";
-    private static final List validRefreshTokens = new ArrayList<>();
+  public static final String PASSWORD = "bm5nhSkxCXZkKRy4";
+  private static final String JWT_PASSWORD = "bm5n3SkxCX4kKRy4";
+  private static final List validRefreshTokens = new ArrayList<>();
 
-    @PostMapping(value = "/JWT/refresh/login", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
-    @ResponseBody
-    public ResponseEntity follow(@RequestBody(required = false) Map json) {
-        if (json == null) {
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-        }
-        String user = (String) json.get("user");
-        String password = (String) json.get("password");
+  @PostMapping(
+      value = "/JWT/refresh/login",
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE)
+  @ResponseBody
+  public ResponseEntity follow(@RequestBody(required = false) Map json) {
+    if (json == null) {
+      return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+    }
+    String user = (String) json.get("user");
+    String password = (String) json.get("password");
 
-        if ("Jerry".equalsIgnoreCase(user) && PASSWORD.equals(password)) {
-            return ok(createNewTokens(user));
-        }
-        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+    if ("Jerry".equalsIgnoreCase(user) && PASSWORD.equals(password)) {
+      return ok(createNewTokens(user));
+    }
+    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+  }
+
+  private Map createNewTokens(String user) {
+    Map claims = new HashMap<>();
+    claims.put("admin", "false");
+    claims.put("user", user);
+    String token =
+        Jwts.builder()
+            .setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10)))
+            .setClaims(claims)
+            .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD)
+            .compact();
+    Map tokenJson = new HashMap<>();
+    String refreshToken = RandomStringUtils.randomAlphabetic(20);
+    validRefreshTokens.add(refreshToken);
+    tokenJson.put("access_token", token);
+    tokenJson.put("refresh_token", refreshToken);
+    return tokenJson;
+  }
+
+  @PostMapping("/JWT/refresh/checkout")
+  @ResponseBody
+  public ResponseEntity checkout(
+      @RequestHeader(value = "Authorization", required = false) String token) {
+    if (token == null) {
+      return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+    }
+    try {
+      Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", ""));
+      Claims claims = (Claims) jwt.getBody();
+      String user = (String) claims.get("user");
+      if ("Tom".equals(user)) {
+        return ok(success(this).build());
+      }
+      return ok(failed(this).feedback("jwt-refresh-not-tom").feedbackArgs(user).build());
+    } catch (ExpiredJwtException e) {
+      return ok(failed(this).output(e.getMessage()).build());
+    } catch (JwtException e) {
+      return ok(failed(this).feedback("jwt-invalid-token").build());
+    }
+  }
+
+  @PostMapping("/JWT/refresh/newToken")
+  @ResponseBody
+  public ResponseEntity newToken(
+      @RequestHeader(value = "Authorization", required = false) String token,
+      @RequestBody(required = false) Map json) {
+    if (token == null || json == null) {
+      return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
     }
 
-    private Map createNewTokens(String user) {
-        Map claims = new HashMap<>();
-        claims.put("admin", "false");
-        claims.put("user", user);
-        String token = Jwts.builder()
-                .setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10)))
-                .setClaims(claims)
-                .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD)
-                .compact();
-        Map tokenJson = new HashMap<>();
-        String refreshToken = RandomStringUtils.randomAlphabetic(20);
-        validRefreshTokens.add(refreshToken);
-        tokenJson.put("access_token", token);
-        tokenJson.put("refresh_token", refreshToken);
-        return tokenJson;
+    String user;
+    String refreshToken;
+    try {
+      Jwt jwt =
+          Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", ""));
+      user = (String) jwt.getBody().get("user");
+      refreshToken = (String) json.get("refresh_token");
+    } catch (ExpiredJwtException e) {
+      user = (String) e.getClaims().get("user");
+      refreshToken = (String) json.get("refresh_token");
     }
 
-    @PostMapping("/JWT/refresh/checkout")
-    @ResponseBody
-    public ResponseEntity checkout(@RequestHeader(value = "Authorization", required = false) String token) {
-        if (token == null) {
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-        }
-        try {
-            Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", ""));
-            Claims claims = (Claims) jwt.getBody();
-            String user = (String) claims.get("user");
-            if ("Tom".equals(user)) {
-                return ok(success(this).build());
-            }
-            return ok(failed(this).feedback("jwt-refresh-not-tom").feedbackArgs(user).build());
-        } catch (ExpiredJwtException e) {
-            return ok(failed(this).output(e.getMessage()).build());
-        } catch (JwtException e) {
-            return ok(failed(this).feedback("jwt-invalid-token").build());
-        }
-    }
-
-    @PostMapping("/JWT/refresh/newToken")
-    @ResponseBody
-    public ResponseEntity newToken(@RequestHeader(value = "Authorization", required = false) String token,
-                                   @RequestBody(required = false) Map json) {
-        if (token == null || json == null) {
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-        }
-
-        String user;
-        String refreshToken;
-        try {
-            Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", ""));
-            user = (String) jwt.getBody().get("user");
-            refreshToken = (String) json.get("refresh_token");
-        } catch (ExpiredJwtException e) {
-            user = (String) e.getClaims().get("user");
-            refreshToken = (String) json.get("refresh_token");
-        }
-
-        if (user == null || refreshToken == null) {
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-        } else if (validRefreshTokens.contains(refreshToken)) {
-            validRefreshTokens.remove(refreshToken);
-            return ok(createNewTokens(user));
-        } else {
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-        }
+    if (user == null || refreshToken == null) {
+      return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+    } else if (validRefreshTokens.contains(refreshToken)) {
+      validRefreshTokens.remove(refreshToken);
+      return ok(createNewTokens(user));
+    } else {
+      return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
     }
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTSecretKeyEndpoint.java b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTSecretKeyEndpoint.java
index affa09cf1..dac1ef5cc 100644
--- a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTSecretKeyEndpoint.java
+++ b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTSecretKeyEndpoint.java
@@ -27,6 +27,11 @@ import io.jsonwebtoken.Jwt;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.SignatureAlgorithm;
 import io.jsonwebtoken.impl.TextCodec;
+import java.time.Instant;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Random;
 import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
 import org.owasp.webgoat.container.assignments.AssignmentHints;
 import org.owasp.webgoat.container.assignments.AttackResult;
@@ -37,12 +42,6 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.time.Instant;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.List;
-import java.util.Random;
-
 /**
  * @author nbaars
  * @since 4/23/17.
@@ -51,45 +50,50 @@ import java.util.Random;
 @AssignmentHints({"jwt-secret-hint1", "jwt-secret-hint2", "jwt-secret-hint3"})
 public class JWTSecretKeyEndpoint extends AssignmentEndpoint {
 
-    public static final String[] SECRETS = {"victory", "business", "available", "shipping", "washington"};
-    public static final String JWT_SECRET = TextCodec.BASE64.encode(SECRETS[new Random().nextInt(SECRETS.length)]);
-    private static final String WEBGOAT_USER = "WebGoat";
-    private static final List expectedClaims = List.of("iss", "iat", "exp", "aud", "sub", "username", "Email", "Role");
+  public static final String[] SECRETS = {
+    "victory", "business", "available", "shipping", "washington"
+  };
+  public static final String JWT_SECRET =
+      TextCodec.BASE64.encode(SECRETS[new Random().nextInt(SECRETS.length)]);
+  private static final String WEBGOAT_USER = "WebGoat";
+  private static final List expectedClaims =
+      List.of("iss", "iat", "exp", "aud", "sub", "username", "Email", "Role");
 
-    @RequestMapping(path = "/JWT/secret/gettoken", produces = MediaType.TEXT_HTML_VALUE)
-    @ResponseBody
-    public String getSecretToken() {
-        return Jwts.builder()
-                .setIssuer("WebGoat Token Builder")
-                .setAudience("webgoat.org")
-                .setIssuedAt(Calendar.getInstance().getTime())
-                .setExpiration(Date.from(Instant.now().plusSeconds(60)))
-                .setSubject("tom@webgoat.org")
-                .claim("username", "Tom")
-                .claim("Email", "tom@webgoat.org")
-                .claim("Role", new String[]{"Manager", "Project Administrator"})
-                .signWith(SignatureAlgorithm.HS256, JWT_SECRET).compact();
-    }
+  @RequestMapping(path = "/JWT/secret/gettoken", produces = MediaType.TEXT_HTML_VALUE)
+  @ResponseBody
+  public String getSecretToken() {
+    return Jwts.builder()
+        .setIssuer("WebGoat Token Builder")
+        .setAudience("webgoat.org")
+        .setIssuedAt(Calendar.getInstance().getTime())
+        .setExpiration(Date.from(Instant.now().plusSeconds(60)))
+        .setSubject("tom@webgoat.org")
+        .claim("username", "Tom")
+        .claim("Email", "tom@webgoat.org")
+        .claim("Role", new String[] {"Manager", "Project Administrator"})
+        .signWith(SignatureAlgorithm.HS256, JWT_SECRET)
+        .compact();
+  }
 
-    @PostMapping("/JWT/secret")
-    @ResponseBody
-    public AttackResult login(@RequestParam String token) {
-        try {
-            Jwt jwt = Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token);
-            Claims claims = (Claims) jwt.getBody();
-            if (!claims.keySet().containsAll(expectedClaims)) {
-                return failed(this).feedback("jwt-secret-claims-missing").build();
-            } else {
-                String user = (String) claims.get("username");
+  @PostMapping("/JWT/secret")
+  @ResponseBody
+  public AttackResult login(@RequestParam String token) {
+    try {
+      Jwt jwt = Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJws(token);
+      Claims claims = (Claims) jwt.getBody();
+      if (!claims.keySet().containsAll(expectedClaims)) {
+        return failed(this).feedback("jwt-secret-claims-missing").build();
+      } else {
+        String user = (String) claims.get("username");
 
-                if (WEBGOAT_USER.equalsIgnoreCase(user)) {
-                    return success(this).build();
-                } else {
-                    return failed(this).feedback("jwt-secret-incorrect-user").feedbackArgs(user).build();
-                }
-            }
-        } catch (Exception e) {
-            return failed(this).feedback("jwt-invalid-token").output(e.getMessage()).build();
+        if (WEBGOAT_USER.equalsIgnoreCase(user)) {
+          return success(this).build();
+        } else {
+          return failed(this).feedback("jwt-secret-incorrect-user").feedbackArgs(user).build();
         }
+      }
+    } catch (Exception e) {
+      return failed(this).feedback("jwt-invalid-token").output(e.getMessage()).build();
     }
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTVotesEndpoint.java b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTVotesEndpoint.java
index c0afdb69f..632449822 100644
--- a/src/main/java/org/owasp/webgoat/lessons/jwt/JWTVotesEndpoint.java
+++ b/src/main/java/org/owasp/webgoat/lessons/jwt/JWTVotesEndpoint.java
@@ -22,11 +22,23 @@
 
 package org.owasp.webgoat.lessons.jwt;
 
+import static java.util.Comparator.comparingLong;
+import static java.util.Optional.ofNullable;
+import static java.util.stream.Collectors.toList;
+
 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.Jwt;
 import io.jsonwebtoken.JwtException;
 import io.jsonwebtoken.Jwts;
 import io.jsonwebtoken.impl.TextCodec;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.StringUtils;
 import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
 import org.owasp.webgoat.container.assignments.AssignmentHints;
@@ -46,139 +58,164 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.ResponseStatus;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.annotation.PostConstruct;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-
-import static java.util.Comparator.comparingLong;
-import static java.util.Optional.ofNullable;
-import static java.util.stream.Collectors.toList;
-
 /**
  * @author nbaars
  * @since 4/23/17.
  */
 @RestController
-@AssignmentHints({"jwt-change-token-hint1", "jwt-change-token-hint2", "jwt-change-token-hint3", "jwt-change-token-hint4", "jwt-change-token-hint5"})
+@AssignmentHints({
+  "jwt-change-token-hint1",
+  "jwt-change-token-hint2",
+  "jwt-change-token-hint3",
+  "jwt-change-token-hint4",
+  "jwt-change-token-hint5"
+})
 public class JWTVotesEndpoint extends AssignmentEndpoint {
 
-    public static final String JWT_PASSWORD = TextCodec.BASE64.encode("victory");
-    private static String validUsers = "TomJerrySylvester";
+  public static final String JWT_PASSWORD = TextCodec.BASE64.encode("victory");
+  private static String validUsers = "TomJerrySylvester";
 
-    private static int totalVotes = 38929;
-    private Map votes = new HashMap<>();
+  private static int totalVotes = 38929;
+  private Map votes = new HashMap<>();
 
-    @PostConstruct
-    public void initVotes() {
-        votes.put("Admin lost password", new Vote("Admin lost password",
-                "In this challenge you will need to help the admin and find the password in order to login",
-                "challenge1-small.png", "challenge1.png", 36000, totalVotes));
-        votes.put("Vote for your favourite",
-                new Vote("Vote for your favourite",
-                        "In this challenge ...",
-                        "challenge5-small.png", "challenge5.png", 30000, totalVotes));
-        votes.put("Get it for free",
-                new Vote("Get it for free",
-                        "The objective for this challenge is to buy a Samsung phone for free.",
-                        "challenge2-small.png", "challenge2.png", 20000, totalVotes));
-        votes.put("Photo comments",
-                new Vote("Photo comments",
-                        "n this challenge you can comment on the photo you will need to find the flag somewhere.",
-                        "challenge3-small.png", "challenge3.png", 10000, totalVotes));
+  @PostConstruct
+  public void initVotes() {
+    votes.put(
+        "Admin lost password",
+        new Vote(
+            "Admin lost password",
+            "In this challenge you will need to help the admin and find the password in order to"
+                + " login",
+            "challenge1-small.png",
+            "challenge1.png",
+            36000,
+            totalVotes));
+    votes.put(
+        "Vote for your favourite",
+        new Vote(
+            "Vote for your favourite",
+            "In this challenge ...",
+            "challenge5-small.png",
+            "challenge5.png",
+            30000,
+            totalVotes));
+    votes.put(
+        "Get it for free",
+        new Vote(
+            "Get it for free",
+            "The objective for this challenge is to buy a Samsung phone for free.",
+            "challenge2-small.png",
+            "challenge2.png",
+            20000,
+            totalVotes));
+    votes.put(
+        "Photo comments",
+        new Vote(
+            "Photo comments",
+            "n this challenge you can comment on the photo you will need to find the flag"
+                + " somewhere.",
+            "challenge3-small.png",
+            "challenge3.png",
+            10000,
+            totalVotes));
+  }
+
+  @GetMapping("/JWT/votings/login")
+  public void login(@RequestParam("user") String user, HttpServletResponse response) {
+    if (validUsers.contains(user)) {
+      Claims claims = Jwts.claims().setIssuedAt(Date.from(Instant.now().plus(Duration.ofDays(10))));
+      claims.put("admin", "false");
+      claims.put("user", user);
+      String token =
+          Jwts.builder()
+              .setClaims(claims)
+              .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD)
+              .compact();
+      Cookie cookie = new Cookie("access_token", token);
+      response.addCookie(cookie);
+      response.setStatus(HttpStatus.OK.value());
+      response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+    } else {
+      Cookie cookie = new Cookie("access_token", "");
+      response.addCookie(cookie);
+      response.setStatus(HttpStatus.UNAUTHORIZED.value());
+      response.setContentType(MediaType.APPLICATION_JSON_VALUE);
     }
+  }
 
-    @GetMapping("/JWT/votings/login")
-    public void login(@RequestParam("user") String user, HttpServletResponse response) {
-        if (validUsers.contains(user)) {
-            Claims claims = Jwts.claims().setIssuedAt(Date.from(Instant.now().plus(Duration.ofDays(10))));
-            claims.put("admin", "false");
-            claims.put("user", user);
-            String token = Jwts.builder()
-                    .setClaims(claims)
-                    .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD)
-                    .compact();
-            Cookie cookie = new Cookie("access_token", token);
-            response.addCookie(cookie);
-            response.setStatus(HttpStatus.OK.value());
-            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+  @GetMapping("/JWT/votings")
+  @ResponseBody
+  public MappingJacksonValue getVotes(
+      @CookieValue(value = "access_token", required = false) String accessToken) {
+    MappingJacksonValue value =
+        new MappingJacksonValue(
+            votes.values().stream()
+                .sorted(comparingLong(Vote::getAverage).reversed())
+                .collect(toList()));
+    if (StringUtils.isEmpty(accessToken)) {
+      value.setSerializationView(Views.GuestView.class);
+    } else {
+      try {
+        Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
+        Claims claims = (Claims) jwt.getBody();
+        String user = (String) claims.get("user");
+        if ("Guest".equals(user) || !validUsers.contains(user)) {
+          value.setSerializationView(Views.GuestView.class);
         } else {
-            Cookie cookie = new Cookie("access_token", "");
-            response.addCookie(cookie);
-            response.setStatus(HttpStatus.UNAUTHORIZED.value());
-            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+          value.setSerializationView(Views.UserView.class);
         }
+      } catch (JwtException e) {
+        value.setSerializationView(Views.GuestView.class);
+      }
     }
+    return value;
+  }
 
-    @GetMapping("/JWT/votings")
-    @ResponseBody
-    public MappingJacksonValue getVotes(@CookieValue(value = "access_token", required = false) String accessToken) {
-        MappingJacksonValue value = new MappingJacksonValue(votes.values().stream().sorted(comparingLong(Vote::getAverage).reversed()).collect(toList()));
-        if (StringUtils.isEmpty(accessToken)) {
-            value.setSerializationView(Views.GuestView.class);
+  @PostMapping(value = "/JWT/votings/{title}")
+  @ResponseBody
+  @ResponseStatus(HttpStatus.ACCEPTED)
+  public ResponseEntity vote(
+      @PathVariable String title,
+      @CookieValue(value = "access_token", required = false) String accessToken) {
+    if (StringUtils.isEmpty(accessToken)) {
+      return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+    } else {
+      try {
+        Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
+        Claims claims = (Claims) jwt.getBody();
+        String user = (String) claims.get("user");
+        if (!validUsers.contains(user)) {
+          return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
         } else {
-            try {
-                Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
-                Claims claims = (Claims) jwt.getBody();
-                String user = (String) claims.get("user");
-                if ("Guest".equals(user) || !validUsers.contains(user)) {
-                    value.setSerializationView(Views.GuestView.class);
-                } else {
-                    value.setSerializationView(Views.UserView.class);
-                }
-            } catch (JwtException e) {
-                value.setSerializationView(Views.GuestView.class);
-            }
+          ofNullable(votes.get(title)).ifPresent(v -> v.incrementNumberOfVotes(totalVotes));
+          return ResponseEntity.accepted().build();
         }
-        return value;
+      } catch (JwtException e) {
+        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+      }
     }
+  }
 
-    @PostMapping(value = "/JWT/votings/{title}")
-    @ResponseBody
-    @ResponseStatus(HttpStatus.ACCEPTED)
-    public ResponseEntity vote(@PathVariable String title, @CookieValue(value = "access_token", required = false) String accessToken) {
-        if (StringUtils.isEmpty(accessToken)) {
-            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
+  @PostMapping("/JWT/votings")
+  @ResponseBody
+  public AttackResult resetVotes(
+      @CookieValue(value = "access_token", required = false) String accessToken) {
+    if (StringUtils.isEmpty(accessToken)) {
+      return failed(this).feedback("jwt-invalid-token").build();
+    } else {
+      try {
+        Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
+        Claims claims = (Claims) jwt.getBody();
+        boolean isAdmin = Boolean.valueOf(String.valueOf(claims.get("admin")));
+        if (!isAdmin) {
+          return failed(this).feedback("jwt-only-admin").build();
         } else {
-            try {
-                Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
-                Claims claims = (Claims) jwt.getBody();
-                String user = (String) claims.get("user");
-                if (!validUsers.contains(user)) {
-                    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-                } else {
-                    ofNullable(votes.get(title)).ifPresent(v -> v.incrementNumberOfVotes(totalVotes));
-                    return ResponseEntity.accepted().build();
-                }
-            } catch (JwtException e) {
-                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
-            }
-        }
-    }
-
-    @PostMapping("/JWT/votings")
-    @ResponseBody
-    public AttackResult resetVotes(@CookieValue(value = "access_token", required = false) String accessToken) {
-        if (StringUtils.isEmpty(accessToken)) {
-            return failed(this).feedback("jwt-invalid-token").build();
-        } else {
-            try {
-                Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
-                Claims claims = (Claims) jwt.getBody();
-                boolean isAdmin = Boolean.valueOf(String.valueOf(claims.get("admin")));
-                if (!isAdmin) {
-                    return failed(this).feedback("jwt-only-admin").build();
-                } else {
-                    votes.values().forEach(vote -> vote.reset());
-                    return success(this).build();
-                }
-            } catch (JwtException e) {
-                return failed(this).feedback("jwt-invalid-token").output(e.toString()).build();
-            }
+          votes.values().forEach(vote -> vote.reset());
+          return success(this).build();
         }
+      } catch (JwtException e) {
+        return failed(this).feedback("jwt-invalid-token").output(e.toString()).build();
+      }
     }
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/votes/Views.java b/src/main/java/org/owasp/webgoat/lessons/jwt/votes/Views.java
index ced070830..cc600318c 100644
--- a/src/main/java/org/owasp/webgoat/lessons/jwt/votes/Views.java
+++ b/src/main/java/org/owasp/webgoat/lessons/jwt/votes/Views.java
@@ -5,9 +5,7 @@ package org.owasp.webgoat.lessons.jwt.votes;
  * @since 4/30/17.
  */
 public class Views {
-    public interface GuestView {
-    }
+  public interface GuestView {}
 
-    public interface UserView extends GuestView {
-    }
+  public interface UserView extends GuestView {}
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/jwt/votes/Vote.java b/src/main/java/org/owasp/webgoat/lessons/jwt/votes/Vote.java
index 5e82bb362..2d065df53 100644
--- a/src/main/java/org/owasp/webgoat/lessons/jwt/votes/Vote.java
+++ b/src/main/java/org/owasp/webgoat/lessons/jwt/votes/Vote.java
@@ -31,42 +31,53 @@ import lombok.Getter;
  */
 @Getter
 public class Vote {
-    @JsonView(Views.GuestView.class)
-    private final String title;
-    @JsonView(Views.GuestView.class)
-    private final String information;
-    @JsonView(Views.GuestView.class)
-    private final String imageSmall;
-    @JsonView(Views.GuestView.class)
-    private final String imageBig;
-    @JsonView(Views.UserView.class)
-    private int numberOfVotes;
-    @JsonView(Views.UserView.class)
-    private boolean votingAllowed = true;
-    @JsonView(Views.UserView.class)
-    private long average = 0;
+  @JsonView(Views.GuestView.class)
+  private final String title;
 
+  @JsonView(Views.GuestView.class)
+  private final String information;
 
-    public Vote(String title, String information, String imageSmall, String imageBig, int numberOfVotes, int totalVotes) {
-        this.title = title;
-        this.information = information;
-        this.imageSmall = imageSmall;
-        this.imageBig = imageBig;
-        this.numberOfVotes = numberOfVotes;
-        this.average = calculateStars(totalVotes);
-    }
+  @JsonView(Views.GuestView.class)
+  private final String imageSmall;
 
-    public void incrementNumberOfVotes(int totalVotes) {
-        this.numberOfVotes = this.numberOfVotes + 1;
-        this.average = calculateStars(totalVotes);
-    }
+  @JsonView(Views.GuestView.class)
+  private final String imageBig;
 
-    public void reset() {
-        this.numberOfVotes = 1;
-        this.average = 1;
-    }
+  @JsonView(Views.UserView.class)
+  private int numberOfVotes;
 
-    private long calculateStars(int totalVotes) {
-        return Math.round(((double) numberOfVotes / (double) totalVotes) * 4);
-    }
+  @JsonView(Views.UserView.class)
+  private boolean votingAllowed = true;
+
+  @JsonView(Views.UserView.class)
+  private long average = 0;
+
+  public Vote(
+      String title,
+      String information,
+      String imageSmall,
+      String imageBig,
+      int numberOfVotes,
+      int totalVotes) {
+    this.title = title;
+    this.information = information;
+    this.imageSmall = imageSmall;
+    this.imageBig = imageBig;
+    this.numberOfVotes = numberOfVotes;
+    this.average = calculateStars(totalVotes);
+  }
+
+  public void incrementNumberOfVotes(int totalVotes) {
+    this.numberOfVotes = this.numberOfVotes + 1;
+    this.average = calculateStars(totalVotes);
+  }
+
+  public void reset() {
+    this.numberOfVotes = 1;
+    this.average = 1;
+  }
+
+  private long calculateStars(int totalVotes) {
+    return Math.round(((double) numberOfVotes / (double) totalVotes) * 4);
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/lessontemplate/LessonTemplate.java b/src/main/java/org/owasp/webgoat/lessons/lessontemplate/LessonTemplate.java
index 9d6024cb8..20fd1f293 100644
--- a/src/main/java/org/owasp/webgoat/lessons/lessontemplate/LessonTemplate.java
+++ b/src/main/java/org/owasp/webgoat/lessons/lessontemplate/LessonTemplate.java
@@ -29,13 +29,13 @@ import org.springframework.stereotype.Component;
 @Component
 public class LessonTemplate extends Lesson {
 
-    @Override
-    public Category getDefaultCategory() {
-        return Category.GENERAL;
-    }
+  @Override
+  public Category getDefaultCategory() {
+    return Category.GENERAL;
+  }
 
-    @Override
-    public String getTitle() {
-        return "lesson-template.title";
-    }
+  @Override
+  public String getTitle() {
+    return "lesson-template.title";
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/lessontemplate/SampleAttack.java b/src/main/java/org/owasp/webgoat/lessons/lessontemplate/SampleAttack.java
index 8bdfabd17..22a028490 100644
--- a/src/main/java/org/owasp/webgoat/lessons/lessontemplate/SampleAttack.java
+++ b/src/main/java/org/owasp/webgoat/lessons/lessontemplate/SampleAttack.java
@@ -22,6 +22,7 @@
 
 package org.owasp.webgoat.lessons.lessontemplate;
 
+import java.util.List;
 import lombok.AllArgsConstructor;
 import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
 import org.owasp.webgoat.container.assignments.AssignmentHints;
@@ -35,56 +36,56 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.List;
-
-/**
- * Created by jason on 1/5/17.
- */
-
+/** Created by jason on 1/5/17. */
 @RestController
 @AssignmentHints({"lesson-template.hints.1", "lesson-template.hints.2", "lesson-template.hints.3"})
 public class SampleAttack extends AssignmentEndpoint {
 
-    String secretValue = "secr37Value";
+  String secretValue = "secr37Value";
 
-    //UserSessionData is bound to session and can be used to persist data across multiple assignments
-    @Autowired
-    UserSessionData userSessionData;
+  // UserSessionData is bound to session and can be used to persist data across multiple assignments
+  @Autowired UserSessionData userSessionData;
 
-    @PostMapping("/lesson-template/sample-attack")
-    @ResponseBody
-    public AttackResult completed(@RequestParam("param1") String param1, @RequestParam("param2") String param2) {
-        if (userSessionData.getValue("some-value") != null) {
-            // do any session updating you want here ... or not, just comment/example here
-            //return failed().feedback("lesson-template.sample-attack.failure-2").build());
-        }
-
-        //overly simple example for success. See other existing lesssons for ways to detect 'success' or 'failure'
-        if (secretValue.equals(param1)) {
-            return success(this)
-                    .output("Custom Output ...if you want, for success")
-                    .feedback("lesson-template.sample-attack.success")
-                    .build();
-            //lesson-template.sample-attack.success is defined in src/main/resources/i18n/WebGoatLabels.properties
-        }
-
-        // else
-        return failed(this)
-                .feedback("lesson-template.sample-attack.failure-2")
-                .output("Custom output for this failure scenario, usually html that will get rendered directly ... yes, you can self-xss if you want")
-                .build();
+  @PostMapping("/lesson-template/sample-attack")
+  @ResponseBody
+  public AttackResult completed(
+      @RequestParam("param1") String param1, @RequestParam("param2") String param2) {
+    if (userSessionData.getValue("some-value") != null) {
+      // do any session updating you want here ... or not, just comment/example here
+      // return failed().feedback("lesson-template.sample-attack.failure-2").build());
     }
 
-    @GetMapping("lesson-template/shop/{user}")
-    @ResponseBody
-    public List getItemsInBasket(@PathVariable("user") String user) {
-        return List.of(new Item("WG-1", "WebGoat promo", 12.0), new Item("WG-2", "WebGoat sticker", 0.00));
+    // overly simple example for success. See other existing lesssons for ways to detect 'success'
+    // or 'failure'
+    if (secretValue.equals(param1)) {
+      return success(this)
+          .output("Custom Output ...if you want, for success")
+          .feedback("lesson-template.sample-attack.success")
+          .build();
+      // lesson-template.sample-attack.success is defined in
+      // src/main/resources/i18n/WebGoatLabels.properties
     }
 
-    @AllArgsConstructor
-    private class Item {
-        private String number;
-        private String description;
-        private double price;
-    }
+    // else
+    return failed(this)
+        .feedback("lesson-template.sample-attack.failure-2")
+        .output(
+            "Custom output for this failure scenario, usually html that will get rendered directly"
+                + " ... yes, you can self-xss if you want")
+        .build();
+  }
+
+  @GetMapping("lesson-template/shop/{user}")
+  @ResponseBody
+  public List getItemsInBasket(@PathVariable("user") String user) {
+    return List.of(
+        new Item("WG-1", "WebGoat promo", 12.0), new Item("WG-2", "WebGoat sticker", 0.00));
+  }
+
+  @AllArgsConstructor
+  private class Item {
+    private String number;
+    private String description;
+    private double price;
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/logging/LogBleedingTask.java b/src/main/java/org/owasp/webgoat/lessons/logging/LogBleedingTask.java
index 54b1e6925..710f22f1a 100644
--- a/src/main/java/org/owasp/webgoat/lessons/logging/LogBleedingTask.java
+++ b/src/main/java/org/owasp/webgoat/lessons/logging/LogBleedingTask.java
@@ -22,6 +22,10 @@
 
 package org.owasp.webgoat.lessons.logging;
 
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.UUID;
+import javax.annotation.PostConstruct;
 import org.apache.logging.log4j.util.Strings;
 import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
 import org.owasp.webgoat.container.assignments.AttackResult;
@@ -32,35 +36,31 @@ import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
-import javax.annotation.PostConstruct;
-import java.util.Base64;
-
-import java.nio.charset.StandardCharsets;
-import java.util.UUID;
-
 @RestController
 public class LogBleedingTask extends AssignmentEndpoint {
 
-    Logger log = LoggerFactory.getLogger(this.getClass().getName());
-    private String password;
+  Logger log = LoggerFactory.getLogger(this.getClass().getName());
+  private String password;
 
-    @PostConstruct
-    public void generatePassword(){
-        password = UUID.randomUUID().toString();
-        log.info("Password for admin: {}", Base64.getEncoder().encodeToString(password.getBytes(StandardCharsets.UTF_8)));
+  @PostConstruct
+  public void generatePassword() {
+    password = UUID.randomUUID().toString();
+    log.info(
+        "Password for admin: {}",
+        Base64.getEncoder().encodeToString(password.getBytes(StandardCharsets.UTF_8)));
+  }
+
+  @PostMapping("/LogSpoofing/log-bleeding")
+  @ResponseBody
+  public AttackResult completed(@RequestParam String username, @RequestParam String password) {
+    if (Strings.isEmpty(username) || Strings.isEmpty(password)) {
+      return failed(this).output("Please provide username (Admin) and password").build();
     }
 
-    @PostMapping("/LogSpoofing/log-bleeding")
-    @ResponseBody
-    public AttackResult completed(@RequestParam String username, @RequestParam String password) {
-        if (Strings.isEmpty(username) || Strings.isEmpty(password)) {
-            return failed(this).output("Please provide username (Admin) and password").build();
-        }
-
-        if (username.equals("Admin") && password.equals(this.password)) {
-            return success(this).build();
-        }
-
-        return failed(this).build();
+    if (username.equals("Admin") && password.equals(this.password)) {
+      return success(this).build();
     }
+
+    return failed(this).build();
+  }
 }
diff --git a/src/main/java/org/owasp/webgoat/lessons/logging/LogSpoofing.java b/src/main/java/org/owasp/webgoat/lessons/logging/LogSpoofing.java
index ec5c814fb..b92d05572 100644
--- a/src/main/java/org/owasp/webgoat/lessons/logging/LogSpoofing.java
+++ b/src/main/java/org/owasp/webgoat/lessons/logging/LogSpoofing.java
@@ -8,25 +8,26 @@ import org.springframework.stereotype.Component;
  * ************************************************************************************************
  * This file is part of WebGoat, an Open Web Application Security Project utility. For details,
  * please see http://www.owasp.org/
- * 

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -35,13 +36,13 @@ import org.springframework.stereotype.Component; */ @Component public class LogSpoofing extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A9; - } + @Override + public Category getDefaultCategory() { + return Category.A9; + } - @Override - public String getTitle() { - return "logging.title"; - } + @Override + public String getTitle() { + return "logging.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/logging/LogSpoofingTask.java b/src/main/java/org/owasp/webgoat/lessons/logging/LogSpoofingTask.java index c521e12b5..0fe3b3559 100644 --- a/src/main/java/org/owasp/webgoat/lessons/logging/LogSpoofingTask.java +++ b/src/main/java/org/owasp/webgoat/lessons/logging/LogSpoofingTask.java @@ -33,19 +33,19 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class LogSpoofingTask extends AssignmentEndpoint { - @PostMapping("/LogSpoofing/log-spoofing") - @ResponseBody - public AttackResult completed(@RequestParam String username, @RequestParam String password) { - if (Strings.isEmpty(username)) { - return failed(this).output(username).build(); - } - username = username.replace("\n", "
"); - if (username.contains("

") || username.contains("

")) { - return failed(this).output("Try to think of something simple ").build(); - } - if (username.indexOf("
") < username.indexOf("admin")) { - return success(this).output(username).build(); - } - return failed(this).output(username).build(); + @PostMapping("/LogSpoofing/log-spoofing") + @ResponseBody + public AttackResult completed(@RequestParam String username, @RequestParam String password) { + if (Strings.isEmpty(username)) { + return failed(this).output(username).build(); } + username = username.replace("\n", "
"); + if (username.contains("

") || username.contains("

")) { + return failed(this).output("Try to think of something simple ").build(); + } + if (username.indexOf("
") < username.indexOf("admin")) { + return success(this).output(username).build(); + } + return failed(this).output(username).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/missingac/DisplayUser.java b/src/main/java/org/owasp/webgoat/lessons/missingac/DisplayUser.java index f474dce5d..90eb06c8d 100644 --- a/src/main/java/org/owasp/webgoat/lessons/missingac/DisplayUser.java +++ b/src/main/java/org/owasp/webgoat/lessons/missingac/DisplayUser.java @@ -1,62 +1,62 @@ package org.owasp.webgoat.lessons.missingac; -import lombok.Getter; - import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.Base64; +import lombok.Getter; /** * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

*/ @Getter public class DisplayUser { - //intended to provide a display version of WebGoatUser for admins to view user attributes + // intended to provide a display version of WebGoatUser for admins to view user attributes - private String username; - private boolean admin; - private String userHash; + private String username; + private boolean admin; + private String userHash; - public DisplayUser(User user, String passwordSalt) { - this.username = user.getUsername(); - this.admin = user.isAdmin(); + public DisplayUser(User user, String passwordSalt) { + this.username = user.getUsername(); + this.admin = user.isAdmin(); - try { - this.userHash = genUserHash(user.getUsername(), user.getPassword(), passwordSalt); - } catch (Exception ex) { - this.userHash = "Error generating user hash"; - } - } - - protected String genUserHash(String username, String password, String passwordSalt) throws Exception { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - // salting is good, but static & too predictable ... short too for a salt - String salted = password + passwordSalt + username; - //md.update(salted.getBytes("UTF-8")); // Change this to "UTF-16" if needed - byte[] hash = md.digest(salted.getBytes(StandardCharsets.UTF_8)); - return Base64.getEncoder().encodeToString(hash); + try { + this.userHash = genUserHash(user.getUsername(), user.getPassword(), passwordSalt); + } catch (Exception ex) { + this.userHash = "Error generating user hash"; } + } + protected String genUserHash(String username, String password, String passwordSalt) + throws Exception { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + // salting is good, but static & too predictable ... short too for a salt + String salted = password + passwordSalt + username; + // md.update(salted.getBytes("UTF-8")); // Change this to "UTF-16" if needed + byte[] hash = md.digest(salted.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(hash); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingAccessControlUserRepository.java b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingAccessControlUserRepository.java index 7c0615e6e..584542928 100644 --- a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingAccessControlUserRepository.java +++ b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingAccessControlUserRepository.java @@ -1,5 +1,6 @@ package org.owasp.webgoat.lessons.missingac; +import java.util.List; import org.owasp.webgoat.container.LessonDataSource; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; @@ -7,39 +8,42 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.List; - @Component public class MissingAccessControlUserRepository { - private final NamedParameterJdbcTemplate jdbcTemplate; - private final RowMapper mapper = (rs, rowNum) -> new User(rs.getString("username"), rs.getString("password"), rs.getBoolean("admin")); + private final NamedParameterJdbcTemplate jdbcTemplate; + private final RowMapper mapper = + (rs, rowNum) -> + new User(rs.getString("username"), rs.getString("password"), rs.getBoolean("admin")); - public MissingAccessControlUserRepository(LessonDataSource lessonDataSource) { - this.jdbcTemplate = new NamedParameterJdbcTemplate(lessonDataSource); - } - - public List findAllUsers() { - return jdbcTemplate.query("select username, password, admin from access_control_users", mapper); - } - - public User findByUsername(String username) { - var users = jdbcTemplate.query("select username, password, admin from access_control_users where username=:username", - new MapSqlParameterSource().addValue("username", username), - mapper); - if (CollectionUtils.isEmpty(users)) { - return null; - } - return users.get(0); - } - - public User save(User user) { - jdbcTemplate.update("INSERT INTO access_control_users(username, password, admin) VALUES(:username,:password,:admin)", - new MapSqlParameterSource() - .addValue("username", user.getUsername()) - .addValue("password", user.getPassword()) - .addValue("admin", user.isAdmin())); - return user; + public MissingAccessControlUserRepository(LessonDataSource lessonDataSource) { + this.jdbcTemplate = new NamedParameterJdbcTemplate(lessonDataSource); + } + + public List findAllUsers() { + return jdbcTemplate.query("select username, password, admin from access_control_users", mapper); + } + + public User findByUsername(String username) { + var users = + jdbcTemplate.query( + "select username, password, admin from access_control_users where username=:username", + new MapSqlParameterSource().addValue("username", username), + mapper); + if (CollectionUtils.isEmpty(users)) { + return null; } + return users.get(0); + } + public User save(User user) { + jdbcTemplate.update( + "INSERT INTO access_control_users(username, password, admin)" + + " VALUES(:username,:password,:admin)", + new MapSqlParameterSource() + .addValue("username", user.getUsername()) + .addValue("password", user.getPassword()) + .addValue("admin", user.isAdmin())); + return user; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionAC.java b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionAC.java index 80dd3a676..46323aca2 100644 --- a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionAC.java +++ b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionAC.java @@ -29,16 +29,16 @@ import org.springframework.stereotype.Component; @Component public class MissingFunctionAC extends Lesson { - public static final String PASSWORD_SALT_SIMPLE = "DeliberatelyInsecure1234"; - public static final String PASSWORD_SALT_ADMIN = "DeliberatelyInsecure1235"; + public static final String PASSWORD_SALT_SIMPLE = "DeliberatelyInsecure1234"; + public static final String PASSWORD_SALT_ADMIN = "DeliberatelyInsecure1235"; - @Override - public Category getDefaultCategory() { - return Category.A1; - } + @Override + public Category getDefaultCategory() { + return Category.A1; + } - @Override - public String getTitle() { - return "missing-function-access-control.title"; - } + @Override + public String getTitle() { + return "missing-function-access-control.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACHiddenMenus.java b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACHiddenMenus.java index 1768e532c..8cf11a6fb 100644 --- a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACHiddenMenus.java +++ b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACHiddenMenus.java @@ -29,33 +29,28 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -/** - * Created by jason on 1/5/17. - */ +/** Created by jason on 1/5/17. */ @RestController -@AssignmentHints({"access-control.hidden-menus.hint1","access-control.hidden-menus.hint2","access-control.hidden-menus.hint3"}) +@AssignmentHints({ + "access-control.hidden-menus.hint1", + "access-control.hidden-menus.hint2", + "access-control.hidden-menus.hint3" +}) public class MissingFunctionACHiddenMenus extends AssignmentEndpoint { - @PostMapping(path = "/access-control/hidden-menu", produces = {"application/json"}) - @ResponseBody - public AttackResult completed(String hiddenMenu1, String hiddenMenu2) { - if (hiddenMenu1.equals("Users") && hiddenMenu2.equals("Config")) { - return success(this) - .output("") - .feedback("access-control.hidden-menus.success") - .build(); - } - - if (hiddenMenu1.equals("Config") && hiddenMenu2.equals("Users")) { - return failed(this) - .output("") - .feedback("access-control.hidden-menus.close") - .build(); - } - - return failed(this) - .feedback("access-control.hidden-menus.failure") - .output("") - .build(); + @PostMapping( + path = "/access-control/hidden-menu", + produces = {"application/json"}) + @ResponseBody + public AttackResult completed(String hiddenMenu1, String hiddenMenu2) { + if (hiddenMenu1.equals("Users") && hiddenMenu2.equals("Config")) { + return success(this).output("").feedback("access-control.hidden-menus.success").build(); } + + if (hiddenMenu1.equals("Config") && hiddenMenu2.equals("Users")) { + return failed(this).output("").feedback("access-control.hidden-menus.close").build(); + } + + return failed(this).feedback("access-control.hidden-menus.failure").output("").build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACUsers.java b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACUsers.java index 1e248c64e..0bbf9d68d 100644 --- a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACUsers.java +++ b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACUsers.java @@ -22,6 +22,12 @@ package org.owasp.webgoat.lessons.missingac; +import static org.owasp.webgoat.lessons.missingac.MissingFunctionAC.PASSWORD_SALT_ADMIN; +import static org.owasp.webgoat.lessons.missingac.MissingFunctionAC.PASSWORD_SALT_SIMPLE; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.session.WebSession; @@ -34,70 +40,75 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; -import static org.owasp.webgoat.lessons.missingac.MissingFunctionAC.PASSWORD_SALT_ADMIN; -import static org.owasp.webgoat.lessons.missingac.MissingFunctionAC.PASSWORD_SALT_SIMPLE; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Created by jason on 1/5/17. - */ +/** Created by jason on 1/5/17. */ @Controller @AllArgsConstructor @Slf4j public class MissingFunctionACUsers { - private final MissingAccessControlUserRepository userRepository; - private final WebSession webSession; + private final MissingAccessControlUserRepository userRepository; + private final WebSession webSession; - @GetMapping(path = {"access-control/users"}) - public ModelAndView listUsers() { + @GetMapping(path = {"access-control/users"}) + public ModelAndView listUsers() { - ModelAndView model = new ModelAndView(); - model.setViewName("list_users"); - List allUsers = userRepository.findAllUsers(); - model.addObject("numUsers", allUsers.size()); - //add display user objects in place of direct users - List displayUsers = new ArrayList<>(); - for (User user : allUsers) { - displayUsers.add(new DisplayUser(user, PASSWORD_SALT_SIMPLE)); - } - model.addObject("allUsers", displayUsers); + ModelAndView model = new ModelAndView(); + model.setViewName("list_users"); + List allUsers = userRepository.findAllUsers(); + model.addObject("numUsers", allUsers.size()); + // add display user objects in place of direct users + List displayUsers = new ArrayList<>(); + for (User user : allUsers) { + displayUsers.add(new DisplayUser(user, PASSWORD_SALT_SIMPLE)); + } + model.addObject("allUsers", displayUsers); - return model; + return model; + } + + @GetMapping( + path = {"access-control/users"}, + consumes = "application/json") + @ResponseBody + public ResponseEntity> usersService() { + return ResponseEntity.ok( + userRepository.findAllUsers().stream() + .map(user -> new DisplayUser(user, PASSWORD_SALT_SIMPLE)) + .collect(Collectors.toList())); + } + + @GetMapping( + path = {"access-control/users-admin-fix"}, + consumes = "application/json") + @ResponseBody + public ResponseEntity> usersFixed() { + var currentUser = userRepository.findByUsername(webSession.getUserName()); + if (currentUser != null && currentUser.isAdmin()) { + return ResponseEntity.ok( + userRepository.findAllUsers().stream() + .map(user -> new DisplayUser(user, PASSWORD_SALT_ADMIN)) + .collect(Collectors.toList())); + } + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); + } + + @PostMapping( + path = {"access-control/users", "access-control/users-admin-fix"}, + consumes = "application/json", + produces = "application/json") + @ResponseBody + public User addUser(@RequestBody User newUser) { + try { + userRepository.save(newUser); + return newUser; + } catch (Exception ex) { + log.error("Error creating new User", ex); + return null; } - @GetMapping(path = {"access-control/users"}, consumes = "application/json") - @ResponseBody - public ResponseEntity> usersService() { - return ResponseEntity.ok(userRepository.findAllUsers().stream().map(user -> new DisplayUser(user, PASSWORD_SALT_SIMPLE)).collect(Collectors.toList())); - } + // @RequestMapping(path = {"user/{username}","/"}, method = RequestMethod.DELETE, consumes = + // "application/json", produces = "application/json") + // TODO implement delete method with id param and authorization - @GetMapping(path = {"access-control/users-admin-fix"}, consumes = "application/json") - @ResponseBody - public ResponseEntity> usersFixed() { - var currentUser = userRepository.findByUsername(webSession.getUserName()); - if (currentUser != null && currentUser.isAdmin()) { - return ResponseEntity.ok(userRepository.findAllUsers().stream().map(user -> new DisplayUser(user, PASSWORD_SALT_ADMIN)).collect(Collectors.toList())); - } - return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); - } - - @PostMapping(path = {"access-control/users", "access-control/users-admin-fix"}, consumes = "application/json", produces = "application/json") - @ResponseBody - public User addUser(@RequestBody User newUser) { - try { - userRepository.save(newUser); - return newUser; - } catch (Exception ex) { - log.error("Error creating new User", ex); - return null; - } - - //@RequestMapping(path = {"user/{username}","/"}, method = RequestMethod.DELETE, consumes = "application/json", produces = "application/json") - //TODO implement delete method with id param and authorization - - } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHash.java b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHash.java index 043fe905a..8417ae059 100644 --- a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHash.java +++ b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHash.java @@ -22,10 +22,9 @@ package org.owasp.webgoat.lessons.missingac; -import lombok.RequiredArgsConstructor; - import static org.owasp.webgoat.lessons.missingac.MissingFunctionAC.PASSWORD_SALT_SIMPLE; +import lombok.RequiredArgsConstructor; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -34,22 +33,29 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController -@AssignmentHints({"access-control.hash.hint1", "access-control.hash.hint2", "access-control.hash.hint3", "access-control.hash.hint4", "access-control.hash.hint5"}) +@AssignmentHints({ + "access-control.hash.hint1", + "access-control.hash.hint2", + "access-control.hash.hint3", + "access-control.hash.hint4", + "access-control.hash.hint5" +}) @RequiredArgsConstructor public class MissingFunctionACYourHash extends AssignmentEndpoint { - private final MissingAccessControlUserRepository userRepository; + private final MissingAccessControlUserRepository userRepository; - - @PostMapping(path = "/access-control/user-hash", produces = {"application/json"}) - @ResponseBody - public AttackResult simple(String userHash) { - User user = userRepository.findByUsername("Jerry"); - DisplayUser displayUser = new DisplayUser(user, PASSWORD_SALT_SIMPLE); - if (userHash.equals(displayUser.getUserHash())) { - return success(this).feedback("access-control.hash.success").build(); - } else { - return failed(this).build(); - } + @PostMapping( + path = "/access-control/user-hash", + produces = {"application/json"}) + @ResponseBody + public AttackResult simple(String userHash) { + User user = userRepository.findByUsername("Jerry"); + DisplayUser displayUser = new DisplayUser(user, PASSWORD_SALT_SIMPLE); + if (userHash.equals(displayUser.getUserHash())) { + return success(this).feedback("access-control.hash.success").build(); + } else { + return failed(this).build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHashAdmin.java b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHashAdmin.java index 80c8d185b..52f9dbcb4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHashAdmin.java +++ b/src/main/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHashAdmin.java @@ -32,29 +32,37 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController -@AssignmentHints({"access-control.hash.hint6", "access-control.hash.hint7", - "access-control.hash.hint8", "access-control.hash.hint9", "access-control.hash.hint10", "access-control.hash.hint11", "access-control.hash.hint12"}) +@AssignmentHints({ + "access-control.hash.hint6", + "access-control.hash.hint7", + "access-control.hash.hint8", + "access-control.hash.hint9", + "access-control.hash.hint10", + "access-control.hash.hint11", + "access-control.hash.hint12" +}) public class MissingFunctionACYourHashAdmin extends AssignmentEndpoint { - private final MissingAccessControlUserRepository userRepository; + private final MissingAccessControlUserRepository userRepository; - public MissingFunctionACYourHashAdmin(MissingAccessControlUserRepository userRepository) { - this.userRepository = userRepository; + public MissingFunctionACYourHashAdmin(MissingAccessControlUserRepository userRepository) { + this.userRepository = userRepository; + } + + @PostMapping( + path = "/access-control/user-hash-fix", + produces = {"application/json"}) + @ResponseBody + public AttackResult admin(String userHash) { + // current user should be in the DB + // if not admin then return 403 + + var user = userRepository.findByUsername("Jerry"); + var displayUser = new DisplayUser(user, PASSWORD_SALT_ADMIN); + if (userHash.equals(displayUser.getUserHash())) { + return success(this).feedback("access-control.hash.success").build(); + } else { + return failed(this).feedback("access-control.hash.close").build(); } - - @PostMapping(path = "/access-control/user-hash-fix", produces = {"application/json"}) - @ResponseBody - public AttackResult admin(String userHash) { - //current user should be in the DB - //if not admin then return 403 - - var user = userRepository.findByUsername("Jerry"); - var displayUser = new DisplayUser(user, PASSWORD_SALT_ADMIN); - if (userHash.equals(displayUser.getUserHash())) { - return success(this).feedback("access-control.hash.success").build(); - } else { - return failed(this).feedback("access-control.hash.close").build(); - } - } - + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/missingac/User.java b/src/main/java/org/owasp/webgoat/lessons/missingac/User.java index f5b8161f7..d7e23c887 100644 --- a/src/main/java/org/owasp/webgoat/lessons/missingac/User.java +++ b/src/main/java/org/owasp/webgoat/lessons/missingac/User.java @@ -9,7 +9,7 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class User { - private String username; - private String password; - private boolean admin; + private String username; + private String password; + private boolean admin; } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/PasswordReset.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/PasswordReset.java index eea060533..79cc05120 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/PasswordReset.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/PasswordReset.java @@ -28,13 +28,13 @@ import org.springframework.stereotype.Component; @Component public class PasswordReset extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A7; - } + @Override + public Category getDefaultCategory() { + return Category.A7; + } - @Override - public String getTitle() { - return "password-reset.title"; - } + @Override + public String getTitle() { + return "password-reset.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/PasswordResetEmail.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/PasswordResetEmail.java index 7f21050dc..ef1f723a5 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/PasswordResetEmail.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/PasswordResetEmail.java @@ -22,19 +22,18 @@ package org.owasp.webgoat.lessons.passwordreset; -import lombok.Builder; -import lombok.Data; - import java.io.Serializable; import java.time.LocalDateTime; +import lombok.Builder; +import lombok.Data; @Builder @Data public class PasswordResetEmail implements Serializable { - private LocalDateTime time; - private String contents; - private String sender; - private String title; - private String recipient; + private LocalDateTime time; + private String contents; + private String sender; + private String title; + private String recipient; } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/QuestionsAssignment.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/QuestionsAssignment.java index 88ac80fff..8568b97ec 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/QuestionsAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/QuestionsAssignment.java @@ -22,6 +22,8 @@ package org.owasp.webgoat.lessons.passwordreset; +import java.util.HashMap; +import java.util.Map; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.http.MediaType; @@ -30,9 +32,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; -import java.util.Map; - /** * @author nbaars * @since 8/20/17. @@ -40,32 +39,37 @@ import java.util.Map; @RestController public class QuestionsAssignment extends AssignmentEndpoint { - private static final Map COLORS = new HashMap<>(); + private static final Map COLORS = new HashMap<>(); - static { - COLORS.put("admin", "green"); - COLORS.put("jerry", "orange"); - COLORS.put("tom", "purple"); - COLORS.put("larry", "yellow"); - COLORS.put("webgoat", "red"); + static { + COLORS.put("admin", "green"); + COLORS.put("jerry", "orange"); + COLORS.put("tom", "purple"); + COLORS.put("larry", "yellow"); + COLORS.put("webgoat", "red"); + } + + @PostMapping( + path = "/PasswordReset/questions", + consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + @ResponseBody + public AttackResult passwordReset(@RequestParam Map json) { + String securityQuestion = (String) json.getOrDefault("securityQuestion", ""); + String username = (String) json.getOrDefault("username", ""); + + if ("webgoat".equalsIgnoreCase(username.toLowerCase())) { + return failed(this).feedback("password-questions-wrong-user").build(); } - @PostMapping(path = "/PasswordReset/questions", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - @ResponseBody - public AttackResult passwordReset(@RequestParam Map json) { - String securityQuestion = (String) json.getOrDefault("securityQuestion", ""); - String username = (String) json.getOrDefault("username", ""); - - if ("webgoat".equalsIgnoreCase(username.toLowerCase())) { - return failed(this).feedback("password-questions-wrong-user").build(); - } - - String validAnswer = COLORS.get(username.toLowerCase()); - if (validAnswer == null) { - return failed(this).feedback("password-questions-unknown-user").feedbackArgs(username).build(); - } else if (validAnswer.equals(securityQuestion)) { - return success(this).build(); - } - return failed(this).build(); + String validAnswer = COLORS.get(username.toLowerCase()); + if (validAnswer == null) { + return failed(this) + .feedback("password-questions-unknown-user") + .feedbackArgs(username) + .build(); + } else if (validAnswer.equals(securityQuestion)) { + return success(this).build(); } + return failed(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/ResetLinkAssignment.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/ResetLinkAssignment.java index d8bfce33d..ace84be78 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/ResetLinkAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/ResetLinkAssignment.java @@ -23,6 +23,10 @@ package org.owasp.webgoat.lessons.passwordreset; import com.google.common.collect.Maps; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -38,94 +42,100 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - /** * @author nbaars * @since 8/20/17. */ @RestController -@AssignmentHints({"password-reset-hint1", "password-reset-hint2", "password-reset-hint3", "password-reset-hint4", "password-reset-hint5", "password-reset-hint6"}) +@AssignmentHints({ + "password-reset-hint1", + "password-reset-hint2", + "password-reset-hint3", + "password-reset-hint4", + "password-reset-hint5", + "password-reset-hint6" +}) public class ResetLinkAssignment extends AssignmentEndpoint { - static final String PASSWORD_TOM_9 = "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom"; - static final String TOM_EMAIL = "tom@webgoat-cloud.org"; - static Map userToTomResetLink = new HashMap<>(); - static Map usersToTomPassword = Maps.newHashMap(); - static List resetLinks = new ArrayList<>(); + static final String PASSWORD_TOM_9 = + "somethingVeryRandomWhichNoOneWillEverTypeInAsPasswordForTom"; + static final String TOM_EMAIL = "tom@webgoat-cloud.org"; + static Map userToTomResetLink = new HashMap<>(); + static Map usersToTomPassword = Maps.newHashMap(); + static List resetLinks = new ArrayList<>(); - static final String TEMPLATE = "Hi, you requested a password reset link, please use this " - + "link to reset your password." - + "\n \n\n" - + "If you did not request this password change you can ignore this message." - + "\n" - + "If you have any comments or questions, please do not hesitate to reach us at support@webgoat-cloud.org" - + "\n\n" - + "Kind regards, \nTeam WebGoat"; + static final String TEMPLATE = + "Hi, you requested a password reset link, please use this link to reset your" + + " password.\n" + + " \n\n" + + "If you did not request this password change you can ignore this message.\n" + + "If you have any comments or questions, please do not hesitate to reach us at" + + " support@webgoat-cloud.org\n\n" + + "Kind regards, \n" + + "Team WebGoat"; - - @PostMapping("/PasswordReset/reset/login") - @ResponseBody - public AttackResult login(@RequestParam String password, @RequestParam String email) { - if (TOM_EMAIL.equals(email)) { - String passwordTom = usersToTomPassword.getOrDefault(getWebSession().getUserName(), PASSWORD_TOM_9); - if (passwordTom.equals(PASSWORD_TOM_9)) { - return failed(this).feedback("login_failed").build(); - } else if (passwordTom.equals(password)) { - return success(this).build(); - } - } - return failed(this).feedback("login_failed.tom").build(); + @PostMapping("/PasswordReset/reset/login") + @ResponseBody + public AttackResult login(@RequestParam String password, @RequestParam String email) { + if (TOM_EMAIL.equals(email)) { + String passwordTom = + usersToTomPassword.getOrDefault(getWebSession().getUserName(), PASSWORD_TOM_9); + if (passwordTom.equals(PASSWORD_TOM_9)) { + return failed(this).feedback("login_failed").build(); + } else if (passwordTom.equals(password)) { + return success(this).build(); + } } + return failed(this).feedback("login_failed.tom").build(); + } - @GetMapping("/PasswordReset/reset/reset-password/{link}") - public ModelAndView resetPassword(@PathVariable(value = "link") String link, Model model) { - ModelAndView modelAndView = new ModelAndView(); - if (ResetLinkAssignment.resetLinks.contains(link)) { - PasswordChangeForm form = new PasswordChangeForm(); - form.setResetLink(link); - model.addAttribute("form", form); - modelAndView.addObject("form", form); - modelAndView.setViewName("password_reset"); //Display html page for changing password - } else { - modelAndView.setViewName("password_link_not_found"); - } - return modelAndView; + @GetMapping("/PasswordReset/reset/reset-password/{link}") + public ModelAndView resetPassword(@PathVariable(value = "link") String link, Model model) { + ModelAndView modelAndView = new ModelAndView(); + if (ResetLinkAssignment.resetLinks.contains(link)) { + PasswordChangeForm form = new PasswordChangeForm(); + form.setResetLink(link); + model.addAttribute("form", form); + modelAndView.addObject("form", form); + modelAndView.setViewName("password_reset"); // Display html page for changing password + } else { + modelAndView.setViewName("password_link_not_found"); } + return modelAndView; + } - @GetMapping("/PasswordReset/reset/change-password") - public ModelAndView illegalCall() { - ModelAndView modelAndView = new ModelAndView(); - modelAndView.setViewName("password_link_not_found"); - return modelAndView; - } - - @PostMapping("/PasswordReset/reset/change-password") - public ModelAndView changePassword(@ModelAttribute("form") PasswordChangeForm form, BindingResult bindingResult) { - ModelAndView modelAndView = new ModelAndView(); - if (!org.springframework.util.StringUtils.hasText(form.getPassword())) { - bindingResult.rejectValue("password", "not.empty"); - } - if (bindingResult.hasErrors()) { - modelAndView.setViewName("password_reset"); - return modelAndView; - } - if (!resetLinks.contains(form.getResetLink())) { - modelAndView.setViewName("password_link_not_found"); - return modelAndView; - } - if (checkIfLinkIsFromTom(form.getResetLink())) { - usersToTomPassword.put(getWebSession().getUserName(), form.getPassword()); - } - modelAndView.setViewName("lessons/passwordreset/templates/success.html"); - return modelAndView; - } + @GetMapping("/PasswordReset/reset/change-password") + public ModelAndView illegalCall() { + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("password_link_not_found"); + return modelAndView; + } - private boolean checkIfLinkIsFromTom(String resetLinkFromForm) { - String resetLink = userToTomResetLink.getOrDefault(getWebSession().getUserName(), "unknown"); - return resetLink.equals(resetLinkFromForm); + @PostMapping("/PasswordReset/reset/change-password") + public ModelAndView changePassword( + @ModelAttribute("form") PasswordChangeForm form, BindingResult bindingResult) { + ModelAndView modelAndView = new ModelAndView(); + if (!org.springframework.util.StringUtils.hasText(form.getPassword())) { + bindingResult.rejectValue("password", "not.empty"); } + if (bindingResult.hasErrors()) { + modelAndView.setViewName("password_reset"); + return modelAndView; + } + if (!resetLinks.contains(form.getResetLink())) { + modelAndView.setViewName("password_link_not_found"); + return modelAndView; + } + if (checkIfLinkIsFromTom(form.getResetLink())) { + usersToTomPassword.put(getWebSession().getUserName(), form.getPassword()); + } + modelAndView.setViewName("lessons/passwordreset/templates/success.html"); + return modelAndView; + } + + private boolean checkIfLinkIsFromTom(String resetLinkFromForm) { + String resetLink = userToTomResetLink.getOrDefault(getWebSession().getUserName(), "unknown"); + return resetLink.equals(resetLinkFromForm); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/ResetLinkAssignmentForgotPassword.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/ResetLinkAssignmentForgotPassword.java index c17529aea..34b8ee856 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/ResetLinkAssignmentForgotPassword.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/ResetLinkAssignmentForgotPassword.java @@ -22,6 +22,8 @@ package org.owasp.webgoat.lessons.passwordreset; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.beans.factory.annotation.Value; @@ -34,9 +36,6 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; -import javax.servlet.http.HttpServletRequest; -import java.util.UUID; - /** * Part of the password reset assignment. Used to send the e-mail. * @@ -46,59 +45,70 @@ import java.util.UUID; @RestController public class ResetLinkAssignmentForgotPassword extends AssignmentEndpoint { - private final RestTemplate restTemplate; - private String webWolfHost; - private String webWolfPort; - private final String webWolfMailURL; + private final RestTemplate restTemplate; + private String webWolfHost; + private String webWolfPort; + private final String webWolfMailURL; - public ResetLinkAssignmentForgotPassword(RestTemplate restTemplate, - @Value("${webwolf.host}") String webWolfHost, - @Value("${webwolf.port}") String webWolfPort, - @Value("${webwolf.mail.url}") String webWolfMailURL) { - this.restTemplate = restTemplate; - this.webWolfHost = webWolfHost; - this.webWolfPort = webWolfPort; - this.webWolfMailURL = webWolfMailURL; + public ResetLinkAssignmentForgotPassword( + RestTemplate restTemplate, + @Value("${webwolf.host}") String webWolfHost, + @Value("${webwolf.port}") String webWolfPort, + @Value("${webwolf.mail.url}") String webWolfMailURL) { + this.restTemplate = restTemplate; + this.webWolfHost = webWolfHost; + this.webWolfPort = webWolfPort; + this.webWolfMailURL = webWolfMailURL; + } + + @PostMapping("/PasswordReset/ForgotPassword/create-password-reset-link") + @ResponseBody + public AttackResult sendPasswordResetLink( + @RequestParam String email, HttpServletRequest request) { + String resetLink = UUID.randomUUID().toString(); + ResetLinkAssignment.resetLinks.add(resetLink); + String host = request.getHeader("host"); + if (ResetLinkAssignment.TOM_EMAIL.equals(email) + && (host.contains(webWolfPort) + || host.contains(webWolfHost))) { // User indeed changed the host header. + ResetLinkAssignment.userToTomResetLink.put(getWebSession().getUserName(), resetLink); + fakeClickingLinkEmail(host, resetLink); + } else { + try { + sendMailToUser(email, host, resetLink); + } catch (Exception e) { + return failed(this).output("E-mail can't be send. please try again.").build(); + } } - @PostMapping("/PasswordReset/ForgotPassword/create-password-reset-link") - @ResponseBody - public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request) { - String resetLink = UUID.randomUUID().toString(); - ResetLinkAssignment.resetLinks.add(resetLink); - String host = request.getHeader("host"); - if (ResetLinkAssignment.TOM_EMAIL.equals(email) && (host.contains(webWolfPort) || host.contains(webWolfHost))) { //User indeed changed the host header. - ResetLinkAssignment.userToTomResetLink.put(getWebSession().getUserName(), resetLink); - fakeClickingLinkEmail(host, resetLink); - } else { - try { - sendMailToUser(email, host, resetLink); - } catch (Exception e) { - return failed(this).output("E-mail can't be send. please try again.").build(); - } - } + return success(this).feedback("email.send").feedbackArgs(email).build(); + } - return success(this).feedback("email.send").feedbackArgs(email).build(); - } + private void sendMailToUser(String email, String host, String resetLink) { + int index = email.indexOf("@"); + String username = email.substring(0, index == -1 ? email.length() : index); + PasswordResetEmail mail = + PasswordResetEmail.builder() + .title("Your password reset link") + .contents(String.format(ResetLinkAssignment.TEMPLATE, host, resetLink)) + .sender("password-reset@webgoat-cloud.net") + .recipient(username) + .build(); + this.restTemplate.postForEntity(webWolfMailURL, mail, Object.class); + } - private void sendMailToUser(String email, String host, String resetLink) { - int index = email.indexOf("@"); - String username = email.substring(0, index == -1 ? email.length() : index); - PasswordResetEmail mail = PasswordResetEmail.builder() - .title("Your password reset link") - .contents(String.format(ResetLinkAssignment.TEMPLATE, host, resetLink)) - .sender("password-reset@webgoat-cloud.net") - .recipient(username).build(); - this.restTemplate.postForEntity(webWolfMailURL, mail, Object.class); - } - - private void fakeClickingLinkEmail(String host, String resetLink) { - try { - HttpHeaders httpHeaders = new HttpHeaders(); - HttpEntity httpEntity = new HttpEntity(httpHeaders); - new RestTemplate().exchange(String.format("http://%s/PasswordReset/reset/reset-password/%s", host, resetLink), HttpMethod.GET, httpEntity, Void.class); - } catch (Exception e) { - //don't care - } + private void fakeClickingLinkEmail(String host, String resetLink) { + try { + HttpHeaders httpHeaders = new HttpHeaders(); + HttpEntity httpEntity = new HttpEntity(httpHeaders); + new RestTemplate() + .exchange( + String.format("http://%s/PasswordReset/reset/reset-password/%s", host, resetLink), + HttpMethod.GET, + httpEntity, + Void.class); + } catch (Exception e) { + // don't care } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/SecurityQuestionAssignment.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/SecurityQuestionAssignment.java index 882b47bd2..044689717 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/SecurityQuestionAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/SecurityQuestionAssignment.java @@ -22,6 +22,10 @@ package org.owasp.webgoat.lessons.passwordreset; +import static java.util.Optional.of; + +import java.util.HashMap; +import java.util.Map; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.beans.factory.annotation.Autowired; @@ -30,11 +34,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; -import java.util.Map; - -import static java.util.Optional.of; - /** * Assignment for picking a good security question. * @@ -44,42 +43,66 @@ import static java.util.Optional.of; @RestController public class SecurityQuestionAssignment extends AssignmentEndpoint { - @Autowired - private TriedQuestions triedQuestions; + @Autowired private TriedQuestions triedQuestions; - private static Map questions; + private static Map questions; - static { - questions = new HashMap<>(); - questions.put("What is your favorite animal?", "The answer can easily be guessed and figured out through social media."); - questions.put("In what year was your mother born?", "Can be easily guessed."); - questions.put("What was the time you were born?", "This may first seem like a good question, but you most likely dont know the exact time, so it might be hard to remember."); - questions.put("What is the name of the person you first kissed?", "Can be figured out through social media, or even guessed by trying the most common names."); - questions.put("What was the house number and street name you lived in as a child?", "Answer can be figured out through social media, or worse it might be your current address."); - questions.put("In what town or city was your first full time job?", "In times of LinkedIn and Facebook, the answer can be figured out quite easily."); - questions.put("In what city were you born?", "Easy to figure out through social media."); - questions.put("What was the last name of your favorite teacher in grade three?", "Most people would probably not know the answer to that."); - questions.put("What is the name of a college/job you applied to but didn't attend?", "It might not be easy to remember and an hacker could just try some company's/colleges in your area."); - questions.put("What are the last 5 digits of your drivers license?", "Is subject to change, and the last digit of your driver license might follow a specific pattern. (For example your birthday)."); - questions.put("What was your childhood nickname?", "Not all people had a nickname."); - questions.put("Who was your childhood hero?", "Most Heroes we had as a child where quite obvious ones, like Superman for example."); - questions.put("On which wrist do you wear your watch?", "There are only to possible real answers, so really easy to guess."); - questions.put("What is your favorite color?", "Can easily be guessed."); - } - - @PostMapping("/PasswordReset/SecurityQuestions") - @ResponseBody - public AttackResult completed(@RequestParam String question) { - var answer = of(questions.get(question)); - if (answer.isPresent()) { - triedQuestions.incr(question); - if (triedQuestions.isComplete()) { - return success(this).output("" + answer + "").build(); - } - } - return informationMessage(this) - .feedback("password-questions-one-successful") - .output(answer.orElse("Unknown question, please try again...")) - .build(); + static { + questions = new HashMap<>(); + questions.put( + "What is your favorite animal?", + "The answer can easily be guessed and figured out through social media."); + questions.put("In what year was your mother born?", "Can be easily guessed."); + questions.put( + "What was the time you were born?", + "This may first seem like a good question, but you most likely dont know the exact time, so" + + " it might be hard to remember."); + questions.put( + "What is the name of the person you first kissed?", + "Can be figured out through social media, or even guessed by trying the most common" + + " names."); + questions.put( + "What was the house number and street name you lived in as a child?", + "Answer can be figured out through social media, or worse it might be your current" + + " address."); + questions.put( + "In what town or city was your first full time job?", + "In times of LinkedIn and Facebook, the answer can be figured out quite easily."); + questions.put("In what city were you born?", "Easy to figure out through social media."); + questions.put( + "What was the last name of your favorite teacher in grade three?", + "Most people would probably not know the answer to that."); + questions.put( + "What is the name of a college/job you applied to but didn't attend?", + "It might not be easy to remember and an hacker could just try some company's/colleges in" + + " your area."); + questions.put( + "What are the last 5 digits of your drivers license?", + "Is subject to change, and the last digit of your driver license might follow a specific" + + " pattern. (For example your birthday)."); + questions.put("What was your childhood nickname?", "Not all people had a nickname."); + questions.put( + "Who was your childhood hero?", + "Most Heroes we had as a child where quite obvious ones, like Superman for example."); + questions.put( + "On which wrist do you wear your watch?", + "There are only to possible real answers, so really easy to guess."); + questions.put("What is your favorite color?", "Can easily be guessed."); + } + + @PostMapping("/PasswordReset/SecurityQuestions") + @ResponseBody + public AttackResult completed(@RequestParam String question) { + var answer = of(questions.get(question)); + if (answer.isPresent()) { + triedQuestions.incr(question); + if (triedQuestions.isComplete()) { + return success(this).output("" + answer + "").build(); + } } + return informationMessage(this) + .feedback("password-questions-one-successful") + .output(answer.orElse("Unknown question, please try again...")) + .build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/SimpleMailAssignment.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/SimpleMailAssignment.java index 42c4dce67..656732183 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/SimpleMailAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/SimpleMailAssignment.java @@ -22,6 +22,9 @@ package org.owasp.webgoat.lessons.passwordreset; +import static java.util.Optional.ofNullable; + +import java.time.LocalDateTime; import org.apache.commons.lang3.StringUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; @@ -34,10 +37,6 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestClientException; import org.springframework.web.client.RestTemplate; -import java.time.LocalDateTime; - -import static java.util.Optional.ofNullable; - /** * @author nbaars * @since 8/20/17. @@ -45,56 +44,74 @@ import static java.util.Optional.ofNullable; @RestController public class SimpleMailAssignment extends AssignmentEndpoint { - private final String webWolfURL; - private RestTemplate restTemplate; + private final String webWolfURL; + private RestTemplate restTemplate; - public SimpleMailAssignment(RestTemplate restTemplate, @Value("${webwolf.mail.url}") String webWolfURL) { - this.restTemplate = restTemplate; - this.webWolfURL = webWolfURL; + public SimpleMailAssignment( + RestTemplate restTemplate, @Value("${webwolf.mail.url}") String webWolfURL) { + this.restTemplate = restTemplate; + this.webWolfURL = webWolfURL; + } + + @PostMapping( + path = "/PasswordReset/simple-mail", + consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + @ResponseBody + public AttackResult login(@RequestParam String email, @RequestParam String password) { + String emailAddress = ofNullable(email).orElse("unknown@webgoat.org"); + String username = extractUsername(emailAddress); + + if (username.equals(getWebSession().getUserName()) + && StringUtils.reverse(username).equals(password)) { + return success(this).build(); + } else { + return failed(this).feedbackArgs("password-reset-simple.password_incorrect").build(); } + } - @PostMapping(path = "/PasswordReset/simple-mail", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) - @ResponseBody - public AttackResult login(@RequestParam String email, @RequestParam String password) { - String emailAddress = ofNullable(email).orElse("unknown@webgoat.org"); - String username = extractUsername(emailAddress); + @PostMapping( + consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, + value = "/PasswordReset/simple-mail/reset") + @ResponseBody + public AttackResult resetPassword(@RequestParam String emailReset) { + String email = ofNullable(emailReset).orElse("unknown@webgoat.org"); + return sendEmail(extractUsername(email), email); + } - if (username.equals(getWebSession().getUserName()) && StringUtils.reverse(username).equals(password)) { - return success(this).build(); - } else { - return failed(this).feedbackArgs("password-reset-simple.password_incorrect").build(); - } - } - - @PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, value = "/PasswordReset/simple-mail/reset") - @ResponseBody - public AttackResult resetPassword(@RequestParam String emailReset) { - String email = ofNullable(emailReset).orElse("unknown@webgoat.org"); - return sendEmail(extractUsername(email), email); - } - - private String extractUsername(String email) { - int index = email.indexOf("@"); - return email.substring(0, index == -1 ? email.length() : index); - } - - private AttackResult sendEmail(String username, String email) { - if (username.equals(getWebSession().getUserName())) { - PasswordResetEmail mailEvent = PasswordResetEmail.builder() - .recipient(username) - .title("Simple e-mail assignment") - .time(LocalDateTime.now()) - .contents("Thanks for resetting your password, your new password is: " + StringUtils.reverse(username)) - .sender("webgoat@owasp.org") - .build(); - try { - restTemplate.postForEntity(webWolfURL, mailEvent, Object.class); - } catch (RestClientException e) { - return informationMessage(this).feedback("password-reset-simple.email_failed").output(e.getMessage()).build(); - } - return informationMessage(this).feedback("password-reset-simple.email_send").feedbackArgs(email).build(); - } else { - return informationMessage(this).feedback("password-reset-simple.email_mismatch").feedbackArgs(username).build(); - } + private String extractUsername(String email) { + int index = email.indexOf("@"); + return email.substring(0, index == -1 ? email.length() : index); + } + + private AttackResult sendEmail(String username, String email) { + if (username.equals(getWebSession().getUserName())) { + PasswordResetEmail mailEvent = + PasswordResetEmail.builder() + .recipient(username) + .title("Simple e-mail assignment") + .time(LocalDateTime.now()) + .contents( + "Thanks for resetting your password, your new password is: " + + StringUtils.reverse(username)) + .sender("webgoat@owasp.org") + .build(); + try { + restTemplate.postForEntity(webWolfURL, mailEvent, Object.class); + } catch (RestClientException e) { + return informationMessage(this) + .feedback("password-reset-simple.email_failed") + .output(e.getMessage()) + .build(); + } + return informationMessage(this) + .feedback("password-reset-simple.email_send") + .feedbackArgs(email) + .build(); + } else { + return informationMessage(this) + .feedback("password-reset-simple.email_mismatch") + .feedbackArgs(username) + .build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/TriedQuestions.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/TriedQuestions.java index 64d565b9f..d8f04167a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/TriedQuestions.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/TriedQuestions.java @@ -22,23 +22,22 @@ package org.owasp.webgoat.lessons.passwordreset; -import org.springframework.stereotype.Component; -import org.springframework.web.context.annotation.SessionScope; - import java.util.HashSet; import java.util.Set; +import org.springframework.stereotype.Component; +import org.springframework.web.context.annotation.SessionScope; @Component @SessionScope public class TriedQuestions { - private Set answeredQuestions = new HashSet<>(); + private Set answeredQuestions = new HashSet<>(); - public void incr(String question) { - answeredQuestions.add(question); - } + public void incr(String question) { + answeredQuestions.add(question); + } - public boolean isComplete() { - return answeredQuestions.size() > 1; - } + public boolean isComplete() { + return answeredQuestions.size() > 1; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/passwordreset/resetlink/PasswordChangeForm.java b/src/main/java/org/owasp/webgoat/lessons/passwordreset/resetlink/PasswordChangeForm.java index 267b39447..604c51fd3 100644 --- a/src/main/java/org/owasp/webgoat/lessons/passwordreset/resetlink/PasswordChangeForm.java +++ b/src/main/java/org/owasp/webgoat/lessons/passwordreset/resetlink/PasswordChangeForm.java @@ -1,10 +1,9 @@ package org.owasp.webgoat.lessons.passwordreset.resetlink; -import lombok.Getter; -import lombok.Setter; - import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; /** * @author nbaars @@ -14,9 +13,9 @@ import javax.validation.constraints.Size; @Setter public class PasswordChangeForm { - @NotNull - @Size(min = 6, max = 10) - private String password; - private String resetLink; + @NotNull + @Size(min = 6, max = 10) + private String password; + private String resetLink; } diff --git a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/PathTraversal.java b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/PathTraversal.java index da689cf42..ef61ae901 100644 --- a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/PathTraversal.java +++ b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/PathTraversal.java @@ -29,13 +29,13 @@ import org.springframework.stereotype.Component; @Component public class PathTraversal extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A3; - } + @Override + public Category getDefaultCategory() { + return Category.A3; + } - @Override - public String getTitle() { - return "path-traversal-title"; - } + @Override + public String getTitle() { + return "path-traversal-title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUpload.java b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUpload.java index 754933530..6c76cede7 100644 --- a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUpload.java +++ b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUpload.java @@ -1,5 +1,8 @@ package org.owasp.webgoat.lessons.pathtraversal; +import static org.springframework.http.MediaType.ALL_VALUE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; import org.owasp.webgoat.container.session.WebSession; @@ -12,27 +15,33 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import static org.springframework.http.MediaType.ALL_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - @RestController -@AssignmentHints({"path-traversal-profile.hint1", "path-traversal-profile.hint2", "path-traversal-profile.hint3"}) +@AssignmentHints({ + "path-traversal-profile.hint1", + "path-traversal-profile.hint2", + "path-traversal-profile.hint3" +}) public class ProfileUpload extends ProfileUploadBase { - public ProfileUpload(@Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { - super(webGoatHomeDirectory, webSession); - } + public ProfileUpload( + @Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { + super(webGoatHomeDirectory, webSession); + } - @PostMapping(value = "/PathTraversal/profile-upload", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE) - @ResponseBody - public AttackResult uploadFileHandler(@RequestParam("uploadedFile") MultipartFile file, @RequestParam(value = "fullName", required = false) String fullName) { - return super.execute(file, fullName); - } - - @GetMapping("/PathTraversal/profile-picture") - @ResponseBody - public ResponseEntity getProfilePicture() { - return super.getProfilePicture(); - } + @PostMapping( + value = "/PathTraversal/profile-upload", + consumes = ALL_VALUE, + produces = APPLICATION_JSON_VALUE) + @ResponseBody + public AttackResult uploadFileHandler( + @RequestParam("uploadedFile") MultipartFile file, + @RequestParam(value = "fullName", required = false) String fullName) { + return super.execute(file, fullName); + } + @GetMapping("/PathTraversal/profile-picture") + @ResponseBody + public ResponseEntity getProfilePicture() { + return super.getProfilePicture(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadBase.java b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadBase.java index 4377650a1..a1ca0967e 100644 --- a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadBase.java +++ b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadBase.java @@ -1,5 +1,9 @@ package org.owasp.webgoat.lessons.pathtraversal; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Base64; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.SneakyThrows; @@ -13,82 +17,89 @@ import org.springframework.util.FileSystemUtils; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Base64; - @AllArgsConstructor @Getter public class ProfileUploadBase extends AssignmentEndpoint { - private String webGoatHomeDirectory; - private WebSession webSession; + private String webGoatHomeDirectory; + private WebSession webSession; - protected AttackResult execute(MultipartFile file, String fullName) { - if (file.isEmpty()) { - return failed(this).feedback("path-traversal-profile-empty-file").build(); - } - if (StringUtils.isEmpty(fullName)) { - return failed(this).feedback("path-traversal-profile-empty-name").build(); - } - - var uploadDirectory = new File(this.webGoatHomeDirectory, "/PathTraversal/" + webSession.getUserName()); - if (uploadDirectory.exists()) { - FileSystemUtils.deleteRecursively(uploadDirectory); - } - - try { - uploadDirectory.mkdirs(); - var uploadedFile = new File(uploadDirectory, fullName); - uploadedFile.createNewFile(); - FileCopyUtils.copy(file.getBytes(), uploadedFile); - - if (attemptWasMade(uploadDirectory, uploadedFile)) { - return solvedIt(uploadedFile); - } - return informationMessage(this).feedback("path-traversal-profile-updated").feedbackArgs(uploadedFile.getAbsoluteFile()).build(); - - } catch (IOException e) { - return failed(this).output(e.getMessage()).build(); - } + protected AttackResult execute(MultipartFile file, String fullName) { + if (file.isEmpty()) { + return failed(this).feedback("path-traversal-profile-empty-file").build(); + } + if (StringUtils.isEmpty(fullName)) { + return failed(this).feedback("path-traversal-profile-empty-name").build(); } - private boolean attemptWasMade(File expectedUploadDirectory, File uploadedFile) throws IOException { - return !expectedUploadDirectory.getCanonicalPath().equals(uploadedFile.getParentFile().getCanonicalPath()); + var uploadDirectory = + new File(this.webGoatHomeDirectory, "/PathTraversal/" + webSession.getUserName()); + if (uploadDirectory.exists()) { + FileSystemUtils.deleteRecursively(uploadDirectory); } - private AttackResult solvedIt(File uploadedFile) throws IOException { - if (uploadedFile.getCanonicalFile().getParentFile().getName().endsWith("PathTraversal")) { - return success(this).build(); - } - return failed(this).attemptWasMade().feedback("path-traversal-profile-attempt").feedbackArgs(uploadedFile.getCanonicalPath()).build(); + try { + uploadDirectory.mkdirs(); + var uploadedFile = new File(uploadDirectory, fullName); + uploadedFile.createNewFile(); + FileCopyUtils.copy(file.getBytes(), uploadedFile); + + if (attemptWasMade(uploadDirectory, uploadedFile)) { + return solvedIt(uploadedFile); + } + return informationMessage(this) + .feedback("path-traversal-profile-updated") + .feedbackArgs(uploadedFile.getAbsoluteFile()) + .build(); + + } catch (IOException e) { + return failed(this).output(e.getMessage()).build(); } + } - public ResponseEntity getProfilePicture() { - return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) - .body(getProfilePictureAsBase64()); + private boolean attemptWasMade(File expectedUploadDirectory, File uploadedFile) + throws IOException { + return !expectedUploadDirectory + .getCanonicalPath() + .equals(uploadedFile.getParentFile().getCanonicalPath()); + } + + private AttackResult solvedIt(File uploadedFile) throws IOException { + if (uploadedFile.getCanonicalFile().getParentFile().getName().endsWith("PathTraversal")) { + return success(this).build(); } + return failed(this) + .attemptWasMade() + .feedback("path-traversal-profile-attempt") + .feedbackArgs(uploadedFile.getCanonicalPath()) + .build(); + } - protected byte[] getProfilePictureAsBase64() { - var profilePictureDirectory = new File(this.webGoatHomeDirectory, "/PathTraversal/" + webSession.getUserName()); - var profileDirectoryFiles = profilePictureDirectory.listFiles(); + public ResponseEntity getProfilePicture() { + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) + .body(getProfilePictureAsBase64()); + } - if (profileDirectoryFiles != null && profileDirectoryFiles.length > 0) { - try (var inputStream = new FileInputStream(profileDirectoryFiles[0])) { - return Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(inputStream)); - } catch (IOException e) { - return defaultImage(); - } - } else { - return defaultImage(); - } - } + protected byte[] getProfilePictureAsBase64() { + var profilePictureDirectory = + new File(this.webGoatHomeDirectory, "/PathTraversal/" + webSession.getUserName()); + var profileDirectoryFiles = profilePictureDirectory.listFiles(); - @SneakyThrows - private byte[] defaultImage() { - var inputStream = getClass().getResourceAsStream("/images/account.png"); + if (profileDirectoryFiles != null && profileDirectoryFiles.length > 0) { + try (var inputStream = new FileInputStream(profileDirectoryFiles[0])) { return Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(inputStream)); + } catch (IOException e) { + return defaultImage(); + } + } else { + return defaultImage(); } + } + + @SneakyThrows + private byte[] defaultImage() { + var inputStream = getClass().getResourceAsStream("/images/account.png"); + return Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(inputStream)); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadFix.java b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadFix.java index c1dd5ce58..90c0589b9 100644 --- a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadFix.java +++ b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadFix.java @@ -1,5 +1,8 @@ package org.owasp.webgoat.lessons.pathtraversal; +import static org.springframework.http.MediaType.ALL_VALUE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; import org.owasp.webgoat.container.session.WebSession; @@ -12,28 +15,33 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import static org.springframework.http.MediaType.ALL_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - @RestController -@AssignmentHints({"path-traversal-profile-fix.hint1", "path-traversal-profile-fix.hint2", "path-traversal-profile-fix.hint3"}) +@AssignmentHints({ + "path-traversal-profile-fix.hint1", + "path-traversal-profile-fix.hint2", + "path-traversal-profile-fix.hint3" +}) public class ProfileUploadFix extends ProfileUploadBase { - public ProfileUploadFix(@Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { - super(webGoatHomeDirectory, webSession); - } + public ProfileUploadFix( + @Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { + super(webGoatHomeDirectory, webSession); + } - @PostMapping(value = "/PathTraversal/profile-upload-fix", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE) - @ResponseBody - public AttackResult uploadFileHandler( - @RequestParam("uploadedFileFix") MultipartFile file, - @RequestParam(value = "fullNameFix", required = false) String fullName) { - return super.execute(file, fullName != null ? fullName.replace("../", "") : ""); - } + @PostMapping( + value = "/PathTraversal/profile-upload-fix", + consumes = ALL_VALUE, + produces = APPLICATION_JSON_VALUE) + @ResponseBody + public AttackResult uploadFileHandler( + @RequestParam("uploadedFileFix") MultipartFile file, + @RequestParam(value = "fullNameFix", required = false) String fullName) { + return super.execute(file, fullName != null ? fullName.replace("../", "") : ""); + } - @GetMapping("/PathTraversal/profile-picture-fix") - @ResponseBody - public ResponseEntity getProfilePicture() { - return super.getProfilePicture(); - } + @GetMapping("/PathTraversal/profile-picture-fix") + @ResponseBody + public ResponseEntity getProfilePicture() { + return super.getProfilePicture(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRemoveUserInput.java b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRemoveUserInput.java index d62c8451d..95971df26 100644 --- a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRemoveUserInput.java +++ b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRemoveUserInput.java @@ -1,5 +1,8 @@ package org.owasp.webgoat.lessons.pathtraversal; +import static org.springframework.http.MediaType.ALL_VALUE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; import org.owasp.webgoat.container.session.WebSession; @@ -10,20 +13,26 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import static org.springframework.http.MediaType.ALL_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - @RestController -@AssignmentHints({"path-traversal-profile-remove-user-input.hint1", "path-traversal-profile-remove-user-input.hint2", "path-traversal-profile-remove-user-input.hint3"}) +@AssignmentHints({ + "path-traversal-profile-remove-user-input.hint1", + "path-traversal-profile-remove-user-input.hint2", + "path-traversal-profile-remove-user-input.hint3" +}) public class ProfileUploadRemoveUserInput extends ProfileUploadBase { - public ProfileUploadRemoveUserInput(@Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { - super(webGoatHomeDirectory, webSession); - } + public ProfileUploadRemoveUserInput( + @Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { + super(webGoatHomeDirectory, webSession); + } - @PostMapping(value = "/PathTraversal/profile-upload-remove-user-input", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE) - @ResponseBody - public AttackResult uploadFileHandler(@RequestParam("uploadedFileRemoveUserInput") MultipartFile file) { - return super.execute(file, file.getOriginalFilename()); - } + @PostMapping( + value = "/PathTraversal/profile-upload-remove-user-input", + consumes = ALL_VALUE, + produces = APPLICATION_JSON_VALUE) + @ResponseBody + public AttackResult uploadFileHandler( + @RequestParam("uploadedFileRemoveUserInput") MultipartFile file) { + return super.execute(file, file.getOriginalFilename()); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrieval.java b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrieval.java index b010532eb..f52bed34a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrieval.java +++ b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrieval.java @@ -1,5 +1,15 @@ package org.owasp.webgoat.lessons.pathtraversal; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.util.Base64; +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -19,90 +29,88 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.PostConstruct; -import javax.servlet.http.HttpServletRequest; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.util.Base64; - @RestController @AssignmentHints({ - "path-traversal-profile-retrieve.hint1", - "path-traversal-profile-retrieve.hint2", - "path-traversal-profile-retrieve.hint3", - "path-traversal-profile-retrieve.hint4", - "path-traversal-profile-retrieve.hint5", - "path-traversal-profile-retrieve.hint6"}) + "path-traversal-profile-retrieve.hint1", + "path-traversal-profile-retrieve.hint2", + "path-traversal-profile-retrieve.hint3", + "path-traversal-profile-retrieve.hint4", + "path-traversal-profile-retrieve.hint5", + "path-traversal-profile-retrieve.hint6" +}) @Slf4j public class ProfileUploadRetrieval extends AssignmentEndpoint { - private final File catPicturesDirectory; + private final File catPicturesDirectory; - public ProfileUploadRetrieval(@Value("${webgoat.server.directory}") String webGoatHomeDirectory) { - this.catPicturesDirectory = new File(webGoatHomeDirectory, "/PathTraversal/" + "/cats"); - this.catPicturesDirectory.mkdirs(); + public ProfileUploadRetrieval(@Value("${webgoat.server.directory}") String webGoatHomeDirectory) { + this.catPicturesDirectory = new File(webGoatHomeDirectory, "/PathTraversal/" + "/cats"); + this.catPicturesDirectory.mkdirs(); + } + + @PostConstruct + public void initAssignment() { + for (int i = 1; i <= 10; i++) { + try (InputStream is = + new ClassPathResource("lessons/pathtraversal/images/cats/" + i + ".jpg") + .getInputStream()) { + FileCopyUtils.copy(is, new FileOutputStream(new File(catPicturesDirectory, i + ".jpg"))); + } catch (Exception e) { + log.error("Unable to copy pictures" + e.getMessage()); + } + } + var secretDirectory = this.catPicturesDirectory.getParentFile().getParentFile(); + try { + Files.writeString( + secretDirectory.toPath().resolve("path-traversal-secret.jpg"), + "You found it submit the SHA-512 hash of your username as answer"); + } catch (IOException e) { + log.error("Unable to write secret in: {}", secretDirectory, e); + } + } + + @PostMapping("/PathTraversal/random") + @ResponseBody + public AttackResult execute(@RequestParam(value = "secret", required = false) String secret) { + if (Sha512DigestUtils.shaHex(getWebSession().getUserName()).equalsIgnoreCase(secret)) { + return success(this).build(); + } + return failed(this).build(); + } + + @GetMapping("/PathTraversal/random-picture") + @ResponseBody + public ResponseEntity getProfilePicture(HttpServletRequest request) { + var queryParams = request.getQueryString(); + if (queryParams != null && (queryParams.contains("..") || queryParams.contains("/"))) { + return ResponseEntity.badRequest() + .body("Illegal characters are not allowed in the query params"); + } + try { + var id = request.getParameter("id"); + var catPicture = + new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + ".jpg"); + + if (catPicture.getName().toLowerCase().contains("path-traversal-secret.jpg")) { + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) + .body(FileCopyUtils.copyToByteArray(catPicture)); + } + if (catPicture.exists()) { + return ResponseEntity.ok() + .contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) + .location(new URI("/PathTraversal/random-picture?id=" + catPicture.getName())) + .body(Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(catPicture))); + } + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .location(new URI("/PathTraversal/random-picture?id=" + catPicture.getName())) + .body( + StringUtils.arrayToCommaDelimitedString(catPicture.getParentFile().listFiles()) + .getBytes()); + } catch (IOException | URISyntaxException e) { + log.error("Image not found", e); } - @PostConstruct - public void initAssignment() { - for (int i = 1; i <= 10; i++) { - try (InputStream is = new ClassPathResource("lessons/pathtraversal/images/cats/" + i + ".jpg").getInputStream()) { - FileCopyUtils.copy(is, new FileOutputStream(new File(catPicturesDirectory, i + ".jpg"))); - } catch (Exception e) { - log.error("Unable to copy pictures" + e.getMessage()); - } - } - var secretDirectory = this.catPicturesDirectory.getParentFile().getParentFile(); - try { - Files.writeString(secretDirectory.toPath().resolve("path-traversal-secret.jpg"), "You found it submit the SHA-512 hash of your username as answer"); - } catch (IOException e) { - log.error("Unable to write secret in: {}", secretDirectory, e); - } - } - - @PostMapping("/PathTraversal/random") - @ResponseBody - public AttackResult execute(@RequestParam(value = "secret", required = false) String secret) { - if (Sha512DigestUtils.shaHex(getWebSession().getUserName()).equalsIgnoreCase(secret)) { - return success(this).build(); - } - return failed(this).build(); - } - - @GetMapping("/PathTraversal/random-picture") - @ResponseBody - public ResponseEntity getProfilePicture(HttpServletRequest request) { - var queryParams = request.getQueryString(); - if (queryParams != null && (queryParams.contains("..") || queryParams.contains("/"))) { - return ResponseEntity.badRequest().body("Illegal characters are not allowed in the query params"); - } - try { - var id = request.getParameter("id"); - var catPicture = new File(catPicturesDirectory, (id == null ? RandomUtils.nextInt(1, 11) : id) + ".jpg"); - - if (catPicture.getName().toLowerCase().contains("path-traversal-secret.jpg")) { - return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) - .body(FileCopyUtils.copyToByteArray(catPicture)); - } - if (catPicture.exists()) { - return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(MediaType.IMAGE_JPEG_VALUE)) - .location(new URI("/PathTraversal/random-picture?id=" + catPicture.getName())) - .body(Base64.getEncoder().encode(FileCopyUtils.copyToByteArray(catPicture))); - } - return ResponseEntity.status(HttpStatus.NOT_FOUND) - .location(new URI("/PathTraversal/random-picture?id=" + catPicture.getName())) - .body(StringUtils.arrayToCommaDelimitedString(catPicture.getParentFile().listFiles()).getBytes()); - } catch (IOException | URISyntaxException e) { - log.error("Image not found", e); - } - - return ResponseEntity.badRequest().build(); - } + return ResponseEntity.badRequest().build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileZipSlip.java b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileZipSlip.java index 7bcf317d9..c14223560 100644 --- a/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileZipSlip.java +++ b/src/main/java/org/owasp/webgoat/lessons/pathtraversal/ProfileZipSlip.java @@ -1,14 +1,7 @@ package org.owasp.webgoat.lessons.pathtraversal; -import lombok.SneakyThrows; -import org.owasp.webgoat.container.assignments.AssignmentHints; -import org.owasp.webgoat.container.assignments.AttackResult; -import org.owasp.webgoat.container.session.WebSession; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.util.FileCopyUtils; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; +import static org.springframework.http.MediaType.ALL_VALUE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import java.io.File; import java.io.IOException; @@ -19,72 +12,87 @@ import java.util.Arrays; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; - -import static org.springframework.http.MediaType.ALL_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import lombok.SneakyThrows; +import org.owasp.webgoat.container.assignments.AssignmentHints; +import org.owasp.webgoat.container.assignments.AttackResult; +import org.owasp.webgoat.container.session.WebSession; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; @RestController -@AssignmentHints({"path-traversal-zip-slip.hint1", "path-traversal-zip-slip.hint2", "path-traversal-zip-slip.hint3", "path-traversal-zip-slip.hint4"}) +@AssignmentHints({ + "path-traversal-zip-slip.hint1", + "path-traversal-zip-slip.hint2", + "path-traversal-zip-slip.hint3", + "path-traversal-zip-slip.hint4" +}) public class ProfileZipSlip extends ProfileUploadBase { - public ProfileZipSlip(@Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { - super(webGoatHomeDirectory, webSession); + public ProfileZipSlip( + @Value("${webgoat.server.directory}") String webGoatHomeDirectory, WebSession webSession) { + super(webGoatHomeDirectory, webSession); + } + + @PostMapping( + value = "/PathTraversal/zip-slip", + consumes = ALL_VALUE, + produces = APPLICATION_JSON_VALUE) + @ResponseBody + public AttackResult uploadFileHandler(@RequestParam("uploadedFileZipSlip") MultipartFile file) { + if (!file.getOriginalFilename().toLowerCase().endsWith(".zip")) { + return failed(this).feedback("path-traversal-zip-slip.no-zip").build(); + } else { + return processZipUpload(file); } + } - @PostMapping(value = "/PathTraversal/zip-slip", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE) - @ResponseBody - public AttackResult uploadFileHandler(@RequestParam("uploadedFileZipSlip") MultipartFile file) { - if (!file.getOriginalFilename().toLowerCase().endsWith(".zip")) { - return failed(this).feedback("path-traversal-zip-slip.no-zip").build(); - } else { - return processZipUpload(file); - } + @SneakyThrows + private AttackResult processZipUpload(MultipartFile file) { + var tmpZipDirectory = Files.createTempDirectory(getWebSession().getUserName()); + var uploadDirectory = + new File(getWebGoatHomeDirectory(), "/PathTraversal/" + getWebSession().getUserName()); + var currentImage = getProfilePictureAsBase64(); + + Files.createDirectories(uploadDirectory.toPath()); + + try { + var uploadedZipFile = tmpZipDirectory.resolve(file.getOriginalFilename()); + FileCopyUtils.copy(file.getBytes(), uploadedZipFile.toFile()); + + ZipFile zip = new ZipFile(uploadedZipFile.toFile()); + Enumeration entries = zip.entries(); + while (entries.hasMoreElements()) { + ZipEntry e = entries.nextElement(); + File f = new File(tmpZipDirectory.toFile(), e.getName()); + InputStream is = zip.getInputStream(e); + Files.copy(is, f.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + + return isSolved(currentImage, getProfilePictureAsBase64()); + } catch (IOException e) { + return failed(this).output(e.getMessage()).build(); } + } - @SneakyThrows - private AttackResult processZipUpload(MultipartFile file) { - var tmpZipDirectory = Files.createTempDirectory(getWebSession().getUserName()); - var uploadDirectory = new File(getWebGoatHomeDirectory(), "/PathTraversal/" + getWebSession().getUserName()); - var currentImage = getProfilePictureAsBase64(); - - Files.createDirectories(uploadDirectory.toPath()); - - try { - var uploadedZipFile = tmpZipDirectory.resolve(file.getOriginalFilename()); - FileCopyUtils.copy(file.getBytes(), uploadedZipFile.toFile()); - - ZipFile zip = new ZipFile(uploadedZipFile.toFile()); - Enumeration entries = zip.entries(); - while (entries.hasMoreElements()) { - ZipEntry e = entries.nextElement(); - File f = new File(tmpZipDirectory.toFile(), e.getName()); - InputStream is = zip.getInputStream(e); - Files.copy(is, f.toPath(), StandardCopyOption.REPLACE_EXISTING); - } - - return isSolved(currentImage, getProfilePictureAsBase64()); - } catch (IOException e) { - return failed(this).output(e.getMessage()).build(); - } + private AttackResult isSolved(byte[] currentImage, byte[] newImage) { + if (Arrays.equals(currentImage, newImage)) { + return failed(this).output("path-traversal-zip-slip.extracted").build(); } + return success(this).output("path-traversal-zip-slip.extracted").build(); + } - private AttackResult isSolved(byte[] currentImage, byte[] newImage) { - if (Arrays.equals(currentImage, newImage)) { - return failed(this).output("path-traversal-zip-slip.extracted").build(); - } - return success(this).output("path-traversal-zip-slip.extracted").build(); - } - - @GetMapping("/PathTraversal/zip-slip/") - @ResponseBody - public ResponseEntity getProfilePicture() { - return super.getProfilePicture(); - } - - @GetMapping("/PathTraversal/zip-slip/profile-image/{username}") - @ResponseBody - public ResponseEntity getProfilePicture(@PathVariable("username") String username) { - return ResponseEntity.notFound().build(); - } + @GetMapping("/PathTraversal/zip-slip/") + @ResponseBody + public ResponseEntity getProfilePicture() { + return super.getProfilePicture(); + } + @GetMapping("/PathTraversal/zip-slip/profile-image/{username}") + @ResponseBody + public ResponseEntity getProfilePicture(@PathVariable("username") String username) { + return ResponseEntity.notFound().build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/securepasswords/SecurePasswords.java b/src/main/java/org/owasp/webgoat/lessons/securepasswords/SecurePasswords.java index 0456c0717..99a62aeff 100644 --- a/src/main/java/org/owasp/webgoat/lessons/securepasswords/SecurePasswords.java +++ b/src/main/java/org/owasp/webgoat/lessons/securepasswords/SecurePasswords.java @@ -33,13 +33,13 @@ import org.springframework.stereotype.Component; @Component public class SecurePasswords extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A7; - } + @Override + public Category getDefaultCategory() { + return Category.A7; + } - @Override - public String getTitle() { - return "secure-passwords.title"; - } + @Override + public String getTitle() { + return "secure-passwords.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/securepasswords/SecurePasswordsAssignment.java b/src/main/java/org/owasp/webgoat/lessons/securepasswords/SecurePasswordsAssignment.java index b026722e3..5b9932d36 100644 --- a/src/main/java/org/owasp/webgoat/lessons/securepasswords/SecurePasswordsAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/securepasswords/SecurePasswordsAssignment.java @@ -24,6 +24,9 @@ package org.owasp.webgoat.lessons.securepasswords; import com.nulabinc.zxcvbn.Strength; import com.nulabinc.zxcvbn.Zxcvbn; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.web.bind.annotation.PostMapping; @@ -31,64 +34,85 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Locale; - @RestController public class SecurePasswordsAssignment extends AssignmentEndpoint { - @PostMapping("SecurePasswords/assignment") - @ResponseBody - public AttackResult completed(@RequestParam String password) { - Zxcvbn zxcvbn = new Zxcvbn(); - StringBuilder output = new StringBuilder(); - DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); - df.setMaximumFractionDigits(340); - Strength strength = zxcvbn.measure(password); + @PostMapping("SecurePasswords/assignment") + @ResponseBody + public AttackResult completed(@RequestParam String password) { + Zxcvbn zxcvbn = new Zxcvbn(); + StringBuilder output = new StringBuilder(); + DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); + df.setMaximumFractionDigits(340); + Strength strength = zxcvbn.measure(password); - output.append("Your Password: *******
"); - output.append("Length: " + password.length() + "
"); - output.append("Estimated guesses needed to crack your password: " + df.format(strength.getGuesses()) + "
"); - output.append("

Score: " + strength.getScore() + "/4
"); - if (strength.getScore() <= 1) { - output.append("
 

"); - } else if (strength.getScore() <= 3) { - output.append("
 

"); - } else { - output.append("
 

"); - } - output.append("Estimated cracking time: " + calculateTime((long) strength.getCrackTimeSeconds().getOnlineNoThrottling10perSecond()) + "
"); - if (strength.getFeedback().getWarning().length() != 0) - output.append("Warning: " + strength.getFeedback().getWarning() + "
"); - // possible feedback: https://github.com/dropbox/zxcvbn/blob/master/src/feedback.coffee - // maybe ask user to try also weak passwords to see and understand feedback? - if (strength.getFeedback().getSuggestions().size() != 0) { - output.append("Suggestions:
    "); - for (String sug : strength.getFeedback().getSuggestions()) output.append("
  • " + sug + "
  • "); - output.append("

"); - } - output.append("Score: " + strength.getScore() + "/4
"); - - if (strength.getScore() >= 4) - return success(this).feedback("securepassword-success").output(output.toString()).build(); - else - return failed(this).feedback("securepassword-failed").output(output.toString()).build(); + output.append("Your Password: *******
"); + output.append("Length: " + password.length() + "
"); + output.append( + "Estimated guesses needed to crack your password: " + + df.format(strength.getGuesses()) + + "
"); + output.append( + "
Score: " + + strength.getScore() + + "/4
"); + if (strength.getScore() <= 1) { + output.append( + "
 

"); + } else if (strength.getScore() <= 3) { + output.append( + "
 

"); + } else { + output.append( + "
 

"); } - - public static String calculateTime(long seconds) { - int s = 1; - int min = (60 * s); - int hr = (60 * min); - int d = (24 * hr); - int yr = (365 * d); - - long years = seconds / (d) / 365; - long days = (seconds % yr) / (d); - long hours = (seconds % d) / (hr); - long minutes = (seconds % hr) / (min); - long sec = (seconds % min * s); - - return (years + " years " + days + " days " + hours + " hours " + minutes + " minutes " + sec + " seconds"); + output.append( + "Estimated cracking time: " + + calculateTime( + (long) strength.getCrackTimeSeconds().getOnlineNoThrottling10perSecond()) + + "
"); + if (strength.getFeedback().getWarning().length() != 0) + output.append("Warning: " + strength.getFeedback().getWarning() + "
"); + // possible feedback: https://github.com/dropbox/zxcvbn/blob/master/src/feedback.coffee + // maybe ask user to try also weak passwords to see and understand feedback? + if (strength.getFeedback().getSuggestions().size() != 0) { + output.append("Suggestions:
    "); + for (String sug : strength.getFeedback().getSuggestions()) + output.append("
  • " + sug + "
  • "); + output.append("

"); } + output.append("Score: " + strength.getScore() + "/4
"); + + if (strength.getScore() >= 4) + return success(this).feedback("securepassword-success").output(output.toString()).build(); + else return failed(this).feedback("securepassword-failed").output(output.toString()).build(); + } + + public static String calculateTime(long seconds) { + int s = 1; + int min = (60 * s); + int hr = (60 * min); + int d = (24 * hr); + int yr = (365 * d); + + long years = seconds / (d) / 365; + long days = (seconds % yr) / (d); + long hours = (seconds % d) / (hr); + long minutes = (seconds % hr) / (min); + long sec = (seconds % min * s); + + return (years + + " years " + + days + + " days " + + hours + + " hours " + + minutes + + " minutes " + + sec + + " seconds"); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookie.java b/src/main/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookie.java index b89627b42..f9552416e 100644 --- a/src/main/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookie.java +++ b/src/main/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookie.java @@ -35,13 +35,13 @@ import org.springframework.stereotype.Component; @Component public class SpoofCookie extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A1; - } + @Override + public Category getDefaultCategory() { + return Category.A1; + } - @Override - public String getTitle() { - return "spoofcookie.title"; - } + @Override + public String getTitle() { + return "spoofcookie.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookieAssignment.java b/src/main/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookieAssignment.java index b9af34d24..2efc739f6 100644 --- a/src/main/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookieAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookieAssignment.java @@ -23,10 +23,8 @@ package org.owasp.webgoat.lessons.spoofcookie; import java.util.Map; - import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; - import org.apache.commons.lang3.StringUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; @@ -49,73 +47,79 @@ import org.springframework.web.bind.annotation.RestController; @RestController public class SpoofCookieAssignment extends AssignmentEndpoint { - private static final String COOKIE_NAME = "spoof_auth"; - private static final String COOKIE_INFO = "Cookie details for user %s:
" + COOKIE_NAME + "=%s"; - private static final String ATTACK_USERNAME = "tom"; + private static final String COOKIE_NAME = "spoof_auth"; + private static final String COOKIE_INFO = + "Cookie details for user %s:
" + COOKIE_NAME + "=%s"; + private static final String ATTACK_USERNAME = "tom"; - private static final Map users = Map.of( - "webgoat", "webgoat", - "admin", "admin", - ATTACK_USERNAME, "apasswordfortom"); + private static final Map users = + Map.of("webgoat", "webgoat", "admin", "admin", ATTACK_USERNAME, "apasswordfortom"); - @PostMapping(path = "/SpoofCookie/login") - @ResponseBody - @ExceptionHandler(UnsatisfiedServletRequestParameterException.class) - public AttackResult login( - @RequestParam String username, - @RequestParam String password, - @CookieValue(value = COOKIE_NAME, required = false) String cookieValue, - HttpServletResponse response) { + @PostMapping(path = "/SpoofCookie/login") + @ResponseBody + @ExceptionHandler(UnsatisfiedServletRequestParameterException.class) + public AttackResult login( + @RequestParam String username, + @RequestParam String password, + @CookieValue(value = COOKIE_NAME, required = false) String cookieValue, + HttpServletResponse response) { - if (StringUtils.isEmpty(cookieValue)) { - return credentialsLoginFlow(username, password, response); - } else { - return cookieLoginFlow(cookieValue); - } + if (StringUtils.isEmpty(cookieValue)) { + return credentialsLoginFlow(username, password, response); + } else { + return cookieLoginFlow(cookieValue); + } + } + + @GetMapping(path = "/SpoofCookie/cleanup") + public void cleanup(HttpServletResponse response) { + Cookie cookie = new Cookie(COOKIE_NAME, ""); + cookie.setMaxAge(0); + response.addCookie(cookie); + } + + private AttackResult credentialsLoginFlow( + String username, String password, HttpServletResponse response) { + String lowerCasedUsername = username.toLowerCase(); + if (ATTACK_USERNAME.equals(lowerCasedUsername) + && users.get(lowerCasedUsername).equals(password)) { + return informationMessage(this).feedback("spoofcookie.cheating").build(); } - @GetMapping(path = "/SpoofCookie/cleanup") - public void cleanup(HttpServletResponse response) { - Cookie cookie = new Cookie(COOKIE_NAME, ""); - cookie.setMaxAge(0); - response.addCookie(cookie); + String authPassword = users.getOrDefault(lowerCasedUsername, ""); + if (!authPassword.isBlank() && authPassword.equals(password)) { + String newCookieValue = EncDec.encode(lowerCasedUsername); + Cookie newCookie = new Cookie(COOKIE_NAME, newCookieValue); + newCookie.setPath("/WebGoat"); + newCookie.setSecure(true); + response.addCookie(newCookie); + return informationMessage(this) + .feedback("spoofcookie.login") + .output(String.format(COOKIE_INFO, lowerCasedUsername, newCookie.getValue())) + .build(); } - private AttackResult credentialsLoginFlow(String username, String password, HttpServletResponse response) { - String lowerCasedUsername = username.toLowerCase(); - if (ATTACK_USERNAME.equals(lowerCasedUsername) && users.get(lowerCasedUsername).equals(password)) { - return informationMessage(this).feedback("spoofcookie.cheating").build(); - } + return informationMessage(this).feedback("spoofcookie.wrong-login").build(); + } - String authPassword = users.getOrDefault(lowerCasedUsername, ""); - if (!authPassword.isBlank() && authPassword.equals(password)) { - String newCookieValue = EncDec.encode(lowerCasedUsername); - Cookie newCookie = new Cookie(COOKIE_NAME, newCookieValue); - newCookie.setPath("/WebGoat"); - newCookie.setSecure(true); - response.addCookie(newCookie); - return informationMessage(this).feedback("spoofcookie.login").output(String.format(COOKIE_INFO, lowerCasedUsername, newCookie.getValue())).build(); - } - - return informationMessage(this).feedback("spoofcookie.wrong-login").build(); - } - - private AttackResult cookieLoginFlow(String cookieValue) { - String cookieUsername; - try { - cookieUsername = EncDec.decode(cookieValue).toLowerCase(); - } catch (Exception e) { - // for providing some instructive guidance, we won't return 4xx error here - return failed(this).output(e.getMessage()).build(); - } - if (users.containsKey(cookieUsername)) { - if (cookieUsername.equals(ATTACK_USERNAME)) { - return success(this).build(); - } - return failed(this).feedback("spoofcookie.cookie-login").output(String.format(COOKIE_INFO, cookieUsername, cookieValue)).build(); - } - - return failed(this).feedback("spoofcookie.wrong-cookie").build(); + private AttackResult cookieLoginFlow(String cookieValue) { + String cookieUsername; + try { + cookieUsername = EncDec.decode(cookieValue).toLowerCase(); + } catch (Exception e) { + // for providing some instructive guidance, we won't return 4xx error here + return failed(this).output(e.getMessage()).build(); + } + if (users.containsKey(cookieUsername)) { + if (cookieUsername.equals(ATTACK_USERNAME)) { + return success(this).build(); + } + return failed(this) + .feedback("spoofcookie.cookie-login") + .output(String.format(COOKIE_INFO, cookieUsername, cookieValue)) + .build(); } + return failed(this).feedback("spoofcookie.wrong-cookie").build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/spoofcookie/encoders/EncDec.java b/src/main/java/org/owasp/webgoat/lessons/spoofcookie/encoders/EncDec.java index 8f933db3a..d5aa4cf7d 100644 --- a/src/main/java/org/owasp/webgoat/lessons/spoofcookie/encoders/EncDec.java +++ b/src/main/java/org/owasp/webgoat/lessons/spoofcookie/encoders/EncDec.java @@ -24,7 +24,6 @@ package org.owasp.webgoat.lessons.spoofcookie.encoders; import java.nio.charset.StandardCharsets; import java.util.Base64; - import org.apache.commons.lang3.RandomStringUtils; import org.springframework.security.crypto.codec.Hex; @@ -36,63 +35,54 @@ import org.springframework.security.crypto.codec.Hex; public class EncDec { - // PoC: weak encoding method + // PoC: weak encoding method - private static final String SALT = RandomStringUtils.randomAlphabetic(10); + private static final String SALT = RandomStringUtils.randomAlphabetic(10); - private EncDec() { + private EncDec() {} + public static String encode(final String value) { + if (value == null) { + return null; } - public static String encode(final String value) { - if (value == null) { - return null; - } + String encoded = value.toLowerCase() + SALT; + encoded = revert(encoded); + encoded = hexEncode(encoded); + return base64Encode(encoded); + } - String encoded = value.toLowerCase() + SALT; - encoded = revert(encoded); - encoded = hexEncode(encoded); - return base64Encode(encoded); + public static String decode(final String encodedValue) throws IllegalArgumentException { + if (encodedValue == null) { + return null; } - public static String decode(final String encodedValue) throws IllegalArgumentException { - if (encodedValue == null) { - return null; - } + String decoded = base64Decode(encodedValue); + decoded = hexDecode(decoded); + decoded = revert(decoded); + return decoded.substring(0, decoded.length() - SALT.length()); + } - String decoded = base64Decode(encodedValue); - decoded = hexDecode(decoded); - decoded = revert(decoded); - return decoded.substring(0, decoded.length() - SALT.length()); - } + private static String revert(final String value) { + return new StringBuilder(value).reverse().toString(); + } - private static String revert(final String value) { - return new StringBuilder(value) - .reverse() - .toString(); - } + private static String hexEncode(final String value) { + char[] encoded = Hex.encode(value.getBytes(StandardCharsets.UTF_8)); + return new String(encoded); + } - private static String hexEncode(final String value) { - char[] encoded = Hex.encode(value.getBytes(StandardCharsets.UTF_8)); - return new String(encoded); - } + private static String hexDecode(final String value) { + byte[] decoded = Hex.decode(value); + return new String(decoded); + } - private static String hexDecode(final String value) { - byte[] decoded = Hex.decode(value); - return new String(decoded); - } - - private static String base64Encode(final String value) { - return Base64 - .getEncoder() - .encodeToString(value.getBytes()); - } - - private static String base64Decode(final String value) { - byte[] decoded = Base64 - .getDecoder() - .decode(value.getBytes()); - return new String(decoded); - } + private static String base64Encode(final String value) { + return Base64.getEncoder().encodeToString(value.getBytes()); + } + private static String base64Decode(final String value) { + byte[] decoded = Base64.getDecoder().decode(value.getBytes()); + return new String(decoded); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionAdvanced.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionAdvanced.java index 39119f875..aa2492703 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionAdvanced.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionAdvanced.java @@ -28,13 +28,13 @@ import org.springframework.stereotype.Component; @Component public class SqlInjectionAdvanced extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A3; - } + @Override + public Category getDefaultCategory() { + return Category.A3; + } - @Override - public String getTitle() { - return "2.sql.advanced.title"; - } + @Override + public String getTitle() { + return "2.sql.advanced.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionChallenge.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionChallenge.java index 63efbdda0..95f86ca02 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionChallenge.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionChallenge.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.sqlinjection.advanced; +import java.sql.*; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -33,66 +34,71 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.*; - /** * @author nbaars * @since 4/8/17. */ @RestController -@AssignmentHints(value = {"SqlInjectionChallenge1", "SqlInjectionChallenge2", "SqlInjectionChallenge3"}) +@AssignmentHints( + value = {"SqlInjectionChallenge1", "SqlInjectionChallenge2", "SqlInjectionChallenge3"}) @Slf4j public class SqlInjectionChallenge extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionChallenge(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionChallenge(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PutMapping("/SqlInjectionAdvanced/challenge") - //assignment path is bounded to class so we use different http method :-) - @ResponseBody - public AttackResult registerNewUser(@RequestParam String username_reg, @RequestParam String email_reg, @RequestParam String password_reg) throws Exception { - AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg); + @PutMapping("/SqlInjectionAdvanced/challenge") + // assignment path is bounded to class so we use different http method :-) + @ResponseBody + public AttackResult registerNewUser( + @RequestParam String username_reg, + @RequestParam String email_reg, + @RequestParam String password_reg) + throws Exception { + AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg); - if (attackResult == null) { + if (attackResult == null) { + try (Connection connection = dataSource.getConnection()) { + String checkUserQuery = + "select userid from sql_challenge_users where userid = '" + username_reg + "'"; + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(checkUserQuery); - try (Connection connection = dataSource.getConnection()) { - String checkUserQuery = "select userid from sql_challenge_users where userid = '" + username_reg + "'"; - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery(checkUserQuery); - - if (resultSet.next()) { - if (username_reg.contains("tom'")) { - attackResult = success(this).feedback("user.exists").build(); - } else { - attackResult = failed(this).feedback("user.exists").feedbackArgs(username_reg).build(); - } - } else { - PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO sql_challenge_users VALUES (?, ?, ?)"); - preparedStatement.setString(1, username_reg); - preparedStatement.setString(2, email_reg); - preparedStatement.setString(3, password_reg); - preparedStatement.execute(); - attackResult = success(this).feedback("user.created").feedbackArgs(username_reg).build(); - } - } catch (SQLException e) { - attackResult = failed(this).output("Something went wrong").build(); - } + if (resultSet.next()) { + if (username_reg.contains("tom'")) { + attackResult = success(this).feedback("user.exists").build(); + } else { + attackResult = failed(this).feedback("user.exists").feedbackArgs(username_reg).build(); + } + } else { + PreparedStatement preparedStatement = + connection.prepareStatement("INSERT INTO sql_challenge_users VALUES (?, ?, ?)"); + preparedStatement.setString(1, username_reg); + preparedStatement.setString(2, email_reg); + preparedStatement.setString(3, password_reg); + preparedStatement.execute(); + attackResult = success(this).feedback("user.created").feedbackArgs(username_reg).build(); } - return attackResult; + } catch (SQLException e) { + attackResult = failed(this).output("Something went wrong").build(); + } } + return attackResult; + } - private AttackResult checkArguments(String username_reg, String email_reg, String password_reg) { - if (StringUtils.isEmpty(username_reg) || StringUtils.isEmpty(email_reg) || StringUtils.isEmpty(password_reg)) { - return failed(this).feedback("input.invalid").build(); - } - if (username_reg.length() > 250 || email_reg.length() > 30 || password_reg.length() > 30) { - return failed(this).feedback("input.invalid").build(); - } - return null; + private AttackResult checkArguments(String username_reg, String email_reg, String password_reg) { + if (StringUtils.isEmpty(username_reg) + || StringUtils.isEmpty(email_reg) + || StringUtils.isEmpty(password_reg)) { + return failed(this).feedback("input.invalid").build(); } + if (username_reg.length() > 250 || email_reg.length() > 30 || password_reg.length() > 30) { + return failed(this).feedback("input.invalid").build(); + } + return null; + } } - diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionChallengeLogin.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionChallengeLogin.java index baaa1965b..bdfcc88f2 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionChallengeLogin.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionChallengeLogin.java @@ -32,30 +32,40 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; @RestController -@AssignmentHints(value = {"SqlInjectionChallengeHint1", "SqlInjectionChallengeHint2", "SqlInjectionChallengeHint3", "SqlInjectionChallengeHint4"}) +@AssignmentHints( + value = { + "SqlInjectionChallengeHint1", + "SqlInjectionChallengeHint2", + "SqlInjectionChallengeHint3", + "SqlInjectionChallengeHint4" + }) public class SqlInjectionChallengeLogin extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionChallengeLogin(LessonDataSource dataSource) { - this.dataSource = dataSource; - } - - @PostMapping("/SqlInjectionAdvanced/challenge_Login") - @ResponseBody - public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception { - try (var connection = dataSource.getConnection()) { - var statement = connection.prepareStatement("select password from sql_challenge_users where userid = ? and password = ?"); - statement.setString(1, username_login); - statement.setString(2, password_login); - var resultSet = statement.executeQuery(); - - if (resultSet.next()) { - return ("tom".equals(username_login)) ? success(this).build() - : failed(this).feedback("ResultsButNotTom").build(); - } else { - return failed(this).feedback("NoResultsMatched").build(); - } - } + public SqlInjectionChallengeLogin(LessonDataSource dataSource) { + this.dataSource = dataSource; + } + + @PostMapping("/SqlInjectionAdvanced/challenge_Login") + @ResponseBody + public AttackResult login( + @RequestParam String username_login, @RequestParam String password_login) throws Exception { + try (var connection = dataSource.getConnection()) { + var statement = + connection.prepareStatement( + "select password from sql_challenge_users where userid = ? and password = ?"); + statement.setString(1, username_login); + statement.setString(2, password_login); + var resultSet = statement.executeQuery(); + + if (resultSet.next()) { + return ("tom".equals(username_login)) + ? success(this).build() + : failed(this).feedback("ResultsButNotTom").build(); + } else { + return failed(this).feedback("NoResultsMatched").build(); + } } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java index ef4c4c0c1..313c73910 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6a.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.sqlinjection.advanced; +import java.sql.*; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -32,67 +33,84 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.*; - - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint-advanced-6a-1", "SqlStringInjectionHint-advanced-6a-2", "SqlStringInjectionHint-advanced-6a-3", - "SqlStringInjectionHint-advanced-6a-4", "SqlStringInjectionHint-advanced-6a-5"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint-advanced-6a-1", + "SqlStringInjectionHint-advanced-6a-2", + "SqlStringInjectionHint-advanced-6a-3", + "SqlStringInjectionHint-advanced-6a-4", + "SqlStringInjectionHint-advanced-6a-5" + }) public class SqlInjectionLesson6a extends AssignmentEndpoint { - private final LessonDataSource dataSource; - private static final String YOUR_QUERY_WAS = "
Your query was: "; - public SqlInjectionLesson6a(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + private final LessonDataSource dataSource; + private static final String YOUR_QUERY_WAS = "
Your query was: "; - @PostMapping("/SqlInjectionAdvanced/attack6a") - @ResponseBody - public AttackResult completed(@RequestParam(value="userid_6a") String userId) { - return injectableQuery(userId); - // The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data -- - } + public SqlInjectionLesson6a(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - public AttackResult injectableQuery(String accountName) { - String query = ""; - try (Connection connection = dataSource.getConnection()) { - boolean usedUnion = true; - query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'"; - //Check if Union is used - if (!accountName.matches("(?i)(^[^-/*;)]*)(\\s*)UNION(.*$)")) { - usedUnion = false; - } - try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY)) { - ResultSet results = statement.executeQuery(query); + @PostMapping("/SqlInjectionAdvanced/attack6a") + @ResponseBody + public AttackResult completed(@RequestParam(value = "userid_6a") String userId) { + return injectableQuery(userId); + // The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from + // user_system_data -- + } - if ((results != null) && results.first()) { - ResultSetMetaData resultsMetaData = results.getMetaData(); - StringBuilder output = new StringBuilder(); + public AttackResult injectableQuery(String accountName) { + String query = ""; + try (Connection connection = dataSource.getConnection()) { + boolean usedUnion = true; + query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'"; + // Check if Union is used + if (!accountName.matches("(?i)(^[^-/*;)]*)(\\s*)UNION(.*$)")) { + usedUnion = false; + } + try (Statement statement = + connection.createStatement( + ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY)) { + ResultSet results = statement.executeQuery(query); - output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData)); + if ((results != null) && results.first()) { + ResultSetMetaData resultsMetaData = results.getMetaData(); + StringBuilder output = new StringBuilder(); - String appendingWhenSucceded; - if (usedUnion) - appendingWhenSucceded = "Well done! Can you also figure out a solution, by appending a new SQL Statement?"; - else - appendingWhenSucceded = "Well done! Can you also figure out a solution, by using a UNION?"; - results.last(); + output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData)); - if (output.toString().contains("dave") && output.toString().contains("passW0rD")) { - output.append(appendingWhenSucceded); - return success(this).feedback("sql-injection.advanced.6a.success").feedbackArgs(output.toString()).output(" Your query was: " + query).build(); - } else { - return failed(this).output(output.toString() + YOUR_QUERY_WAS + query).build(); - } - } else { - return failed(this).feedback("sql-injection.advanced.6a.no.results").output(YOUR_QUERY_WAS + query).build(); - } - } catch (SQLException sqle) { - return failed(this).output(sqle.getMessage() + YOUR_QUERY_WAS + query).build(); - } - } catch (Exception e) { - return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + YOUR_QUERY_WAS + query).build(); + String appendingWhenSucceded; + if (usedUnion) + appendingWhenSucceded = + "Well done! Can you also figure out a solution, by appending a new SQL Statement?"; + else + appendingWhenSucceded = + "Well done! Can you also figure out a solution, by using a UNION?"; + results.last(); + + if (output.toString().contains("dave") && output.toString().contains("passW0rD")) { + output.append(appendingWhenSucceded); + return success(this) + .feedback("sql-injection.advanced.6a.success") + .feedbackArgs(output.toString()) + .output(" Your query was: " + query) + .build(); + } else { + return failed(this).output(output.toString() + YOUR_QUERY_WAS + query).build(); + } + } else { + return failed(this) + .feedback("sql-injection.advanced.6a.no.results") + .output(YOUR_QUERY_WAS + query) + .build(); } + } catch (SQLException sqle) { + return failed(this).output(sqle.getMessage() + YOUR_QUERY_WAS + query).build(); + } + } catch (Exception e) { + return failed(this) + .output(this.getClass().getName() + " : " + e.getMessage() + YOUR_QUERY_WAS + query) + .build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6b.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6b.java index 602c921b1..5cf42437f 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6b.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionLesson6b.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,11 @@ package org.owasp.webgoat.lessons.sqlinjection.advanced; +import java.io.IOException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; @@ -31,52 +35,46 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - - @RestController public class SqlInjectionLesson6b extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson6b(LessonDataSource dataSource) { - this.dataSource = dataSource; + public SqlInjectionLesson6b(LessonDataSource dataSource) { + this.dataSource = dataSource; + } + + @PostMapping("/SqlInjectionAdvanced/attack6b") + @ResponseBody + public AttackResult completed(@RequestParam String userid_6b) throws IOException { + if (userid_6b.equals(getPassword())) { + return success(this).build(); + } else { + return failed(this).build(); } + } - @PostMapping("/SqlInjectionAdvanced/attack6b") - @ResponseBody - public AttackResult completed(@RequestParam String userid_6b) throws IOException { - if (userid_6b.equals(getPassword())) { - return success(this).build(); - } else { - return failed(this).build(); + protected String getPassword() { + String password = "dave"; + try (Connection connection = dataSource.getConnection()) { + String query = "SELECT password FROM user_system_data WHERE user_name = 'dave'"; + try { + Statement statement = + connection.createStatement( + ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + ResultSet results = statement.executeQuery(query); + + if (results != null && results.first()) { + password = results.getString("password"); } + } catch (SQLException sqle) { + sqle.printStackTrace(); + // do nothing + } + } catch (Exception e) { + e.printStackTrace(); + // do nothing } - - protected String getPassword() { - String password = "dave"; - try (Connection connection = dataSource.getConnection()) { - String query = "SELECT password FROM user_system_data WHERE user_name = 'dave'"; - try { - Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY); - ResultSet results = statement.executeQuery(query); - - if (results != null && results.first()) { - password = results.getString("password"); - } - } catch (SQLException sqle) { - sqle.printStackTrace(); - // do nothing - } - } catch (Exception e) { - e.printStackTrace(); - // do nothing - } - return (password); - } + return (password); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionQuiz.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionQuiz.java index 4e526d605..e7c03139a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionQuiz.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/advanced/SqlInjectionQuiz.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.sqlinjection.advanced; +import java.io.IOException; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.web.bind.annotation.GetMapping; @@ -30,49 +31,57 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; - /** - * add a question: 1. Append new question to JSON string - * 2. add right solution to solutions array - * 3. add Request param with name of question to method head - * For a more detailed description how to implement the quiz go to the quiz.js file in webgoat-container -> js + * add a question: 1. Append new question to JSON string 2. add right solution to solutions array 3. + * add Request param with name of question to method head For a more detailed description how to + * implement the quiz go to the quiz.js file in webgoat-container -> js */ @RestController public class SqlInjectionQuiz extends AssignmentEndpoint { - String[] solutions = {"Solution 4", "Solution 3", "Solution 2", "Solution 3", "Solution 4"}; - boolean[] guesses = new boolean[solutions.length]; + String[] solutions = {"Solution 4", "Solution 3", "Solution 2", "Solution 3", "Solution 4"}; + boolean[] guesses = new boolean[solutions.length]; - @PostMapping("/SqlInjectionAdvanced/quiz") - @ResponseBody - public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution, @RequestParam String[] question_2_solution, @RequestParam String[] question_3_solution, @RequestParam String[] question_4_solution) throws IOException { - int correctAnswers = 0; + @PostMapping("/SqlInjectionAdvanced/quiz") + @ResponseBody + public AttackResult completed( + @RequestParam String[] question_0_solution, + @RequestParam String[] question_1_solution, + @RequestParam String[] question_2_solution, + @RequestParam String[] question_3_solution, + @RequestParam String[] question_4_solution) + throws IOException { + int correctAnswers = 0; - String[] givenAnswers = {question_0_solution[0], question_1_solution[0], question_2_solution[0], question_3_solution[0], question_4_solution[0]}; + String[] givenAnswers = { + question_0_solution[0], + question_1_solution[0], + question_2_solution[0], + question_3_solution[0], + question_4_solution[0] + }; - for (int i = 0; i < solutions.length; i++) { - if (givenAnswers[i].contains(solutions[i])) { - // answer correct - correctAnswers++; - guesses[i] = true; - } else { - // answer incorrect - guesses[i] = false; - } - } - - if (correctAnswers == solutions.length) { - return success(this).build(); - } else { - return failed(this).build(); - } + for (int i = 0; i < solutions.length; i++) { + if (givenAnswers[i].contains(solutions[i])) { + // answer correct + correctAnswers++; + guesses[i] = true; + } else { + // answer incorrect + guesses[i] = false; + } } - @GetMapping("/SqlInjectionAdvanced/quiz") - @ResponseBody - public boolean[] getResults() { - return this.guesses; + if (correctAnswers == solutions.length) { + return success(this).build(); + } else { + return failed(this).build(); } + } + @GetMapping("/SqlInjectionAdvanced/quiz") + @ResponseBody + public boolean[] getResults() { + return this.guesses; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjection.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjection.java index fc76b5d49..a8f68f0f6 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjection.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjection.java @@ -28,13 +28,13 @@ import org.springframework.stereotype.Component; @Component public class SqlInjection extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A3; - } + @Override + public Category getDefaultCategory() { + return Category.A3; + } - @Override - public String getTitle() { - return "1.sql.injection.title"; - } + @Override + public String getTitle() { + return "1.sql.injection.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10.java index 89a75ab9c..55f802116 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,10 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -32,75 +35,94 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint.10.1", "SqlStringInjectionHint.10.2", "SqlStringInjectionHint.10.3", "SqlStringInjectionHint.10.4", "SqlStringInjectionHint.10.5", "SqlStringInjectionHint.10.6"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint.10.1", + "SqlStringInjectionHint.10.2", + "SqlStringInjectionHint.10.3", + "SqlStringInjectionHint.10.4", + "SqlStringInjectionHint.10.5", + "SqlStringInjectionHint.10.6" + }) public class SqlInjectionLesson10 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson10(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionLesson10(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PostMapping("/SqlInjection/attack10") - @ResponseBody - public AttackResult completed(@RequestParam String action_string) { - return injectableQueryAvailability(action_string); - } + @PostMapping("/SqlInjection/attack10") + @ResponseBody + public AttackResult completed(@RequestParam String action_string) { + return injectableQueryAvailability(action_string); + } - protected AttackResult injectableQueryAvailability(String action) { - StringBuilder output = new StringBuilder(); - String query = "SELECT * FROM access_log WHERE action LIKE '%" + action + "%'"; + protected AttackResult injectableQueryAvailability(String action) { + StringBuilder output = new StringBuilder(); + String query = "SELECT * FROM access_log WHERE action LIKE '%" + action + "%'"; - try (Connection connection = dataSource.getConnection()) { - try { - Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - ResultSet results = statement.executeQuery(query); + try (Connection connection = dataSource.getConnection()) { + try { + Statement statement = + connection.createStatement( + ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + ResultSet results = statement.executeQuery(query); - if (results.getStatement() != null) { - results.first(); - output.append(SqlInjectionLesson8.generateTable(results)); - return failed(this).feedback("sql-injection.10.entries").output(output.toString()).build(); - } else { - if (tableExists(connection)) { - return failed(this).feedback("sql-injection.10.entries").output(output.toString()).build(); - } else { - return success(this).feedback("sql-injection.10.success").build(); - } - } - } catch (SQLException e) { - if (tableExists(connection)) { - return failed(this).output("
" + output.toString()).build(); - } else { - return success(this).feedback("sql-injection.10.success").build(); - } - } - - } catch (Exception e) { - return failed(this).output("").build(); + if (results.getStatement() != null) { + results.first(); + output.append(SqlInjectionLesson8.generateTable(results)); + return failed(this) + .feedback("sql-injection.10.entries") + .output(output.toString()) + .build(); + } else { + if (tableExists(connection)) { + return failed(this) + .feedback("sql-injection.10.entries") + .output(output.toString()) + .build(); + } else { + return success(this).feedback("sql-injection.10.success").build(); + } } - } - - private boolean tableExists(Connection connection) { - try { - Statement stmt = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - ResultSet results = stmt.executeQuery("SELECT * FROM access_log"); - int cols = results.getMetaData().getColumnCount(); - return (cols > 0); - } catch (SQLException e) { - String errorMsg = e.getMessage(); - if (errorMsg.contains("object not found: ACCESS_LOG")) { - return false; - } else { - System.err.println(e.getMessage()); - return false; - } + } catch (SQLException e) { + if (tableExists(connection)) { + return failed(this) + .output( + "
" + + output.toString()) + .build(); + } else { + return success(this).feedback("sql-injection.10.success").build(); } - } + } + } catch (Exception e) { + return failed(this) + .output("") + .build(); + } + } + + private boolean tableExists(Connection connection) { + try { + Statement stmt = + connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + ResultSet results = stmt.executeQuery("SELECT * FROM access_log"); + int cols = results.getMetaData().getColumnCount(); + return (cols > 0); + } catch (SQLException e) { + String errorMsg = e.getMessage(); + if (errorMsg.contains("object not found: ACCESS_LOG")) { + return false; + } else { + System.err.println(e.getMessage()); + return false; + } + } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson2.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson2.java index 328ac3a4a..5540f31a4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson2.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson2.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,12 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import static java.sql.ResultSet.CONCUR_READ_ONLY; +import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -32,47 +37,45 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static java.sql.ResultSet.CONCUR_READ_ONLY; -import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; - - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint2-1", "SqlStringInjectionHint2-2", "SqlStringInjectionHint2-3", "SqlStringInjectionHint2-4"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint2-1", + "SqlStringInjectionHint2-2", + "SqlStringInjectionHint2-3", + "SqlStringInjectionHint2-4" + }) public class SqlInjectionLesson2 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson2(LessonDataSource dataSource) { - this.dataSource = dataSource; - } - - @PostMapping("/SqlInjection/attack2") - @ResponseBody - public AttackResult completed(@RequestParam String query) { - return injectableQuery(query); - } - - protected AttackResult injectableQuery(String query) { - try (var connection = dataSource.getConnection()) { - Statement statement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY); - ResultSet results = statement.executeQuery(query); - StringBuilder output = new StringBuilder(); - - results.first(); - - if (results.getString("department").equals("Marketing")) { - output.append(""); - output.append(SqlInjectionLesson8.generateTable(results)); - return success(this).feedback("sql-injection.2.success").output(output.toString()).build(); - } else { - return failed(this).feedback("sql-injection.2.failed").output(output.toString()).build(); - } - } catch (SQLException sqle) { - return failed(this).feedback("sql-injection.2.failed").output(sqle.getMessage()).build(); - } + public SqlInjectionLesson2(LessonDataSource dataSource) { + this.dataSource = dataSource; + } + + @PostMapping("/SqlInjection/attack2") + @ResponseBody + public AttackResult completed(@RequestParam String query) { + return injectableQuery(query); + } + + protected AttackResult injectableQuery(String query) { + try (var connection = dataSource.getConnection()) { + Statement statement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY); + ResultSet results = statement.executeQuery(query); + StringBuilder output = new StringBuilder(); + + results.first(); + + if (results.getString("department").equals("Marketing")) { + output.append(""); + output.append(SqlInjectionLesson8.generateTable(results)); + return success(this).feedback("sql-injection.2.success").output(output.toString()).build(); + } else { + return failed(this).feedback("sql-injection.2.failed").output(output.toString()).build(); + } + } catch (SQLException sqle) { + return failed(this).feedback("sql-injection.2.failed").output(sqle.getMessage()).build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson3.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson3.java index a1ec2cc40..f34c9302d 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson3.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson3.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,13 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import static java.sql.ResultSet.CONCUR_READ_ONLY; +import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -32,54 +38,47 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static java.sql.ResultSet.CONCUR_READ_ONLY; -import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; - - @RestController @AssignmentHints(value = {"SqlStringInjectionHint3-1", "SqlStringInjectionHint3-2"}) public class SqlInjectionLesson3 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson3(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionLesson3(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PostMapping("/SqlInjection/attack3") - @ResponseBody - public AttackResult completed(@RequestParam String query) { - return injectableQuery(query); - } + @PostMapping("/SqlInjection/attack3") + @ResponseBody + public AttackResult completed(@RequestParam String query) { + return injectableQuery(query); + } - protected AttackResult injectableQuery(String query) { - try (Connection connection = dataSource.getConnection()) { - try (Statement statement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY)) { - Statement checkStatement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, - CONCUR_READ_ONLY); - statement.executeUpdate(query); - ResultSet results = checkStatement.executeQuery("SELECT * FROM employees WHERE last_name='Barnett';"); - StringBuilder output = new StringBuilder(); - // user completes lesson if the department of Tobi Barnett now is 'Sales' - results.first(); - if (results.getString("department").equals("Sales")) { - output.append(""); - output.append(SqlInjectionLesson8.generateTable(results)); - return success(this).output(output.toString()).build(); - } else { - return failed(this).output(output.toString()).build(); - } - - } catch (SQLException sqle) { - return failed(this).output(sqle.getMessage()).build(); - } - } catch (Exception e) { - return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build(); + protected AttackResult injectableQuery(String query) { + try (Connection connection = dataSource.getConnection()) { + try (Statement statement = + connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY)) { + Statement checkStatement = + connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY); + statement.executeUpdate(query); + ResultSet results = + checkStatement.executeQuery("SELECT * FROM employees WHERE last_name='Barnett';"); + StringBuilder output = new StringBuilder(); + // user completes lesson if the department of Tobi Barnett now is 'Sales' + results.first(); + if (results.getString("department").equals("Sales")) { + output.append(""); + output.append(SqlInjectionLesson8.generateTable(results)); + return success(this).output(output.toString()).build(); + } else { + return failed(this).output(output.toString()).build(); } + + } catch (SQLException sqle) { + return failed(this).output(sqle.getMessage()).build(); + } + } catch (Exception e) { + return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson4.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson4.java index 28bd50d3e..2299becc4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson4.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson4.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,13 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import static java.sql.ResultSet.CONCUR_READ_ONLY; +import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -32,50 +38,43 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static java.sql.ResultSet.CONCUR_READ_ONLY; -import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE; - - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint4-1", "SqlStringInjectionHint4-2", "SqlStringInjectionHint4-3"}) +@AssignmentHints( + value = {"SqlStringInjectionHint4-1", "SqlStringInjectionHint4-2", "SqlStringInjectionHint4-3"}) public class SqlInjectionLesson4 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson4(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionLesson4(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PostMapping("/SqlInjection/attack4") - @ResponseBody - public AttackResult completed(@RequestParam String query) { - return injectableQuery(query); - } + @PostMapping("/SqlInjection/attack4") + @ResponseBody + public AttackResult completed(@RequestParam String query) { + return injectableQuery(query); + } - protected AttackResult injectableQuery(String query) { - try (Connection connection = dataSource.getConnection()) { - try (Statement statement = connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY)) { - statement.executeUpdate(query); - connection.commit(); - ResultSet results = statement.executeQuery("SELECT phone from employees;"); - StringBuilder output = new StringBuilder(); - // user completes lesson if column phone exists - if (results.first()) { - output.append(""); - return success(this).output(output.toString()).build(); - } else { - return failed(this).output(output.toString()).build(); - } - } catch (SQLException sqle) { - return failed(this).output(sqle.getMessage()).build(); - } - } catch (Exception e) { - return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build(); + protected AttackResult injectableQuery(String query) { + try (Connection connection = dataSource.getConnection()) { + try (Statement statement = + connection.createStatement(TYPE_SCROLL_INSENSITIVE, CONCUR_READ_ONLY)) { + statement.executeUpdate(query); + connection.commit(); + ResultSet results = statement.executeQuery("SELECT phone from employees;"); + StringBuilder output = new StringBuilder(); + // user completes lesson if column phone exists + if (results.first()) { + output.append(""); + return success(this).output(output.toString()).build(); + } else { + return failed(this).output(output.toString()).build(); } + } catch (SQLException sqle) { + return failed(this).output(sqle.getMessage()).build(); + } + } catch (Exception e) { + return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5.java index 9f031d45c..32db401fa 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,11 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import javax.annotation.PostConstruct; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -31,66 +35,74 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.annotation.PostConstruct; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint5-1", "SqlStringInjectionHint5-2", "SqlStringInjectionHint5-3", "SqlStringInjectionHint5-4"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint5-1", + "SqlStringInjectionHint5-2", + "SqlStringInjectionHint5-3", + "SqlStringInjectionHint5-4" + }) public class SqlInjectionLesson5 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson5(LessonDataSource dataSource) { - this.dataSource = dataSource; + public SqlInjectionLesson5(LessonDataSource dataSource) { + this.dataSource = dataSource; + } + + @PostConstruct + public void createUser() { + // HSQLDB does not support CREATE USER with IF NOT EXISTS so we need to do it in code (using + // DROP first will throw error if user does not exists) + try (Connection connection = dataSource.getConnection()) { + try (var statement = + connection.prepareStatement("CREATE USER unauthorized_user PASSWORD test")) { + statement.execute(); + } + } catch (Exception e) { + // user already exists continue } + } - @PostConstruct - public void createUser() { - // HSQLDB does not support CREATE USER with IF NOT EXISTS so we need to do it in code (using DROP first will throw error if user does not exists) - try (Connection connection = dataSource.getConnection()) { - try (var statement = connection.prepareStatement("CREATE USER unauthorized_user PASSWORD test")) { - statement.execute(); - } - } catch (Exception e) { - //user already exists continue + @PostMapping("/SqlInjection/attack5") + @ResponseBody + public AttackResult completed(String query) { + createUser(); + return injectableQuery(query); + } + + protected AttackResult injectableQuery(String query) { + try (Connection connection = dataSource.getConnection()) { + try (Statement statement = + connection.createStatement( + ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + statement.executeQuery(query); + if (checkSolution(connection)) { + return success(this).build(); } + return failed(this).output("Your query was: " + query).build(); + } + } catch (Exception e) { + return failed(this) + .output( + this.getClass().getName() + " : " + e.getMessage() + "
Your query was: " + query) + .build(); } + } - @PostMapping("/SqlInjection/attack5") - @ResponseBody - public AttackResult completed(String query) { - createUser(); - return injectableQuery(query); - } - - protected AttackResult injectableQuery(String query) { - try (Connection connection = dataSource.getConnection()) { - try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)) { - statement.executeQuery(query); - if (checkSolution(connection)) { - return success(this).build(); - } - return failed(this).output("Your query was: " + query).build(); - } - } catch (Exception e) { - return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + "
Your query was: " + query).build(); - } - } - - private boolean checkSolution(Connection connection) { - try { - var stmt = connection.prepareStatement("SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE TABLE_NAME = ? AND GRANTEE = ?"); - stmt.setString(1, "GRANT_RIGHTS"); - stmt.setString(2, "UNAUTHORIZED_USER"); - var resultSet = stmt.executeQuery(); - return resultSet.next(); - } catch (SQLException throwables) { - return false; - } - + private boolean checkSolution(Connection connection) { + try { + var stmt = + connection.prepareStatement( + "SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE TABLE_NAME = ? AND GRANTEE =" + + " ?"); + stmt.setString(1, "GRANT_RIGHTS"); + stmt.setString(2, "UNAUTHORIZED_USER"); + var resultSet = stmt.executeQuery(); + return resultSet.next(); + } catch (SQLException throwables) { + return false; } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5a.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5a.java index 0a6429ee8..59a29ff10 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5a.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5a.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import java.sql.*; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -31,90 +32,105 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.*; - - @RestController @AssignmentHints(value = {"SqlStringInjectionHint5a1"}) public class SqlInjectionLesson5a extends AssignmentEndpoint { - private static final String EXPLANATION = "
Explanation: This injection works, because or '1' = '1' " - + "always evaluates to true (The string ending literal for '1 is closed by the query itself, so you should not inject it). " - + "So the injected query basically looks like this: SELECT * FROM user_data WHERE first_name = 'John' and last_name = '' or TRUE, " - + "which will always evaluate to true, no matter what came before it."; - private final LessonDataSource dataSource; + private static final String EXPLANATION = + "
Explanation: This injection works, because or '1' =" + + " '1' always evaluates to true (The string ending literal for '1 is closed by" + + " the query itself, so you should not inject it). So the injected query basically looks" + + " like this: SELECT * FROM user_data WHERE" + + " first_name = 'John' and last_name = '' or TRUE, which will always evaluate to" + + " true, no matter what came before it."; + private final LessonDataSource dataSource; - public SqlInjectionLesson5a(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionLesson5a(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PostMapping("/SqlInjection/assignment5a") - @ResponseBody - public AttackResult completed(@RequestParam String account, @RequestParam String operator, @RequestParam String injection) { - return injectableQuery(account + " " + operator + " " + injection); - } + @PostMapping("/SqlInjection/assignment5a") + @ResponseBody + public AttackResult completed( + @RequestParam String account, @RequestParam String operator, @RequestParam String injection) { + return injectableQuery(account + " " + operator + " " + injection); + } - protected AttackResult injectableQuery(String accountName) { - String query = ""; - try (Connection connection = dataSource.getConnection()) { - query = "SELECT * FROM user_data WHERE first_name = 'John' and last_name = '" + accountName + "'"; - try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)) { - ResultSet results = statement.executeQuery(query); + protected AttackResult injectableQuery(String accountName) { + String query = ""; + try (Connection connection = dataSource.getConnection()) { + query = + "SELECT * FROM user_data WHERE first_name = 'John' and last_name = '" + accountName + "'"; + try (Statement statement = + connection.createStatement( + ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + ResultSet results = statement.executeQuery(query); - if ((results != null) && (results.first())) { - ResultSetMetaData resultsMetaData = results.getMetaData(); - StringBuilder output = new StringBuilder(); + if ((results != null) && (results.first())) { + ResultSetMetaData resultsMetaData = results.getMetaData(); + StringBuilder output = new StringBuilder(); - output.append(writeTable(results, resultsMetaData)); - results.last(); - - // If they get back more than one user they succeeded - if (results.getRow() >= 6) { - return success(this).feedback("sql-injection.5a.success").output("Your query was: " + query + EXPLANATION).feedbackArgs(output.toString()).build(); - } else { - return failed(this).output(output.toString() + "
Your query was: " + query).build(); - } - } else { - return failed(this).feedback("sql-injection.5a.no.results").output("Your query was: " + query).build(); - } - } catch (SQLException sqle) { - return failed(this).output(sqle.getMessage() + "
Your query was: " + query).build(); - } - } catch (Exception e) { - return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + "
Your query was: " + query).build(); - } - } - - public static String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws SQLException { - int numColumns = resultsMetaData.getColumnCount(); - results.beforeFirst(); - StringBuilder t = new StringBuilder(); - t.append("

"); - - if (results.next()) { - for (int i = 1; i < (numColumns + 1); i++) { - t.append(resultsMetaData.getColumnName(i)); - t.append(", "); - } - - t.append("
"); - results.beforeFirst(); - - while (results.next()) { - - for (int i = 1; i < (numColumns + 1); i++) { - t.append(results.getString(i)); - t.append(", "); - } - - t.append("
"); - } + output.append(writeTable(results, resultsMetaData)); + results.last(); + // If they get back more than one user they succeeded + if (results.getRow() >= 6) { + return success(this) + .feedback("sql-injection.5a.success") + .output("Your query was: " + query + EXPLANATION) + .feedbackArgs(output.toString()) + .build(); + } else { + return failed(this).output(output.toString() + "
Your query was: " + query).build(); + } } else { - t.append("Query Successful; however no data was returned from this query."); + return failed(this) + .feedback("sql-injection.5a.no.results") + .output("Your query was: " + query) + .build(); + } + } catch (SQLException sqle) { + return failed(this).output(sqle.getMessage() + "
Your query was: " + query).build(); + } + } catch (Exception e) { + return failed(this) + .output( + this.getClass().getName() + " : " + e.getMessage() + "
Your query was: " + query) + .build(); + } + } + + public static String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) + throws SQLException { + int numColumns = resultsMetaData.getColumnCount(); + results.beforeFirst(); + StringBuilder t = new StringBuilder(); + t.append("

"); + + if (results.next()) { + for (int i = 1; i < (numColumns + 1); i++) { + t.append(resultsMetaData.getColumnName(i)); + t.append(", "); + } + + t.append("
"); + results.beforeFirst(); + + while (results.next()) { + + for (int i = 1; i < (numColumns + 1); i++) { + t.append(results.getString(i)); + t.append(", "); } - t.append("

"); - return (t.toString()); + t.append("
"); + } + + } else { + t.append("Query Successful; however no data was returned from this query."); } + + t.append("

"); + return (t.toString()); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5b.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5b.java index e22b6e4b6..20225384f 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5b.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5b.java @@ -22,6 +22,9 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import java.io.IOException; +import java.sql.*; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -31,68 +34,102 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; -import java.sql.*; - - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint5b1", "SqlStringInjectionHint5b2", "SqlStringInjectionHint5b3", "SqlStringInjectionHint5b4"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint5b1", + "SqlStringInjectionHint5b2", + "SqlStringInjectionHint5b3", + "SqlStringInjectionHint5b4" + }) public class SqlInjectionLesson5b extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson5b(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionLesson5b(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PostMapping("/SqlInjection/assignment5b") - @ResponseBody - public AttackResult completed(@RequestParam String userid, @RequestParam String login_count, HttpServletRequest request) throws IOException { - return injectableQuery(login_count, userid); - } + @PostMapping("/SqlInjection/assignment5b") + @ResponseBody + public AttackResult completed( + @RequestParam String userid, @RequestParam String login_count, HttpServletRequest request) + throws IOException { + return injectableQuery(login_count, userid); + } - protected AttackResult injectableQuery(String login_count, String accountName) { - String queryString = "SELECT * From user_data WHERE Login_Count = ? and userid= " + accountName; - try (Connection connection = dataSource.getConnection()) { - PreparedStatement query = connection.prepareStatement(queryString, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + protected AttackResult injectableQuery(String login_count, String accountName) { + String queryString = "SELECT * From user_data WHERE Login_Count = ? and userid= " + accountName; + try (Connection connection = dataSource.getConnection()) { + PreparedStatement query = + connection.prepareStatement( + queryString, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - int count = 0; - try { - count = Integer.parseInt(login_count); - } catch (Exception e) { - return failed(this).output("Could not parse: " + login_count + " to a number" - + "
Your query was: " + queryString.replace("?", login_count)).build(); - } + int count = 0; + try { + count = Integer.parseInt(login_count); + } catch (Exception e) { + return failed(this) + .output( + "Could not parse: " + + login_count + + " to a number" + + "
Your query was: " + + queryString.replace("?", login_count)) + .build(); + } - query.setInt(1, count); - //String query = "SELECT * FROM user_data WHERE Login_Count = " + login_count + " and userid = " + accountName, ; - try { - ResultSet results = query.executeQuery(); + query.setInt(1, count); + // String query = "SELECT * FROM user_data WHERE Login_Count = " + login_count + " and userid + // = " + accountName, ; + try { + ResultSet results = query.executeQuery(); - if ((results != null) && (results.first() == true)) { - ResultSetMetaData resultsMetaData = results.getMetaData(); - StringBuilder output = new StringBuilder(); + if ((results != null) && (results.first() == true)) { + ResultSetMetaData resultsMetaData = results.getMetaData(); + StringBuilder output = new StringBuilder(); - output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData)); - results.last(); + output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData)); + results.last(); - // If they get back more than one user they succeeded - if (results.getRow() >= 6) { - return success(this).feedback("sql-injection.5b.success").output("Your query was: " + queryString.replace("?", login_count)).feedbackArgs(output.toString()).build(); - } else { - return failed(this).output(output.toString() + "
Your query was: " + queryString.replace("?", login_count)).build(); - } + // If they get back more than one user they succeeded + if (results.getRow() >= 6) { + return success(this) + .feedback("sql-injection.5b.success") + .output("Your query was: " + queryString.replace("?", login_count)) + .feedbackArgs(output.toString()) + .build(); + } else { + return failed(this) + .output( + output.toString() + + "
Your query was: " + + queryString.replace("?", login_count)) + .build(); + } - } else { - return failed(this).feedback("sql-injection.5b.no.results").output("Your query was: " + queryString.replace("?", login_count)).build(); - } - } catch (SQLException sqle) { - - return failed(this).output(sqle.getMessage() + "
Your query was: " + queryString.replace("?", login_count)).build(); - } - } catch (Exception e) { - return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + "
Your query was: " + queryString.replace("?", login_count)).build(); + } else { + return failed(this) + .feedback("sql-injection.5b.no.results") + .output("Your query was: " + queryString.replace("?", login_count)) + .build(); } + } catch (SQLException sqle) { + + return failed(this) + .output( + sqle.getMessage() + "
Your query was: " + queryString.replace("?", login_count)) + .build(); + } + } catch (Exception e) { + return failed(this) + .output( + this.getClass().getName() + + " : " + + e.getMessage() + + "
Your query was: " + + queryString.replace("?", login_count)) + .build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java index 6870708b3..ae7fbb9f4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,12 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import static java.sql.ResultSet.CONCUR_UPDATABLE; +import static java.sql.ResultSet.TYPE_SCROLL_SENSITIVE; + +import java.sql.*; +import java.text.SimpleDateFormat; +import java.util.Calendar; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -32,112 +37,127 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.*; -import java.text.SimpleDateFormat; -import java.util.Calendar; - -import static java.sql.ResultSet.CONCUR_UPDATABLE; -import static java.sql.ResultSet.TYPE_SCROLL_SENSITIVE; - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint.8.1", "SqlStringInjectionHint.8.2", "SqlStringInjectionHint.8.3", "SqlStringInjectionHint.8.4", "SqlStringInjectionHint.8.5"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint.8.1", + "SqlStringInjectionHint.8.2", + "SqlStringInjectionHint.8.3", + "SqlStringInjectionHint.8.4", + "SqlStringInjectionHint.8.5" + }) public class SqlInjectionLesson8 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson8(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionLesson8(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PostMapping("/SqlInjection/attack8") - @ResponseBody - public AttackResult completed(@RequestParam String name, @RequestParam String auth_tan) { - return injectableQueryConfidentiality(name, auth_tan); - } + @PostMapping("/SqlInjection/attack8") + @ResponseBody + public AttackResult completed(@RequestParam String name, @RequestParam String auth_tan) { + return injectableQueryConfidentiality(name, auth_tan); + } - protected AttackResult injectableQueryConfidentiality(String name, String auth_tan) { - StringBuilder output = new StringBuilder(); - String query = "SELECT * FROM employees WHERE last_name = '" + name + "' AND auth_tan = '" + auth_tan + "'"; + protected AttackResult injectableQueryConfidentiality(String name, String auth_tan) { + StringBuilder output = new StringBuilder(); + String query = + "SELECT * FROM employees WHERE last_name = '" + + name + + "' AND auth_tan = '" + + auth_tan + + "'"; - try (Connection connection = dataSource.getConnection()) { - try { - Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); - log(connection, query); - ResultSet results = statement.executeQuery(query); + try (Connection connection = dataSource.getConnection()) { + try { + Statement statement = + connection.createStatement( + ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE); + log(connection, query); + ResultSet results = statement.executeQuery(query); - if (results.getStatement() != null) { - if (results.first()) { - output.append(generateTable(results)); - results.last(); + if (results.getStatement() != null) { + if (results.first()) { + output.append(generateTable(results)); + results.last(); - if (results.getRow() > 1) { - // more than one record, the user succeeded - return success(this).feedback("sql-injection.8.success").output(output.toString()).build(); - } else { - // only one record - return failed(this).feedback("sql-injection.8.one").output(output.toString()).build(); - } - - } else { - // no results - return failed(this).feedback("sql-injection.8.no.results").build(); - } - } else { - return failed(this).build(); - } - } catch (SQLException e) { - return failed(this).output("
").build(); - } - - } catch (Exception e) { - return failed(this).output("
").build(); - } - } - - public static String generateTable(ResultSet results) throws SQLException { - ResultSetMetaData resultsMetaData = results.getMetaData(); - int numColumns = resultsMetaData.getColumnCount(); - results.beforeFirst(); - StringBuilder table = new StringBuilder(); - table.append(""); - - if (results.next()) { - table.append(""); - for (int i = 1; i < (numColumns + 1); i++) { - table.append(""); - } - table.append(""); - - results.beforeFirst(); - while (results.next()) { - table.append(""); - for (int i = 1; i < (numColumns + 1); i++) { - table.append(""); - } - table.append(""); + if (results.getRow() > 1) { + // more than one record, the user succeeded + return success(this) + .feedback("sql-injection.8.success") + .output(output.toString()) + .build(); + } else { + // only one record + return failed(this).feedback("sql-injection.8.one").output(output.toString()).build(); } + } else { + // no results + return failed(this).feedback("sql-injection.8.no.results").build(); + } } else { - table.append("Query Successful; however no data was returned from this query."); + return failed(this).build(); } + } catch (SQLException e) { + return failed(this) + .output("
") + .build(); + } - table.append("
" + resultsMetaData.getColumnName(i) + "
" + results.getString(i) + "
"); - return (table.toString()); + } catch (Exception e) { + return failed(this) + .output("
") + .build(); + } + } + + public static String generateTable(ResultSet results) throws SQLException { + ResultSetMetaData resultsMetaData = results.getMetaData(); + int numColumns = resultsMetaData.getColumnCount(); + results.beforeFirst(); + StringBuilder table = new StringBuilder(); + table.append(""); + + if (results.next()) { + table.append(""); + for (int i = 1; i < (numColumns + 1); i++) { + table.append(""); + } + table.append(""); + + results.beforeFirst(); + while (results.next()) { + table.append(""); + for (int i = 1; i < (numColumns + 1); i++) { + table.append(""); + } + table.append(""); + } + + } else { + table.append("Query Successful; however no data was returned from this query."); } - public static void log(Connection connection, String action) { - action = action.replace('\'', '"'); - Calendar cal = Calendar.getInstance(); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - String time = sdf.format(cal.getTime()); + table.append("
" + resultsMetaData.getColumnName(i) + "
" + results.getString(i) + "
"); + return (table.toString()); + } - String logQuery = "INSERT INTO access_log (time, action) VALUES ('" + time + "', '" + action + "')"; + public static void log(Connection connection, String action) { + action = action.replace('\'', '"'); + Calendar cal = Calendar.getInstance(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String time = sdf.format(cal.getTime()); - try { - Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); - statement.executeUpdate(logQuery); - } catch (SQLException e) { - System.err.println(e.getMessage()); - } + String logQuery = + "INSERT INTO access_log (time, action) VALUES ('" + time + "', '" + action + "')"; + + try { + Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); + statement.executeUpdate(logQuery); + } catch (SQLException e) { + System.err.println(e.getMessage()); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java index 1377ea5eb..3df08175a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,13 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; +import static org.hsqldb.jdbc.JDBCResultSet.CONCUR_UPDATABLE; +import static org.hsqldb.jdbc.JDBCResultSet.TYPE_SCROLL_SENSITIVE; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -32,79 +38,91 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import static org.hsqldb.jdbc.JDBCResultSet.CONCUR_UPDATABLE; -import static org.hsqldb.jdbc.JDBCResultSet.TYPE_SCROLL_SENSITIVE; - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint.9.1", "SqlStringInjectionHint.9.2", "SqlStringInjectionHint.9.3", "SqlStringInjectionHint.9.4", "SqlStringInjectionHint.9.5"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint.9.1", + "SqlStringInjectionHint.9.2", + "SqlStringInjectionHint.9.3", + "SqlStringInjectionHint.9.4", + "SqlStringInjectionHint.9.5" + }) public class SqlInjectionLesson9 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson9(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionLesson9(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PostMapping("/SqlInjection/attack9") - @ResponseBody - public AttackResult completed(@RequestParam String name, @RequestParam String auth_tan) { - return injectableQueryIntegrity(name, auth_tan); - } + @PostMapping("/SqlInjection/attack9") + @ResponseBody + public AttackResult completed(@RequestParam String name, @RequestParam String auth_tan) { + return injectableQueryIntegrity(name, auth_tan); + } - protected AttackResult injectableQueryIntegrity(String name, String auth_tan) { - StringBuilder output = new StringBuilder(); - String query = "SELECT * FROM employees WHERE last_name = '" + name + "' AND auth_tan = '" + auth_tan + "'"; - try (Connection connection = dataSource.getConnection()) { - try { - Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); - SqlInjectionLesson8.log(connection, query); - ResultSet results = statement.executeQuery(query); - var test = results.getRow() != 0; - if (results.getStatement() != null) { - if (results.first()) { - output.append(SqlInjectionLesson8.generateTable(results)); - } else { - // no results - return failed(this).feedback("sql-injection.8.no.results").build(); - } - } - } catch (SQLException e) { - System.err.println(e.getMessage()); - return failed(this).output("
").build(); - } - - return checkSalaryRanking(connection, output); - - } catch (Exception e) { - System.err.println(e.getMessage()); - return failed(this).output("
").build(); + protected AttackResult injectableQueryIntegrity(String name, String auth_tan) { + StringBuilder output = new StringBuilder(); + String query = + "SELECT * FROM employees WHERE last_name = '" + + name + + "' AND auth_tan = '" + + auth_tan + + "'"; + try (Connection connection = dataSource.getConnection()) { + try { + Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); + SqlInjectionLesson8.log(connection, query); + ResultSet results = statement.executeQuery(query); + var test = results.getRow() != 0; + if (results.getStatement() != null) { + if (results.first()) { + output.append(SqlInjectionLesson8.generateTable(results)); + } else { + // no results + return failed(this).feedback("sql-injection.8.no.results").build(); + } } + } catch (SQLException e) { + System.err.println(e.getMessage()); + return failed(this) + .output("
") + .build(); + } + + return checkSalaryRanking(connection, output); + + } catch (Exception e) { + System.err.println(e.getMessage()); + return failed(this) + .output("
") + .build(); } + } - private AttackResult checkSalaryRanking(Connection connection, StringBuilder output) { - try { - String query = "SELECT * FROM employees ORDER BY salary DESC"; - try (Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); - ) { - ResultSet results = statement.executeQuery(query); + private AttackResult checkSalaryRanking(Connection connection, StringBuilder output) { + try { + String query = "SELECT * FROM employees ORDER BY salary DESC"; + try (Statement statement = + connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); ) { + ResultSet results = statement.executeQuery(query); - results.first(); - // user completes lesson if John Smith is the first in the list - if ((results.getString(2).equals("John")) && (results.getString(3).equals("Smith"))) { - output.append(SqlInjectionLesson8.generateTable(results)); - return success(this).feedback("sql-injection.9.success").output(output.toString()).build(); - } else { - return failed(this).feedback("sql-injection.9.one").output(output.toString()).build(); - } - } - } catch (SQLException e) { - return failed(this).output("
").build(); + results.first(); + // user completes lesson if John Smith is the first in the list + if ((results.getString(2).equals("John")) && (results.getString(3).equals("Smith"))) { + output.append(SqlInjectionLesson8.generateTable(results)); + return success(this) + .feedback("sql-injection.9.success") + .output(output.toString()) + .build(); + } else { + return failed(this).feedback("sql-injection.9.one").output(output.toString()).build(); } + } + } catch (SQLException e) { + return failed(this) + .output("
") + .build(); } - + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/Servers.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/Servers.java index 078f18d44..083e57061 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/Servers.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/Servers.java @@ -22,6 +22,8 @@ package org.owasp.webgoat.lessons.sqlinjection.mitigation; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -33,9 +35,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.ArrayList; -import java.util.List; - /** * @author nbaars * @since 6/13/17. @@ -45,40 +44,50 @@ import java.util.List; @Slf4j public class Servers { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - @AllArgsConstructor - @Getter - private class Server { + @AllArgsConstructor + @Getter + private class Server { - private String id; - private String hostname; - private String ip; - private String mac; - private String status; - private String description; - } + private String id; + private String hostname; + private String ip; + private String mac; + private String status; + private String description; + } - public Servers(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public Servers(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public List sort(@RequestParam String column) throws Exception { - List servers = new ArrayList<>(); + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public List sort(@RequestParam String column) throws Exception { + List servers = new ArrayList<>(); - try (var connection = dataSource.getConnection()) { - try (var statement = connection.prepareStatement("select id, hostname, ip, mac, status, description from SERVERS where status <> 'out of order' order by " + column)) { - try (var rs = statement.executeQuery()) { - while (rs.next()) { - Server server = new Server(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6)); - servers.add(server); - } - } - } + try (var connection = dataSource.getConnection()) { + try (var statement = + connection.prepareStatement( + "select id, hostname, ip, mac, status, description from SERVERS where status <> 'out" + + " of order' order by " + + column)) { + try (var rs = statement.executeQuery()) { + while (rs.next()) { + Server server = + new Server( + rs.getString(1), + rs.getString(2), + rs.getString(3), + rs.getString(4), + rs.getString(5), + rs.getString(6)); + servers.add(server); + } } - return servers; + } } - + return servers; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson10a.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson10a.java index 9c1c5a902..fbe551427 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson10a.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson10a.java @@ -33,28 +33,38 @@ import org.springframework.web.bind.annotation.RestController; @RestController @Slf4j -@AssignmentHints(value = {"SqlStringInjectionHint-mitigation-10a-1", "SqlStringInjectionHint-mitigation-10a-2"}) +@AssignmentHints( + value = {"SqlStringInjectionHint-mitigation-10a-1", "SqlStringInjectionHint-mitigation-10a-2"}) public class SqlInjectionLesson10a extends AssignmentEndpoint { - private String[] results = {"getConnection", "PreparedStatement", "prepareStatement", "?", "?", "setString", "setString"}; + private String[] results = { + "getConnection", "PreparedStatement", "prepareStatement", "?", "?", "setString", "setString" + }; - @PostMapping("/SqlInjectionMitigations/attack10a") - @ResponseBody - public AttackResult completed(@RequestParam String field1, @RequestParam String field2, @RequestParam String field3, @RequestParam String field4, @RequestParam String field5, @RequestParam String field6, @RequestParam String field7) { - String[] userInput = {field1, field2, field3, field4, field5, field6, field7}; - int position = 0; - boolean completed = false; - for (String input : userInput) { - if (input.toLowerCase().contains(this.results[position].toLowerCase())) { - completed = true; - } else { - return failed(this).build(); - } - position++; - } - if (completed) { - return success(this).build(); - } + @PostMapping("/SqlInjectionMitigations/attack10a") + @ResponseBody + public AttackResult completed( + @RequestParam String field1, + @RequestParam String field2, + @RequestParam String field3, + @RequestParam String field4, + @RequestParam String field5, + @RequestParam String field6, + @RequestParam String field7) { + String[] userInput = {field1, field2, field3, field4, field5, field6, field7}; + int position = 0; + boolean completed = false; + for (String input : userInput) { + if (input.toLowerCase().contains(this.results[position].toLowerCase())) { + completed = true; + } else { return failed(this).build(); + } + position++; } + if (completed) { + return success(this).build(); + } + return failed(this).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson10b.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson10b.java index 106cf457e..325d376bb 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson10b.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson10b.java @@ -22,6 +22,19 @@ package org.owasp.webgoat.lessons.sqlinjection.mitigation; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -30,108 +43,112 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.tools.Diagnostic; -import javax.tools.DiagnosticCollector; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.ToolProvider; -import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint-mitigation-10b-1", "SqlStringInjectionHint-mitigation-10b-2", "SqlStringInjectionHint-mitigation-10b-3", "SqlStringInjectionHint-mitigation-10b-4", "SqlStringInjectionHint-mitigation-10b-5"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint-mitigation-10b-1", + "SqlStringInjectionHint-mitigation-10b-2", + "SqlStringInjectionHint-mitigation-10b-3", + "SqlStringInjectionHint-mitigation-10b-4", + "SqlStringInjectionHint-mitigation-10b-5" + }) public class SqlInjectionLesson10b extends AssignmentEndpoint { - @PostMapping("/SqlInjectionMitigations/attack10b") - @ResponseBody - public AttackResult completed(@RequestParam String editor) { - try { - if (editor.isEmpty()) return failed(this).feedback("sql-injection.10b.no-code").build(); + @PostMapping("/SqlInjectionMitigations/attack10b") + @ResponseBody + public AttackResult completed(@RequestParam String editor) { + try { + if (editor.isEmpty()) return failed(this).feedback("sql-injection.10b.no-code").build(); - editor = editor.replaceAll("\\<.*?>", ""); + editor = editor.replaceAll("\\<.*?>", ""); - String regexSetsUpConnection = "(?=.*getConnection.*)"; - String regexUsesPreparedStatement = "(?=.*PreparedStatement.*)"; - String regexUsesPlaceholder = "(?=.*\\=\\?.*|.*\\=\\s\\?.*)"; - String regexUsesSetString = "(?=.*setString.*)"; - String regexUsesExecute = "(?=.*execute.*)"; - String regexUsesExecuteUpdate = "(?=.*executeUpdate.*)"; + String regexSetsUpConnection = "(?=.*getConnection.*)"; + String regexUsesPreparedStatement = "(?=.*PreparedStatement.*)"; + String regexUsesPlaceholder = "(?=.*\\=\\?.*|.*\\=\\s\\?.*)"; + String regexUsesSetString = "(?=.*setString.*)"; + String regexUsesExecute = "(?=.*execute.*)"; + String regexUsesExecuteUpdate = "(?=.*executeUpdate.*)"; - String codeline = editor.replace("\n", "").replace("\r", ""); + String codeline = editor.replace("\n", "").replace("\r", ""); - boolean setsUpConnection = this.check_text(regexSetsUpConnection, codeline); - boolean usesPreparedStatement = this.check_text(regexUsesPreparedStatement, codeline); - boolean usesSetString = this.check_text(regexUsesSetString, codeline); - boolean usesPlaceholder = this.check_text(regexUsesPlaceholder, codeline); - boolean usesExecute = this.check_text(regexUsesExecute, codeline); - boolean usesExecuteUpdate = this.check_text(regexUsesExecuteUpdate, codeline); + boolean setsUpConnection = this.check_text(regexSetsUpConnection, codeline); + boolean usesPreparedStatement = this.check_text(regexUsesPreparedStatement, codeline); + boolean usesSetString = this.check_text(regexUsesSetString, codeline); + boolean usesPlaceholder = this.check_text(regexUsesPlaceholder, codeline); + boolean usesExecute = this.check_text(regexUsesExecute, codeline); + boolean usesExecuteUpdate = this.check_text(regexUsesExecuteUpdate, codeline); - boolean hasImportant = (setsUpConnection && usesPreparedStatement && usesPlaceholder && usesSetString && (usesExecute || usesExecuteUpdate)); - List hasCompiled = this.compileFromString(editor); + boolean hasImportant = + (setsUpConnection + && usesPreparedStatement + && usesPlaceholder + && usesSetString + && (usesExecute || usesExecuteUpdate)); + List hasCompiled = this.compileFromString(editor); - if (hasImportant && hasCompiled.size() < 1) { - return success(this).feedback("sql-injection.10b.success").build(); - } else if (hasCompiled.size() > 0) { - String errors = ""; - for (Diagnostic d : hasCompiled) { - errors += d.getMessage(null) + "
"; - } - return failed(this).feedback("sql-injection.10b.compiler-errors").output(errors).build(); - } else { - return failed(this).feedback("sql-injection.10b.failed").build(); - } - } catch (Exception e) { - return failed(this).output(e.getMessage()).build(); + if (hasImportant && hasCompiled.size() < 1) { + return success(this).feedback("sql-injection.10b.success").build(); + } else if (hasCompiled.size() > 0) { + String errors = ""; + for (Diagnostic d : hasCompiled) { + errors += d.getMessage(null) + "
"; } + return failed(this).feedback("sql-injection.10b.compiler-errors").output(errors).build(); + } else { + return failed(this).feedback("sql-injection.10b.failed").build(); + } + } catch (Exception e) { + return failed(this).output(e.getMessage()).build(); + } + } + + private List compileFromString(String s) { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + DiagnosticCollector diagnosticsCollector = new DiagnosticCollector(); + StandardJavaFileManager fileManager = + compiler.getStandardFileManager(diagnosticsCollector, null, null); + JavaFileObject javaObjectFromString = getJavaFileContentsAsString(s); + Iterable fileObjects = Arrays.asList(javaObjectFromString); + JavaCompiler.CompilationTask task = + compiler.getTask(null, fileManager, diagnosticsCollector, null, null, fileObjects); + Boolean result = task.call(); + List diagnostics = diagnosticsCollector.getDiagnostics(); + return diagnostics; + } + + private SimpleJavaFileObject getJavaFileContentsAsString(String s) { + StringBuilder javaFileContents = + new StringBuilder( + "import java.sql.*; public class TestClass { static String DBUSER; static String DBPW;" + + " static String DBURL; public static void main(String[] args) {" + + s + + "}}"); + JavaObjectFromString javaFileObject = null; + try { + javaFileObject = new JavaObjectFromString("TestClass.java", javaFileContents.toString()); + } catch (Exception exception) { + exception.printStackTrace(); + } + return javaFileObject; + } + + class JavaObjectFromString extends SimpleJavaFileObject { + private String contents = null; + + public JavaObjectFromString(String className, String contents) throws Exception { + super(new URI(className), Kind.SOURCE); + this.contents = contents; } - private List compileFromString(String s) { - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - DiagnosticCollector diagnosticsCollector = new DiagnosticCollector(); - StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticsCollector, null, null); - JavaFileObject javaObjectFromString = getJavaFileContentsAsString(s); - Iterable fileObjects = Arrays.asList(javaObjectFromString); - JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnosticsCollector, null, null, fileObjects); - Boolean result = task.call(); - List diagnostics = diagnosticsCollector.getDiagnostics(); - return diagnostics; + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return contents; } + } - private SimpleJavaFileObject getJavaFileContentsAsString(String s) { - StringBuilder javaFileContents = new StringBuilder("import java.sql.*; public class TestClass { static String DBUSER; static String DBPW; static String DBURL; public static void main(String[] args) {" + s + "}}"); - JavaObjectFromString javaFileObject = null; - try { - javaFileObject = new JavaObjectFromString("TestClass.java", javaFileContents.toString()); - } catch (Exception exception) { - exception.printStackTrace(); - } - return javaFileObject; - } - - class JavaObjectFromString extends SimpleJavaFileObject { - private String contents = null; - - public JavaObjectFromString(String className, String contents) throws Exception { - super(new URI(className), Kind.SOURCE); - this.contents = contents; - } - - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - return contents; - } - } - - private boolean check_text(String regex, String text) { - Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); - Matcher m = p.matcher(text); - if (m.find()) - return true; - else return false; - } + private boolean check_text(String regex, String text) { + Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + Matcher m = p.matcher(text); + if (m.find()) return true; + else return false; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson13.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson13.java index c94e65b67..453f0e3e1 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson13.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson13.java @@ -22,6 +22,10 @@ package org.owasp.webgoat.lessons.sqlinjection.mitigation; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.LessonDataSource; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -32,37 +36,39 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - @RestController -@AssignmentHints(value = {"SqlStringInjectionHint-mitigation-13-1", "SqlStringInjectionHint-mitigation-13-2", "SqlStringInjectionHint-mitigation-13-3", "SqlStringInjectionHint-mitigation-13-4"}) +@AssignmentHints( + value = { + "SqlStringInjectionHint-mitigation-13-1", + "SqlStringInjectionHint-mitigation-13-2", + "SqlStringInjectionHint-mitigation-13-3", + "SqlStringInjectionHint-mitigation-13-4" + }) @Slf4j public class SqlInjectionLesson13 extends AssignmentEndpoint { - private final LessonDataSource dataSource; + private final LessonDataSource dataSource; - public SqlInjectionLesson13(LessonDataSource dataSource) { - this.dataSource = dataSource; - } + public SqlInjectionLesson13(LessonDataSource dataSource) { + this.dataSource = dataSource; + } - @PostMapping("/SqlInjectionMitigations/attack12a") - @ResponseBody - public AttackResult completed(@RequestParam String ip) { - try (Connection connection = dataSource.getConnection(); - PreparedStatement preparedStatement = connection.prepareStatement("select ip from servers where ip = ? and hostname = ?")) { - preparedStatement.setString(1, ip); - preparedStatement.setString(2, "webgoat-prd"); - ResultSet resultSet = preparedStatement.executeQuery(); - if (resultSet.next()) { - return success(this).build(); - } - return failed(this).build(); - } catch (SQLException e) { - log.error("Failed", e); - return (failed(this).build()); - } + @PostMapping("/SqlInjectionMitigations/attack12a") + @ResponseBody + public AttackResult completed(@RequestParam String ip) { + try (Connection connection = dataSource.getConnection(); + PreparedStatement preparedStatement = + connection.prepareStatement("select ip from servers where ip = ? and hostname = ?")) { + preparedStatement.setString(1, ip); + preparedStatement.setString(2, "webgoat-prd"); + ResultSet resultSet = preparedStatement.executeQuery(); + if (resultSet.next()) { + return success(this).build(); + } + return failed(this).build(); + } catch (SQLException e) { + log.error("Failed", e); + return (failed(this).build()); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionMitigations.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionMitigations.java index 417790c45..8ed3e0c1b 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionMitigations.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionMitigations.java @@ -28,13 +28,13 @@ import org.springframework.stereotype.Component; @Component public class SqlInjectionMitigations extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A3; - } + @Override + public Category getDefaultCategory() { + return Category.A3; + } - @Override - public String getTitle() { - return "3.sql.mitigation.title"; - } + @Override + public String getTitle() { + return "3.sql.mitigation.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidation.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidation.java index 42136180e..4cfec6337 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidation.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidation.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -32,24 +31,29 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; - @RestController -@AssignmentHints(value = {"SqlOnlyInputValidation-1", "SqlOnlyInputValidation-2", "SqlOnlyInputValidation-3"}) +@AssignmentHints( + value = {"SqlOnlyInputValidation-1", "SqlOnlyInputValidation-2", "SqlOnlyInputValidation-3"}) public class SqlOnlyInputValidation extends AssignmentEndpoint { - private final SqlInjectionLesson6a lesson6a; + private final SqlInjectionLesson6a lesson6a; - public SqlOnlyInputValidation(SqlInjectionLesson6a lesson6a) { - this.lesson6a = lesson6a; - } + public SqlOnlyInputValidation(SqlInjectionLesson6a lesson6a) { + this.lesson6a = lesson6a; + } - @PostMapping("/SqlOnlyInputValidation/attack") - @ResponseBody - public AttackResult attack(@RequestParam("userid_sql_only_input_validation") String userId) { - if (userId.contains(" ")) { - return failed(this).feedback("SqlOnlyInputValidation-failed").build(); - } - AttackResult attackResult = lesson6a.injectableQuery(userId); - return new AttackResult(attackResult.isLessonCompleted(), attackResult.getFeedback(), attackResult.getOutput(), getClass().getSimpleName(), true); + @PostMapping("/SqlOnlyInputValidation/attack") + @ResponseBody + public AttackResult attack(@RequestParam("userid_sql_only_input_validation") String userId) { + if (userId.contains(" ")) { + return failed(this).feedback("SqlOnlyInputValidation-failed").build(); } + AttackResult attackResult = lesson6a.injectableQuery(userId); + return new AttackResult( + attackResult.isLessonCompleted(), + attackResult.getFeedback(), + attackResult.getOutput(), + getClass().getSimpleName(), + true); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywords.java b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywords.java index 5e93dae55..3a324bc65 100644 --- a/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywords.java +++ b/src/main/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywords.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -32,25 +31,35 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; - @RestController -@AssignmentHints(value = {"SqlOnlyInputValidationOnKeywords-1", "SqlOnlyInputValidationOnKeywords-2", "SqlOnlyInputValidationOnKeywords-3"}) +@AssignmentHints( + value = { + "SqlOnlyInputValidationOnKeywords-1", + "SqlOnlyInputValidationOnKeywords-2", + "SqlOnlyInputValidationOnKeywords-3" + }) public class SqlOnlyInputValidationOnKeywords extends AssignmentEndpoint { - private final SqlInjectionLesson6a lesson6a; + private final SqlInjectionLesson6a lesson6a; - public SqlOnlyInputValidationOnKeywords(SqlInjectionLesson6a lesson6a) { - this.lesson6a = lesson6a; - } + public SqlOnlyInputValidationOnKeywords(SqlInjectionLesson6a lesson6a) { + this.lesson6a = lesson6a; + } - @PostMapping("/SqlOnlyInputValidationOnKeywords/attack") - @ResponseBody - public AttackResult attack(@RequestParam("userid_sql_only_input_validation_on_keywords") String userId) { - userId = userId.toUpperCase().replace("FROM", "").replace("SELECT", ""); - if (userId.contains(" ")) { - return failed(this).feedback("SqlOnlyInputValidationOnKeywords-failed").build(); - } - AttackResult attackResult = lesson6a.injectableQuery(userId); - return new AttackResult(attackResult.isLessonCompleted(), attackResult.getFeedback(), attackResult.getOutput(), getClass().getSimpleName(), true); + @PostMapping("/SqlOnlyInputValidationOnKeywords/attack") + @ResponseBody + public AttackResult attack( + @RequestParam("userid_sql_only_input_validation_on_keywords") String userId) { + userId = userId.toUpperCase().replace("FROM", "").replace("SELECT", ""); + if (userId.contains(" ")) { + return failed(this).feedback("SqlOnlyInputValidationOnKeywords-failed").build(); } + AttackResult attackResult = lesson6a.injectableQuery(userId); + return new AttackResult( + attackResult.isLessonCompleted(), + attackResult.getFeedback(), + attackResult.getOutput(), + getClass().getSimpleName(), + true); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRF.java b/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRF.java index d82cf3d9d..7a4d788d2 100644 --- a/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRF.java +++ b/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRF.java @@ -8,25 +8,26 @@ import org.springframework.stereotype.Component; * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -35,13 +36,13 @@ import org.springframework.stereotype.Component; */ @Component public class SSRF extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A10; - } + @Override + public Category getDefaultCategory() { + return Category.A10; + } - @Override - public String getTitle() { - return "ssrf.title"; - } + @Override + public String getTitle() { + return "ssrf.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask1.java b/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask1.java index 6f12b3d9d..210c98421 100644 --- a/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask1.java +++ b/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask1.java @@ -30,45 +30,37 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; - @RestController @AssignmentHints({"ssrf.hint1", "ssrf.hint2"}) public class SSRFTask1 extends AssignmentEndpoint { - @PostMapping("/SSRF/task1") - @ResponseBody - public AttackResult completed(@RequestParam String url) { - return stealTheCheese(url); - } + @PostMapping("/SSRF/task1") + @ResponseBody + public AttackResult completed(@RequestParam String url) { + return stealTheCheese(url); + } - protected AttackResult stealTheCheese(String url) { - try { - StringBuilder html = new StringBuilder(); + protected AttackResult stealTheCheese(String url) { + try { + StringBuilder html = new StringBuilder(); - if (url.matches("images/tom.png")) { - html.append("\"Tom\""); - return failed(this) - .feedback("ssrf.tom") - .output(html.toString()) - .build(); - } else if (url.matches("images/jerry.png")) { - html.append("\"Jerry\""); - return success(this) - .feedback("ssrf.success") - .output(html.toString()) - .build(); - } else { - html.append("\"Silly"); - return failed(this) - .feedback("ssrf.failure") - .output(html.toString()) - .build(); - } - } catch (Exception e) { - e.printStackTrace(); - return failed(this) - .output(e.getMessage()) - .build(); - } + if (url.matches("images/tom.png")) { + html.append( + "\"Tom\""); + return failed(this).feedback("ssrf.tom").output(html.toString()).build(); + } else if (url.matches("images/jerry.png")) { + html.append( + "\"Jerry\""); + return success(this).feedback("ssrf.success").output(html.toString()).build(); + } else { + html.append("\"Silly"); + return failed(this).feedback("ssrf.failure").output(html.toString()).build(); + } + } catch (Exception e) { + e.printStackTrace(); + return failed(this).output(e.getMessage()).build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask2.java b/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask2.java index 4dd4f2759..cb58bd63d 100644 --- a/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask2.java +++ b/src/main/java/org/owasp/webgoat/lessons/ssrf/SSRFTask2.java @@ -22,6 +22,11 @@ package org.owasp.webgoat.lessons.ssrf; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.StandardCharsets; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -30,49 +35,38 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.nio.charset.StandardCharsets; - - @RestController @AssignmentHints({"ssrf.hint3"}) public class SSRFTask2 extends AssignmentEndpoint { - @PostMapping("/SSRF/task2") - @ResponseBody - public AttackResult completed(@RequestParam String url) { - return furBall(url); - } + @PostMapping("/SSRF/task2") + @ResponseBody + public AttackResult completed(@RequestParam String url) { + return furBall(url); + } - protected AttackResult furBall(String url) { - if (url.matches("http://ifconfig.pro")) { - String html; - try (InputStream in = new URL(url).openStream()) { - html = new String(in.readAllBytes(), StandardCharsets.UTF_8) - .replaceAll("\n","
"); // Otherwise the \n gets escaped in the response - } catch (MalformedURLException e) { - return getFailedResult(e.getMessage()); - } catch (IOException e) { - //in case the external site is down, the test and lesson should still be ok - html = "Although the http://ifconfig.pro site is down, you still managed to solve" + - " this exercise the right way!"; - } - return success(this) - .feedback("ssrf.success") - .output(html) - .build(); - } - var html = "\"image"; - return getFailedResult(html); + protected AttackResult furBall(String url) { + if (url.matches("http://ifconfig.pro")) { + String html; + try (InputStream in = new URL(url).openStream()) { + html = + new String(in.readAllBytes(), StandardCharsets.UTF_8) + .replaceAll("\n", "
"); // Otherwise the \n gets escaped in the response + } catch (MalformedURLException e) { + return getFailedResult(e.getMessage()); + } catch (IOException e) { + // in case the external site is down, the test and lesson should still be ok + html = + "Although the http://ifconfig.pro site is down, you still managed to solve" + + " this exercise the right way!"; + } + return success(this).feedback("ssrf.success").output(html).build(); } + var html = "\"image"; + return getFailedResult(html); + } - private AttackResult getFailedResult(String errorMsg) { - return failed(this) - .feedback("ssrf.failure") - .output(errorMsg) - .build(); - } + private AttackResult getFailedResult(String errorMsg) { + return failed(this).feedback("ssrf.failure").output(errorMsg).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/Contact.java b/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/Contact.java index 4b603b993..32c4df24a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/Contact.java +++ b/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/Contact.java @@ -24,12 +24,19 @@ package org.owasp.webgoat.lessons.vulnerablecomponents; public interface Contact { - public Integer getId(); - public void setId(Integer id); - public String getFirstName(); - public void setFirstName(String firstName); - public String getLastName(); - public void setLastName(String lastName); - public String getEmail(); - public void setEmail(String email); + public Integer getId(); + + public void setId(Integer id); + + public String getFirstName(); + + public void setFirstName(String firstName); + + public String getLastName(); + + public void setLastName(String lastName); + + public String getEmail(); + + public void setEmail(String email); } diff --git a/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/ContactImpl.java b/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/ContactImpl.java index 541b18bfb..f69b253e7 100644 --- a/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/ContactImpl.java +++ b/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/ContactImpl.java @@ -27,9 +27,8 @@ import lombok.Data; @Data public class ContactImpl implements Contact { - private Integer id; - private String firstName; - private String lastName; - private String email; - + private Integer id; + private String firstName; + private String lastName; + private String email; } diff --git a/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponents.java b/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponents.java index 4340d6edf..a868727db 100644 --- a/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponents.java +++ b/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponents.java @@ -28,14 +28,13 @@ import org.springframework.stereotype.Component; @Component public class VulnerableComponents extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A6; - } - - @Override - public String getTitle() { - return "vulnerable-components.title"; - } + @Override + public Category getDefaultCategory() { + return Category.A6; + } + @Override + public String getTitle() { + return "vulnerable-components.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLesson.java b/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLesson.java index 5487e7e33..ad1a91cc4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLesson.java +++ b/src/main/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLesson.java @@ -36,34 +36,40 @@ import org.springframework.web.bind.annotation.RestController; @AssignmentHints({"vulnerable.hint"}) public class VulnerableComponentsLesson extends AssignmentEndpoint { - @PostMapping("/VulnerableComponents/attack1") - public @ResponseBody - AttackResult completed(@RequestParam String payload) { - XStream xstream = new XStream(); - xstream.setClassLoader(Contact.class.getClassLoader()); - xstream.alias("contact", ContactImpl.class); - xstream.ignoreUnknownElements(); - Contact contact = null; + @PostMapping("/VulnerableComponents/attack1") + public @ResponseBody AttackResult completed(@RequestParam String payload) { + XStream xstream = new XStream(); + xstream.setClassLoader(Contact.class.getClassLoader()); + xstream.alias("contact", ContactImpl.class); + xstream.ignoreUnknownElements(); + Contact contact = null; - try { - if (!StringUtils.isEmpty(payload)) { - payload = payload.replace("+", "").replace("\r", "").replace("\n", "").replace("> ", ">").replace(" <", "<"); - } - contact = (Contact) xstream.fromXML(payload); - } catch (Exception ex) { - return failed(this).feedback("vulnerable-components.close").output(ex.getMessage()).build(); - } - - try { - if (null != contact) { - contact.getFirstName();//trigger the example like https://x-stream.github.io/CVE-2013-7285.html - } - if (!(contact instanceof ContactImpl)) { - return success(this).feedback("vulnerable-components.success").build(); - } - } catch (Exception e) { - return success(this).feedback("vulnerable-components.success").output(e.getMessage()).build(); - } - return failed(this).feedback("vulnerable-components.fromXML").feedbackArgs(contact).build(); + try { + if (!StringUtils.isEmpty(payload)) { + payload = + payload + .replace("+", "") + .replace("\r", "") + .replace("\n", "") + .replace("> ", ">") + .replace(" <", "<"); + } + contact = (Contact) xstream.fromXML(payload); + } catch (Exception ex) { + return failed(this).feedback("vulnerable-components.close").output(ex.getMessage()).build(); } + + try { + if (null != contact) { + contact.getFirstName(); // trigger the example like + // https://x-stream.github.io/CVE-2013-7285.html + } + if (!(contact instanceof ContactImpl)) { + return success(this).feedback("vulnerable-components.success").build(); + } + } catch (Exception e) { + return success(this).feedback("vulnerable-components.success").output(e.getMessage()).build(); + } + return failed(this).feedback("vulnerable-components.fromXML").feedbackArgs(contact).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/webgoatintroduction/WebGoatIntroduction.java b/src/main/java/org/owasp/webgoat/lessons/webgoatintroduction/WebGoatIntroduction.java index 35c876700..6c2171e9a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/webgoatintroduction/WebGoatIntroduction.java +++ b/src/main/java/org/owasp/webgoat/lessons/webgoatintroduction/WebGoatIntroduction.java @@ -8,25 +8,26 @@ import org.springframework.stereotype.Component; * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author WebGoat @@ -35,14 +36,13 @@ import org.springframework.stereotype.Component; */ @Component public class WebGoatIntroduction extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.INTRODUCTION; - } - - @Override - public String getTitle() { - return "webgoat.title"; - } + @Override + public Category getDefaultCategory() { + return Category.INTRODUCTION; + } + @Override + public String getTitle() { + return "webgoat.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/Email.java b/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/Email.java index 524384689..b1a3442b3 100644 --- a/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/Email.java +++ b/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/Email.java @@ -1,16 +1,15 @@ package org.owasp.webgoat.lessons.webwolfintroduction; +import java.io.Serializable; import lombok.Builder; import lombok.Data; -import java.io.Serializable; - @Builder @Data public class Email implements Serializable { - private String contents; - private String sender; - private String title; - private String recipient; + private String contents; + private String sender; + private String title; + private String recipient; } diff --git a/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/LandingAssignment.java b/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/LandingAssignment.java index a7243d07d..c6e9e0493 100644 --- a/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/LandingAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/LandingAssignment.java @@ -22,6 +22,9 @@ package org.owasp.webgoat.lessons.webwolfintroduction; +import java.net.URI; +import java.net.URISyntaxException; +import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; @@ -32,10 +35,6 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; -import javax.servlet.http.HttpServletRequest; -import java.net.URI; -import java.net.URISyntaxException; - /** * @author nbaars * @since 8/20/17. @@ -43,27 +42,26 @@ import java.net.URISyntaxException; @RestController public class LandingAssignment extends AssignmentEndpoint { - @Value("${webwolf.landingpage.url}") - private String landingPageUrl; + @Value("${webwolf.landingpage.url}") + private String landingPageUrl; - @PostMapping("/WebWolf/landing") - @ResponseBody - public AttackResult click(String uniqueCode) { - if (StringUtils.reverse(getWebSession().getUserName()).equals(uniqueCode)) { - return success(this).build(); - } - return failed(this).feedback("webwolf.landing_wrong").build(); + @PostMapping("/WebWolf/landing") + @ResponseBody + public AttackResult click(String uniqueCode) { + if (StringUtils.reverse(getWebSession().getUserName()).equals(uniqueCode)) { + return success(this).build(); } + return failed(this).feedback("webwolf.landing_wrong").build(); + } + @GetMapping("/WebWolf/landing/password-reset") + public ModelAndView openPasswordReset(HttpServletRequest request) throws URISyntaxException { + URI uri = new URI(request.getRequestURL().toString()); + ModelAndView modelAndView = new ModelAndView(); + modelAndView.addObject("webwolfUrl", landingPageUrl); + modelAndView.addObject("uniqueCode", StringUtils.reverse(getWebSession().getUserName())); - @GetMapping("/WebWolf/landing/password-reset") - public ModelAndView openPasswordReset(HttpServletRequest request) throws URISyntaxException { - URI uri = new URI(request.getRequestURL().toString()); - ModelAndView modelAndView = new ModelAndView(); - modelAndView.addObject("webwolfUrl", landingPageUrl); - modelAndView.addObject("uniqueCode", StringUtils.reverse(getWebSession().getUserName())); - - modelAndView.setViewName("lessons/webwolfintroduction/templates/webwolfPasswordReset.html"); - return modelAndView; - } + modelAndView.setViewName("lessons/webwolfintroduction/templates/webwolfPasswordReset.html"); + return modelAndView; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/MailAssignment.java b/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/MailAssignment.java index ec5b1c6a6..8dd168d6e 100644 --- a/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/MailAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/MailAssignment.java @@ -40,43 +40,53 @@ import org.springframework.web.client.RestTemplate; @RestController public class MailAssignment extends AssignmentEndpoint { - private final String webWolfURL; - private RestTemplate restTemplate; + private final String webWolfURL; + private RestTemplate restTemplate; - public MailAssignment(RestTemplate restTemplate, @Value("${webwolf.mail.url}") String webWolfURL) { - this.restTemplate = restTemplate; - this.webWolfURL = webWolfURL; - } + public MailAssignment( + RestTemplate restTemplate, @Value("${webwolf.mail.url}") String webWolfURL) { + this.restTemplate = restTemplate; + this.webWolfURL = webWolfURL; + } - @PostMapping("/WebWolf/mail/send") - @ResponseBody - public AttackResult sendEmail(@RequestParam String email) { - String username = email.substring(0, email.indexOf("@")); - if (username.equalsIgnoreCase(getWebSession().getUserName())) { - Email mailEvent = Email.builder() - .recipient(username) - .title("Test messages from WebWolf") - .contents("This is a test message from WebWolf, your unique code is: " + StringUtils.reverse(username)) - .sender("webgoat@owasp.org") - .build(); - try { - restTemplate.postForEntity(webWolfURL, mailEvent, Object.class); - } catch (RestClientException e ) { - return informationMessage(this).feedback("webwolf.email_failed").output(e.getMessage()).build(); - } - return informationMessage(this).feedback("webwolf.email_send").feedbackArgs(email).build(); - } else { - return informationMessage(this).feedback("webwolf.email_mismatch").feedbackArgs(username).build(); - } + @PostMapping("/WebWolf/mail/send") + @ResponseBody + public AttackResult sendEmail(@RequestParam String email) { + String username = email.substring(0, email.indexOf("@")); + if (username.equalsIgnoreCase(getWebSession().getUserName())) { + Email mailEvent = + Email.builder() + .recipient(username) + .title("Test messages from WebWolf") + .contents( + "This is a test message from WebWolf, your unique code is: " + + StringUtils.reverse(username)) + .sender("webgoat@owasp.org") + .build(); + try { + restTemplate.postForEntity(webWolfURL, mailEvent, Object.class); + } catch (RestClientException e) { + return informationMessage(this) + .feedback("webwolf.email_failed") + .output(e.getMessage()) + .build(); + } + return informationMessage(this).feedback("webwolf.email_send").feedbackArgs(email).build(); + } else { + return informationMessage(this) + .feedback("webwolf.email_mismatch") + .feedbackArgs(username) + .build(); } + } - @PostMapping("/WebWolf/mail") - @ResponseBody - public AttackResult completed(@RequestParam String uniqueCode) { - if (uniqueCode.equals(StringUtils.reverse(getWebSession().getUserName()))) { - return success(this).build(); - } else { - return failed(this).feedbackArgs("webwolf.code_incorrect").feedbackArgs(uniqueCode).build(); - } + @PostMapping("/WebWolf/mail") + @ResponseBody + public AttackResult completed(@RequestParam String uniqueCode) { + if (uniqueCode.equals(StringUtils.reverse(getWebSession().getUserName()))) { + return success(this).build(); + } else { + return failed(this).feedbackArgs("webwolf.code_incorrect").feedbackArgs(uniqueCode).build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/WebWolfIntroduction.java b/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/WebWolfIntroduction.java index 240132413..39fe97e2d 100644 --- a/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/WebWolfIntroduction.java +++ b/src/main/java/org/owasp/webgoat/lessons/webwolfintroduction/WebWolfIntroduction.java @@ -28,14 +28,13 @@ import org.springframework.stereotype.Component; @Component public class WebWolfIntroduction extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.INTRODUCTION; - } - - @Override - public String getTitle() { - return "webwolf.title"; - } + @Override + public Category getDefaultCategory() { + return Category.INTRODUCTION; + } + @Override + public String getTitle() { + return "webwolf.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/Comment.java b/src/main/java/org/owasp/webgoat/lessons/xss/Comment.java index eea482a34..b0b719b21 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/Comment.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/Comment.java @@ -1,12 +1,11 @@ package org.owasp.webgoat.lessons.xss; +import javax.xml.bind.annotation.XmlRootElement; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import javax.xml.bind.annotation.XmlRootElement; - /** * @author nbaars * @since 4/8/17. @@ -17,8 +16,7 @@ import javax.xml.bind.annotation.XmlRootElement; @NoArgsConstructor @XmlRootElement public class Comment { - private String user; - private String dateTime; - private String text; + private String user; + private String dateTime; + private String text; } - diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScripting.java b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScripting.java index 308ff6221..9068e030f 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScripting.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScripting.java @@ -28,13 +28,13 @@ import org.springframework.stereotype.Component; @Component public class CrossSiteScripting extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A3; - } + @Override + public Category getDefaultCategory() { + return Category.A3; + } - @Override - public String getTitle() { - return "xss.title"; - } + @Override + public String getTitle() { + return "xss.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson1.java b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson1.java index c6326eb97..114632ef5 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson1.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson1.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -30,17 +29,17 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; - @RestController public class CrossSiteScriptingLesson1 extends AssignmentEndpoint { - @PostMapping("/CrossSiteScripting/attack1") - @ResponseBody - public AttackResult completed(@RequestParam(value = "checkboxAttack1", required = false) String checkboxValue) { - if (checkboxValue != null) { - return success(this).build(); - } else { - return failed(this).feedback("xss.lesson1.failure").build(); - } + @PostMapping("/CrossSiteScripting/attack1") + @ResponseBody + public AttackResult completed( + @RequestParam(value = "checkboxAttack1", required = false) String checkboxValue) { + if (checkboxValue != null) { + return success(this).build(); + } else { + return failed(this).feedback("xss.lesson1.failure").build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson3.java b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson3.java index b5a643e73..fcd9138da 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson3.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson3.java @@ -31,48 +31,59 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -//@RestController +// @RestController @Deprecated -//TODO This assignment seems not to be in use in the UI +// TODO This assignment seems not to be in use in the UI // it is there to make sure the lesson can be marked complete // in order to restore it, make it accessible through the UI and uncomment RestController -@AssignmentHints(value = {"xss-mitigation-3-hint1", "xss-mitigation-3-hint2", "xss-mitigation-3-hint3", "xss-mitigation-3-hint4"}) +@AssignmentHints( + value = { + "xss-mitigation-3-hint1", + "xss-mitigation-3-hint2", + "xss-mitigation-3-hint3", + "xss-mitigation-3-hint4" + }) public class CrossSiteScriptingLesson3 extends AssignmentEndpoint { - @PostMapping("/CrossSiteScripting/attack3") - @ResponseBody - public AttackResult completed(@RequestParam String editor) { - String unescapedString = org.jsoup.parser.Parser.unescapeEntities(editor, true); - try { - if (editor.isEmpty()) return failed(this).feedback("xss-mitigation-3-no-code").build(); - Document doc = Jsoup.parse(unescapedString); - String[] lines = unescapedString.split(""); + @PostMapping("/CrossSiteScripting/attack3") + @ResponseBody + public AttackResult completed(@RequestParam String editor) { + String unescapedString = org.jsoup.parser.Parser.unescapeEntities(editor, true); + try { + if (editor.isEmpty()) return failed(this).feedback("xss-mitigation-3-no-code").build(); + Document doc = Jsoup.parse(unescapedString); + String[] lines = unescapedString.split(""); - String include = (lines[0]); - String fistNameElement = doc.select("body > table > tbody > tr:nth-child(1) > td:nth-child(2)").first().text(); - String lastNameElement = doc.select("body > table > tbody > tr:nth-child(2) > td:nth-child(2)").first().text(); + String include = (lines[0]); + String fistNameElement = + doc.select("body > table > tbody > tr:nth-child(1) > td:nth-child(2)").first().text(); + String lastNameElement = + doc.select("body > table > tbody > tr:nth-child(2) > td:nth-child(2)").first().text(); - Boolean includeCorrect = false; - Boolean firstNameCorrect = false; - Boolean lastNameCorrect = false; + Boolean includeCorrect = false; + Boolean firstNameCorrect = false; + Boolean lastNameCorrect = false; - if (include.contains("<%@") && include.contains("taglib") && include.contains("uri=\"https://www.owasp.org/index.php/OWASP_Java_Encoder_Project\"") && include.contains("%>")) { - includeCorrect = true; - } - if (fistNameElement.equals("${e:forHtml(param.first_name)}")) { - firstNameCorrect = true; - } - if (lastNameElement.equals("${e:forHtml(param.last_name)}")) { - lastNameCorrect = true; - } + if (include.contains("<%@") + && include.contains("taglib") + && include.contains("uri=\"https://www.owasp.org/index.php/OWASP_Java_Encoder_Project\"") + && include.contains("%>")) { + includeCorrect = true; + } + if (fistNameElement.equals("${e:forHtml(param.first_name)}")) { + firstNameCorrect = true; + } + if (lastNameElement.equals("${e:forHtml(param.last_name)}")) { + lastNameCorrect = true; + } - if (includeCorrect && firstNameCorrect && lastNameCorrect) { - return success(this).feedback("xss-mitigation-3-success").build(); - } else { - return failed(this).feedback("xss-mitigation-3-failure").build(); - } - } catch (Exception e) { - return failed(this).output(e.getMessage()).build(); - } + if (includeCorrect && firstNameCorrect && lastNameCorrect) { + return success(this).feedback("xss-mitigation-3-success").build(); + } else { + return failed(this).feedback("xss-mitigation-3-failure").build(); + } + } catch (Exception e) { + return failed(this).output(e.getMessage()).build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson4.java b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson4.java index d6df6b1fc..7a487471e 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson4.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson4.java @@ -30,33 +30,35 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -//@RestController +// @RestController @Deprecated -//TODO This assignment seems not to be in use in the UI -//it is there to make sure the lesson can be marked complete -//in order to restore it, make it accessible through the UI and uncomment RestController@Slf4j +// TODO This assignment seems not to be in use in the UI +// it is there to make sure the lesson can be marked complete +// in order to restore it, make it accessible through the UI and uncomment RestController@Slf4j @Slf4j @AssignmentHints(value = {"xss-mitigation-4-hint1"}) public class CrossSiteScriptingLesson4 extends AssignmentEndpoint { - @PostMapping("/CrossSiteScripting/attack4") - @ResponseBody - public AttackResult completed(@RequestParam String editor2) { + @PostMapping("/CrossSiteScripting/attack4") + @ResponseBody + public AttackResult completed(@RequestParam String editor2) { - String editor = editor2.replaceAll("\\<.*?>", ""); - log.debug(editor); + String editor = editor2.replaceAll("\\<.*?>", ""); + log.debug(editor); - if ((editor.contains("Policy.getInstance(\"antisamy-slashdot.xml\"") || editor.contains(".scan(newComment, \"antisamy-slashdot.xml\"") || editor.contains(".scan(newComment, new File(\"antisamy-slashdot.xml\")")) && - editor.contains("new AntiSamy();") && - editor.contains(".scan(newComment,") && - editor.contains("CleanResults") && - editor.contains("MyCommentDAO.addComment(threadID, userID") && - editor.contains(".getCleanHTML());")) { - log.debug("true"); - return success(this).feedback("xss-mitigation-4-success").build(); - } else { - log.debug("false"); - return failed(this).feedback("xss-mitigation-4-failed").build(); - } + if ((editor.contains("Policy.getInstance(\"antisamy-slashdot.xml\"") + || editor.contains(".scan(newComment, \"antisamy-slashdot.xml\"") + || editor.contains(".scan(newComment, new File(\"antisamy-slashdot.xml\")")) + && editor.contains("new AntiSamy();") + && editor.contains(".scan(newComment,") + && editor.contains("CleanResults") + && editor.contains("MyCommentDAO.addComment(threadID, userID") + && editor.contains(".getCleanHTML());")) { + log.debug("true"); + return success(this).feedback("xss-mitigation-4-success").build(); + } else { + log.debug("false"); + return failed(this).feedback("xss-mitigation-4-failed").build(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson5a.java b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson5a.java index 9a7c1135a..9807d8d4e 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson5a.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson5a.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -23,6 +22,8 @@ package org.owasp.webgoat.lessons.xss; +import java.util.function.Predicate; +import java.util.regex.Pattern; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; import org.owasp.webgoat.container.assignments.AttackResult; @@ -33,58 +34,70 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.function.Predicate; -import java.util.regex.Pattern; - - @RestController -@AssignmentHints(value = {"xss-reflected-5a-hint-1", "xss-reflected-5a-hint-2", "xss-reflected-5a-hint-3", "xss-reflected-5a-hint-4"}) +@AssignmentHints( + value = { + "xss-reflected-5a-hint-1", + "xss-reflected-5a-hint-2", + "xss-reflected-5a-hint-3", + "xss-reflected-5a-hint-4" + }) public class CrossSiteScriptingLesson5a extends AssignmentEndpoint { - public static final Predicate XSS_PATTERN = Pattern.compile( - ".*.*" - , Pattern.CASE_INSENSITIVE).asMatchPredicate(); - @Autowired - UserSessionData userSessionData; + public static final Predicate XSS_PATTERN = + Pattern.compile( + ".*.*", Pattern.CASE_INSENSITIVE) + .asMatchPredicate(); + @Autowired UserSessionData userSessionData; - @GetMapping("/CrossSiteScripting/attack5a") - @ResponseBody - public AttackResult completed(@RequestParam Integer QTY1, - @RequestParam Integer QTY2, @RequestParam Integer QTY3, - @RequestParam Integer QTY4, @RequestParam String field1, - @RequestParam String field2) { + @GetMapping("/CrossSiteScripting/attack5a") + @ResponseBody + public AttackResult completed( + @RequestParam Integer QTY1, + @RequestParam Integer QTY2, + @RequestParam Integer QTY3, + @RequestParam Integer QTY4, + @RequestParam String field1, + @RequestParam String field2) { - if (XSS_PATTERN.test(field2)) { - return failed(this).feedback("xss-reflected-5a-failed-wrong-field").build(); - } - - double totalSale = QTY1.intValue() * 69.99 + QTY2.intValue() * 27.99 + QTY3.intValue() * 1599.99 + QTY4.intValue() * 299.99; - - userSessionData.setValue("xss-reflected1-complete", "false"); - StringBuilder cart = new StringBuilder(); - cart.append("Thank you for shopping at WebGoat.
Your support is appreciated


"); - cart.append("

We have charged credit card:" + field1 + "
"); - cart.append(" -------------------
"); - cart.append(" $" + totalSale); - - //init state - if (userSessionData.getValue("xss-reflected1-complete") == null) { - userSessionData.setValue("xss-reflected1-complete", "false"); - } - - if (XSS_PATTERN.test(field1)) { - userSessionData.setValue("xss-reflected-5a-complete", "true"); - if (field1.toLowerCase().contains("console.log")) { - return success(this).feedback("xss-reflected-5a-success-console").output(cart.toString()).build(); - } else { - return success(this).feedback("xss-reflected-5a-success-alert").output(cart.toString()).build(); - } - } else { - userSessionData.setValue("xss-reflected1-complete", "false"); - return failed(this) - .feedback("xss-reflected-5a-failure") - .output(cart.toString()) - .build(); - } + if (XSS_PATTERN.test(field2)) { + return failed(this).feedback("xss-reflected-5a-failed-wrong-field").build(); } + + double totalSale = + QTY1.intValue() * 69.99 + + QTY2.intValue() * 27.99 + + QTY3.intValue() * 1599.99 + + QTY4.intValue() * 299.99; + + userSessionData.setValue("xss-reflected1-complete", "false"); + StringBuilder cart = new StringBuilder(); + cart.append("Thank you for shopping at WebGoat.
Your support is appreciated


"); + cart.append("

We have charged credit card:" + field1 + "
"); + cart.append(" -------------------
"); + cart.append(" $" + totalSale); + + // init state + if (userSessionData.getValue("xss-reflected1-complete") == null) { + userSessionData.setValue("xss-reflected1-complete", "false"); + } + + if (XSS_PATTERN.test(field1)) { + userSessionData.setValue("xss-reflected-5a-complete", "true"); + if (field1.toLowerCase().contains("console.log")) { + return success(this) + .feedback("xss-reflected-5a-success-console") + .output(cart.toString()) + .build(); + } else { + return success(this) + .feedback("xss-reflected-5a-success-alert") + .output(cart.toString()) + .build(); + } + } else { + userSessionData.setValue("xss-reflected1-complete", "false"); + return failed(this).feedback("xss-reflected-5a-failure").output(cart.toString()).build(); + } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson6a.java b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson6a.java index ce8f2f620..d0252280c 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson6a.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson6a.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -33,23 +32,26 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; - @RestController -@AssignmentHints(value = {"xss-reflected-6a-hint-1", "xss-reflected-6a-hint-2", "xss-reflected-6a-hint-3", "xss-reflected-6a-hint-4"}) +@AssignmentHints( + value = { + "xss-reflected-6a-hint-1", + "xss-reflected-6a-hint-2", + "xss-reflected-6a-hint-3", + "xss-reflected-6a-hint-4" + }) public class CrossSiteScriptingLesson6a extends AssignmentEndpoint { - @Autowired - UserSessionData userSessionData; + @Autowired UserSessionData userSessionData; - @PostMapping("/CrossSiteScripting/attack6a") - @ResponseBody - public AttackResult completed(@RequestParam String DOMTestRoute) { + @PostMapping("/CrossSiteScripting/attack6a") + @ResponseBody + public AttackResult completed(@RequestParam String DOMTestRoute) { - if (DOMTestRoute.matches("start\\.mvc#test(\\/|)")) { - //return ) - return success(this).feedback("xss-reflected-6a-success").build(); - } else { - return failed(this).feedback("xss-reflected-6a-failure").build(); - } + if (DOMTestRoute.matches("start\\.mvc#test(\\/|)")) { + // return ) + return success(this).feedback("xss-reflected-6a-success").build(); + } else { + return failed(this).feedback("xss-reflected-6a-failure").build(); } - + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingMitigation.java b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingMitigation.java index 2515d7e0c..89977ea79 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingMitigation.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingMitigation.java @@ -26,13 +26,13 @@ import org.owasp.webgoat.container.lessons.Category; import org.owasp.webgoat.container.lessons.Lesson; public class CrossSiteScriptingMitigation extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A3; - } + @Override + public Category getDefaultCategory() { + return Category.A3; + } - @Override - public String getTitle() { - return "xss-mitigation.title"; - } + @Override + public String getTitle() { + return "xss-mitigation.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingQuiz.java b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingQuiz.java index 7612f559a..e193d262a 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingQuiz.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingQuiz.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.xss; +import java.io.IOException; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.springframework.web.bind.annotation.GetMapping; @@ -30,43 +31,52 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.io.IOException; - @RestController public class CrossSiteScriptingQuiz extends AssignmentEndpoint { - String[] solutions = {"Solution 4", "Solution 3", "Solution 1", "Solution 2", "Solution 4"}; - boolean[] guesses = new boolean[solutions.length]; + String[] solutions = {"Solution 4", "Solution 3", "Solution 1", "Solution 2", "Solution 4"}; + boolean[] guesses = new boolean[solutions.length]; - @PostMapping("/CrossSiteScripting/quiz") - @ResponseBody - public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution, @RequestParam String[] question_2_solution, @RequestParam String[] question_3_solution, @RequestParam String[] question_4_solution) throws IOException { - int correctAnswers = 0; + @PostMapping("/CrossSiteScripting/quiz") + @ResponseBody + public AttackResult completed( + @RequestParam String[] question_0_solution, + @RequestParam String[] question_1_solution, + @RequestParam String[] question_2_solution, + @RequestParam String[] question_3_solution, + @RequestParam String[] question_4_solution) + throws IOException { + int correctAnswers = 0; - String[] givenAnswers = {question_0_solution[0], question_1_solution[0], question_2_solution[0], question_3_solution[0], question_4_solution[0]}; + String[] givenAnswers = { + question_0_solution[0], + question_1_solution[0], + question_2_solution[0], + question_3_solution[0], + question_4_solution[0] + }; - for (int i = 0; i < solutions.length; i++) { - if (givenAnswers[i].contains(solutions[i])) { - // answer correct - correctAnswers++; - guesses[i] = true; - } else { - // answer incorrect - guesses[i] = false; - } - } - - if (correctAnswers == solutions.length) { - return success(this).build(); - } else { - return failed(this).build(); - } + for (int i = 0; i < solutions.length; i++) { + if (givenAnswers[i].contains(solutions[i])) { + // answer correct + correctAnswers++; + guesses[i] = true; + } else { + // answer incorrect + guesses[i] = false; + } } - @GetMapping("/CrossSiteScripting/quiz") - @ResponseBody - public boolean[] getResults() { - return this.guesses; + if (correctAnswers == solutions.length) { + return success(this).build(); + } else { + return failed(this).build(); } + } + @GetMapping("/CrossSiteScripting/quiz") + @ResponseBody + public boolean[] getResults() { + return this.guesses; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xss/DOMCrossSiteScripting.java b/src/main/java/org/owasp/webgoat/lessons/xss/DOMCrossSiteScripting.java index e5e28b94b..11da6ea19 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xss/DOMCrossSiteScripting.java +++ b/src/main/java/org/owasp/webgoat/lessons/xss/DOMCrossSiteScripting.java @@ -22,6 +22,8 @@ package org.owasp.webgoat.lessons.xss; +import java.security.SecureRandom; +import javax.servlet.http.HttpServletRequest; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AttackResult; import org.owasp.webgoat.container.session.UserSessionData; @@ -30,26 +32,29 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; -import java.security.SecureRandom; - @RestController public class DOMCrossSiteScripting extends AssignmentEndpoint { - @PostMapping("/CrossSiteScripting/phone-home-xss") - @ResponseBody - public AttackResult completed(@RequestParam Integer param1, - @RequestParam Integer param2, HttpServletRequest request) { - UserSessionData userSessionData = getUserSessionData(); - SecureRandom number = new SecureRandom(); - userSessionData.setValue("randValue", String.valueOf(number.nextInt())); + @PostMapping("/CrossSiteScripting/phone-home-xss") + @ResponseBody + public AttackResult completed( + @RequestParam Integer param1, @RequestParam Integer param2, HttpServletRequest request) { + UserSessionData userSessionData = getUserSessionData(); + SecureRandom number = new SecureRandom(); + userSessionData.setValue("randValue", String.valueOf(number.nextInt())); - if (param1 == 42 && param2 == 24 && request.getHeader("webgoat-requested-by").equals("dom-xss-vuln")) { - return success(this).output("phoneHome Response is " + userSessionData.getValue("randValue").toString()).build(); - } else { - return failed(this).build(); - } + if (param1 == 42 + && param2 == 24 + && request.getHeader("webgoat-requested-by").equals("dom-xss-vuln")) { + return success(this) + .output("phoneHome Response is " + userSessionData.getValue("randValue").toString()) + .build(); + } else { + return failed(this).build(); } + } } -// something like ... http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere%3Cscript%3Ewebgoat.customjs.phoneHome();%3C%2Fscript%3E--andMoreGarbageHere -// or http://localhost:8080/WebGoat/start.mvc#test/testParam=foobar&_someVar=234902384lotslsfjdOf9889080GarbageHere"; + private static final Map> userComments = new HashMap<>(); + private static final List comments = new ArrayList<>(); + private static final String phoneHomeString = ""; + static { + comments.add( + new Comment( + "secUriTy", + LocalDateTime.now().format(fmt), + "Comment for Unit Testing")); + comments.add(new Comment("webgoat", LocalDateTime.now().format(fmt), "This comment is safe")); + comments.add(new Comment("guest", LocalDateTime.now().format(fmt), "This one is safe too.")); + comments.add( + new Comment( + "guest", + LocalDateTime.now().format(fmt), + "Can you post a comment, calling webgoat.customjs.phoneHome() ?")); + } - static { - comments.add(new Comment("secUriTy", LocalDateTime.now().format(fmt), "Comment for Unit Testing")); - comments.add(new Comment("webgoat", LocalDateTime.now().format(fmt), "This comment is safe")); - comments.add(new Comment("guest", LocalDateTime.now().format(fmt), "This one is safe too.")); - comments.add(new Comment("guest", LocalDateTime.now().format(fmt), "Can you post a comment, calling webgoat.customjs.phoneHome() ?")); + // TODO This assignment seems not to be in use in the UI + @GetMapping( + path = "/CrossSiteScriptingStored/stored-xss", + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = ALL_VALUE) + @ResponseBody + public Collection retrieveComments() { + List allComments = Lists.newArrayList(); + Collection newComments = userComments.get(webSession.getUserName()); + allComments.addAll(comments); + if (newComments != null) { + allComments.addAll(newComments); } + Collections.reverse(allComments); + return allComments; + } - //TODO This assignment seems not to be in use in the UI - @GetMapping(path = "/CrossSiteScriptingStored/stored-xss", produces = MediaType.APPLICATION_JSON_VALUE, consumes = ALL_VALUE) - @ResponseBody - public Collection retrieveComments() { - List allComments = Lists.newArrayList(); - Collection newComments = userComments.get(webSession.getUserName()); - allComments.addAll(comments); - if (newComments != null) { - allComments.addAll(newComments); - } - Collections.reverse(allComments); - return allComments; + // TODO This assignment seems not to be in use in the UI + @PostMapping("/CrossSiteScriptingStored/stored-xss") + @ResponseBody + public AttackResult createNewComment(@RequestBody String commentStr) { + Comment comment = parseJson(commentStr); + + List comments = userComments.getOrDefault(webSession.getUserName(), new ArrayList<>()); + comment.setDateTime(LocalDateTime.now().format(fmt)); + comment.setUser(webSession.getUserName()); + + comments.add(comment); + userComments.put(webSession.getUserName(), comments); + + if (comment.getText().contains(phoneHomeString)) { + return (success(this).feedback("xss-stored-comment-success").build()); + } else { + return (failed(this).feedback("xss-stored-comment-failure").build()); } + } - //TODO This assignment seems not to be in use in the UI - @PostMapping("/CrossSiteScriptingStored/stored-xss") - @ResponseBody - public AttackResult createNewComment(@RequestBody String commentStr) { - Comment comment = parseJson(commentStr); - - List comments = userComments.getOrDefault(webSession.getUserName(), new ArrayList<>()); - comment.setDateTime(LocalDateTime.now().format(fmt)); - comment.setUser(webSession.getUserName()); - - comments.add(comment); - userComments.put(webSession.getUserName(), comments); - - if (comment.getText().contains(phoneHomeString)) { - return (success(this).feedback("xss-stored-comment-success").build()); - } else { - return (failed(this).feedback("xss-stored-comment-failure").build()); - } - } - - private Comment parseJson(String comment) { - ObjectMapper mapper = new ObjectMapper(); - try { - return mapper.readValue(comment, Comment.class); - } catch (IOException e) { - return new Comment(); - } + private Comment parseJson(String comment) { + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.readValue(comment, Comment.class); + } catch (IOException e) { + return new Comment(); } + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/BlindSendFileAssignment.java b/src/main/java/org/owasp/webgoat/lessons/xxe/BlindSendFileAssignment.java index 96eb6f4a7..317ef948e 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/BlindSendFileAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/BlindSendFileAssignment.java @@ -1,5 +1,15 @@ package org.owasp.webgoat.lessons.xxe; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; +import static org.springframework.http.MediaType.ALL_VALUE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; import org.owasp.webgoat.container.assignments.AssignmentHints; @@ -11,96 +21,93 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.HashMap; -import java.util.Map; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; -import static org.springframework.http.MediaType.ALL_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - /** * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

*/ @Slf4j @RestController -@AssignmentHints({"xxe.blind.hints.1", "xxe.blind.hints.2", "xxe.blind.hints.3", "xxe.blind.hints.4", "xxe.blind.hints.5"}) +@AssignmentHints({ + "xxe.blind.hints.1", + "xxe.blind.hints.2", + "xxe.blind.hints.3", + "xxe.blind.hints.4", + "xxe.blind.hints.5" +}) public class BlindSendFileAssignment extends AssignmentEndpoint { - private final String webGoatHomeDirectory; - private final CommentsCache comments; - private final Map userToFileContents = new HashMap<>(); + private final String webGoatHomeDirectory; + private final CommentsCache comments; + private final Map userToFileContents = new HashMap<>(); - public BlindSendFileAssignment(@Value("${webgoat.user.directory}") String webGoatHomeDirectory, CommentsCache comments) { - this.webGoatHomeDirectory = webGoatHomeDirectory; - this.comments = comments; + public BlindSendFileAssignment( + @Value("${webgoat.user.directory}") String webGoatHomeDirectory, CommentsCache comments) { + this.webGoatHomeDirectory = webGoatHomeDirectory; + this.comments = comments; + } + + private void createSecretFileWithRandomContents(WebGoatUser user) { + var fileContents = "WebGoat 8.0 rocks... (" + randomAlphabetic(10) + ")"; + userToFileContents.put(user, fileContents); + File targetDirectory = new File(webGoatHomeDirectory, "/XXE/" + user.getUsername()); + if (!targetDirectory.exists()) { + targetDirectory.mkdirs(); + } + try { + Files.writeString(new File(targetDirectory, "secret.txt").toPath(), fileContents, UTF_8); + } catch (IOException e) { + log.error("Unable to write 'secret.txt' to '{}", targetDirectory); + } + } + + @PostMapping(path = "xxe/blind", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE) + @ResponseBody + public AttackResult addComment(@RequestBody String commentStr) { + var fileContentsForUser = userToFileContents.getOrDefault(getWebSession().getUser(), ""); + + // Solution is posted by the user as a separate comment + if (commentStr.contains(fileContentsForUser)) { + return success(this).build(); } - private void createSecretFileWithRandomContents(WebGoatUser user) { - var fileContents = "WebGoat 8.0 rocks... (" + randomAlphabetic(10) + ")"; - userToFileContents.put(user, fileContents); - File targetDirectory = new File(webGoatHomeDirectory, "/XXE/" + user.getUsername()); - if (!targetDirectory.exists()) { - targetDirectory.mkdirs(); - } - try { - Files.writeString(new File(targetDirectory, "secret.txt").toPath(), fileContents, UTF_8); - } catch (IOException e) { - log.error("Unable to write 'secret.txt' to '{}", targetDirectory); - } + try { + Comment comment = comments.parseXml(commentStr); + if (fileContentsForUser.contains(comment.getText())) { + comment.setText("Nice try, you need to send the file to WebWolf"); + } + comments.addComment(comment, false); + } catch (Exception e) { + return failed(this).output(e.toString()).build(); } + return failed(this).build(); + } - @PostMapping(path = "xxe/blind", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE) - @ResponseBody - public AttackResult addComment(@RequestBody String commentStr) { - var fileContentsForUser = userToFileContents.getOrDefault(getWebSession().getUser(), ""); - - //Solution is posted by the user as a separate comment - if (commentStr.contains(fileContentsForUser)) { - return success(this).build(); - } - - try { - Comment comment = comments.parseXml(commentStr); - if (fileContentsForUser.contains(comment.getText())) { - comment.setText("Nice try, you need to send the file to WebWolf"); - } - comments.addComment(comment, false); - } catch (Exception e) { - return failed(this).output(e.toString()).build(); - } - return failed(this).build(); - } - - @Override - public void initialize(WebGoatUser user) { - comments.reset(user); - userToFileContents.remove(user); - createSecretFileWithRandomContents(user); - } + @Override + public void initialize(WebGoatUser user) { + comments.reset(user); + userToFileContents.remove(user); + createSecretFileWithRandomContents(user); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/Comment.java b/src/main/java/org/owasp/webgoat/lessons/xxe/Comment.java index 37a5b42f1..90d06fdd1 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/Comment.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/Comment.java @@ -22,14 +22,13 @@ package org.owasp.webgoat.lessons.xxe; +import javax.xml.bind.annotation.XmlRootElement; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import javax.xml.bind.annotation.XmlRootElement; - /** * @author nbaars * @since 4/8/17. @@ -41,7 +40,7 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @ToString public class Comment { - private String user; - private String dateTime; - private String text; + private String user; + private String dateTime; + private String text; } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/CommentsCache.java b/src/main/java/org/owasp/webgoat/lessons/xxe/CommentsCache.java index f020228cd..b949f0abe 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/CommentsCache.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/CommentsCache.java @@ -22,17 +22,10 @@ package org.owasp.webgoat.lessons.xxe; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.owasp.webgoat.container.session.WebSession; -import org.owasp.webgoat.container.users.WebGoatUser; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; +import static java.util.Optional.empty; +import static java.util.Optional.of; -import javax.xml.XMLConstants; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamException; +import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.StringReader; import java.time.LocalDateTime; @@ -42,93 +35,103 @@ import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Optional; - -import static java.util.Optional.empty; -import static java.util.Optional.of; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import org.owasp.webgoat.container.session.WebSession; +import org.owasp.webgoat.container.users.WebGoatUser; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; @Component @Scope("singleton") public class CommentsCache { - static class Comments extends ArrayList { - void sort() { - sort(Comparator.comparing(Comment::getDateTime).reversed()); - } + static class Comments extends ArrayList { + void sort() { + sort(Comparator.comparing(Comment::getDateTime).reversed()); + } + } + + private static final Comments comments = new Comments(); + private static final Map userComments = new HashMap<>(); + private static final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd, HH:mm:ss"); + + private final WebSession webSession; + + public CommentsCache(WebSession webSession) { + this.webSession = webSession; + initDefaultComments(); + } + + void initDefaultComments() { + comments.add(new Comment("webgoat", LocalDateTime.now().format(fmt), "Silly cat....")); + comments.add( + new Comment( + "guest", + LocalDateTime.now().format(fmt), + "I think I will use this picture in one of my projects.")); + comments.add(new Comment("guest", LocalDateTime.now().format(fmt), "Lol!! :-).")); + } + + protected Comments getComments() { + Comments allComments = new Comments(); + Comments commentsByUser = userComments.get(webSession.getUser()); + if (commentsByUser != null) { + allComments.addAll(commentsByUser); + } + allComments.addAll(comments); + allComments.sort(); + return allComments; + } + + /** + * Notice this parse method is not a "trick" to get the XXE working, we need to catch some of the + * exception which might happen during when users post message (we want to give feedback track + * progress etc). In real life the XmlMapper bean defined above will be used automatically and the + * Comment class can be directly used in the controller method (instead of a String) + */ + protected Comment parseXml(String xml) throws JAXBException, XMLStreamException { + var jc = JAXBContext.newInstance(Comment.class); + var xif = XMLInputFactory.newInstance(); + + if (webSession.isSecurityEnabled()) { + xif.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant + xif.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant } - private static final Comments comments = new Comments(); - private static final Map userComments = new HashMap<>(); - private static final DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd, HH:mm:ss"); + var xsr = xif.createXMLStreamReader(new StringReader(xml)); - private final WebSession webSession; + var unmarshaller = jc.createUnmarshaller(); + return (Comment) unmarshaller.unmarshal(xsr); + } - public CommentsCache(WebSession webSession) { - this.webSession = webSession; - initDefaultComments(); + protected Optional parseJson(String comment) { + ObjectMapper mapper = new ObjectMapper(); + try { + return of(mapper.readValue(comment, Comment.class)); + } catch (IOException e) { + return empty(); } + } - void initDefaultComments() { - comments.add(new Comment("webgoat", LocalDateTime.now().format(fmt), "Silly cat....")); - comments.add(new Comment("guest", LocalDateTime.now().format(fmt), "I think I will use this picture in one of my projects.")); - comments.add(new Comment("guest", LocalDateTime.now().format(fmt), "Lol!! :-).")); + public void addComment(Comment comment, boolean visibleForAllUsers) { + comment.setDateTime(LocalDateTime.now().format(fmt)); + comment.setUser(webSession.getUserName()); + if (visibleForAllUsers) { + comments.add(comment); + } else { + var comments = userComments.getOrDefault(webSession.getUserName(), new Comments()); + comments.add(comment); + userComments.put(webSession.getUser(), comments); } + } - protected Comments getComments() { - Comments allComments = new Comments(); - Comments commentsByUser = userComments.get(webSession.getUser()); - if (commentsByUser != null) { - allComments.addAll(commentsByUser); - } - allComments.addAll(comments); - allComments.sort(); - return allComments; - } - - /** - * Notice this parse method is not a "trick" to get the XXE working, we need to catch some of the exception which - * might happen during when users post message (we want to give feedback track progress etc). In real life the - * XmlMapper bean defined above will be used automatically and the Comment class can be directly used in the - * controller method (instead of a String) - */ - protected Comment parseXml(String xml) throws JAXBException, XMLStreamException { - var jc = JAXBContext.newInstance(Comment.class); - var xif = XMLInputFactory.newInstance(); - - if (webSession.isSecurityEnabled()) { - xif.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant - xif.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant - } - - var xsr = xif.createXMLStreamReader(new StringReader(xml)); - - var unmarshaller = jc.createUnmarshaller(); - return (Comment) unmarshaller.unmarshal(xsr); - } - - protected Optional parseJson(String comment) { - ObjectMapper mapper = new ObjectMapper(); - try { - return of(mapper.readValue(comment, Comment.class)); - } catch (IOException e) { - return empty(); - } - } - - public void addComment(Comment comment, boolean visibleForAllUsers) { - comment.setDateTime(LocalDateTime.now().format(fmt)); - comment.setUser(webSession.getUserName()); - if (visibleForAllUsers) { - comments.add(comment); - } else { - var comments = userComments.getOrDefault(webSession.getUserName(), new Comments()); - comments.add(comment); - userComments.put(webSession.getUser(), comments); - } - } - - public void reset(WebGoatUser user) { - comments.clear(); - userComments.remove(user); - initDefaultComments(); - } + public void reset(WebGoatUser user) { + comments.clear(); + userComments.remove(user); + initDefaultComments(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/CommentsEndpoint.java b/src/main/java/org/owasp/webgoat/lessons/xxe/CommentsEndpoint.java index e5a43d0e2..721e649ea 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/CommentsEndpoint.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/CommentsEndpoint.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.lessons.xxe; +import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; @@ -29,8 +30,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import java.util.Collection; - /** * @author nbaars * @since 5/4/17. @@ -39,13 +38,11 @@ import java.util.Collection; @RequestMapping("xxe/comments") public class CommentsEndpoint { - @Autowired - private CommentsCache comments; - - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody - public Collection retrieveComments() { - return comments.getComments(); - } + @Autowired private CommentsCache comments; + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public Collection retrieveComments() { + return comments.getComments(); + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/ContentTypeAssignment.java b/src/main/java/org/owasp/webgoat/lessons/xxe/ContentTypeAssignment.java index 085d097ee..2e54dc1d8 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/ContentTypeAssignment.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/ContentTypeAssignment.java @@ -22,6 +22,9 @@ package org.owasp.webgoat.lessons.xxe; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +import javax.servlet.http.HttpServletRequest; import org.apache.commons.exec.OS; import org.apache.commons.lang3.exception.ExceptionUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -37,58 +40,61 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; - -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - @RestController @AssignmentHints({"xxe.hints.content.type.xxe.1", "xxe.hints.content.type.xxe.2"}) public class ContentTypeAssignment extends AssignmentEndpoint { - private static final String[] DEFAULT_LINUX_DIRECTORIES = {"usr", "etc", "var"}; - private static final String[] DEFAULT_WINDOWS_DIRECTORIES = {"Windows", "Program Files (x86)", "Program Files", "pagefile.sys"}; + private static final String[] DEFAULT_LINUX_DIRECTORIES = {"usr", "etc", "var"}; + private static final String[] DEFAULT_WINDOWS_DIRECTORIES = { + "Windows", "Program Files (x86)", "Program Files", "pagefile.sys" + }; - @Value("${webgoat.server.directory}") - private String webGoatHomeDirectory; - @Autowired - private WebSession webSession; - @Autowired - private CommentsCache comments; + @Value("${webgoat.server.directory}") + private String webGoatHomeDirectory; - @PostMapping(path = "xxe/content-type") - @ResponseBody - public AttackResult createNewUser(HttpServletRequest request, @RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception { - AttackResult attackResult = failed(this).build(); + @Autowired private WebSession webSession; + @Autowired private CommentsCache comments; - if (APPLICATION_JSON_VALUE.equals(contentType)) { - comments.parseJson(commentStr).ifPresent(c -> comments.addComment(c, true)); - attackResult = failed(this).feedback("xxe.content.type.feedback.json").build(); - } + @PostMapping(path = "xxe/content-type") + @ResponseBody + public AttackResult createNewUser( + HttpServletRequest request, + @RequestBody String commentStr, + @RequestHeader("Content-Type") String contentType) + throws Exception { + AttackResult attackResult = failed(this).build(); - if (null != contentType && contentType.contains(MediaType.APPLICATION_XML_VALUE)) { - String error = ""; - try { - Comment comment = comments.parseXml(commentStr); - comments.addComment(comment, false); - if (checkSolution(comment)) { - attackResult = success(this).build(); - } - } catch (Exception e) { - error = ExceptionUtils.getStackTrace(e); - attackResult = failed(this).feedback("xxe.content.type.feedback.xml").output(error).build(); - } - } - - return attackResult; + if (APPLICATION_JSON_VALUE.equals(contentType)) { + comments.parseJson(commentStr).ifPresent(c -> comments.addComment(c, true)); + attackResult = failed(this).feedback("xxe.content.type.feedback.json").build(); } - private boolean checkSolution(Comment comment) { - String[] directoriesToCheck = OS.isFamilyMac() || OS.isFamilyUnix() ? DEFAULT_LINUX_DIRECTORIES : DEFAULT_WINDOWS_DIRECTORIES; - boolean success = false; - for (String directory : directoriesToCheck) { - success |= org.apache.commons.lang3.StringUtils.contains(comment.getText(), directory); + if (null != contentType && contentType.contains(MediaType.APPLICATION_XML_VALUE)) { + String error = ""; + try { + Comment comment = comments.parseXml(commentStr); + comments.addComment(comment, false); + if (checkSolution(comment)) { + attackResult = success(this).build(); } - return success; + } catch (Exception e) { + error = ExceptionUtils.getStackTrace(e); + attackResult = failed(this).feedback("xxe.content.type.feedback.xml").output(error).build(); + } } + return attackResult; + } + + private boolean checkSolution(Comment comment) { + String[] directoriesToCheck = + OS.isFamilyMac() || OS.isFamilyUnix() + ? DEFAULT_LINUX_DIRECTORIES + : DEFAULT_WINDOWS_DIRECTORIES; + boolean success = false; + for (String directory : directoriesToCheck) { + success |= org.apache.commons.lang3.StringUtils.contains(comment.getText(), directory); + } + return success; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/Ping.java b/src/main/java/org/owasp/webgoat/lessons/xxe/Ping.java index 12a270dc5..f71dbd7dd 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/Ping.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/Ping.java @@ -22,6 +22,9 @@ package org.owasp.webgoat.lessons.xxe; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; import lombok.extern.slf4j.Slf4j; import org.owasp.webgoat.container.session.WebSession; import org.springframework.beans.factory.annotation.Autowired; @@ -32,31 +35,28 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; - @Slf4j public class Ping { - @Value("${webgoat.user.directory}") - private String webGoatHomeDirectory; - @Autowired - private WebSession webSession; + @Value("${webgoat.user.directory}") + private String webGoatHomeDirectory; - @RequestMapping(method = RequestMethod.GET) - @ResponseBody - public String logRequest(@RequestHeader("User-Agent") String userAgent, @RequestParam(required = false) String text) { - String logLine = String.format("%s %s %s", "GET", userAgent, text); - log.debug(logLine); - File logFile = new File(webGoatHomeDirectory, "/XXE/log" + webSession.getUserName() + ".txt"); - try { - try (PrintWriter pw = new PrintWriter(logFile)) { - pw.println(logLine); - } - } catch (FileNotFoundException e) { - log.error("Error occurred while writing the logfile", e); - } - return ""; + @Autowired private WebSession webSession; + + @RequestMapping(method = RequestMethod.GET) + @ResponseBody + public String logRequest( + @RequestHeader("User-Agent") String userAgent, @RequestParam(required = false) String text) { + String logLine = String.format("%s %s %s", "GET", userAgent, text); + log.debug(logLine); + File logFile = new File(webGoatHomeDirectory, "/XXE/log" + webSession.getUserName() + ".txt"); + try { + try (PrintWriter pw = new PrintWriter(logFile)) { + pw.println(logLine); + } + } catch (FileNotFoundException e) { + log.error("Error occurred while writing the logfile", e); } + return ""; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/SimpleXXE.java b/src/main/java/org/owasp/webgoat/lessons/xxe/SimpleXXE.java index 37893cd73..d51712cd4 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/SimpleXXE.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/SimpleXXE.java @@ -22,6 +22,10 @@ package org.owasp.webgoat.lessons.xxe; +import static org.springframework.http.MediaType.ALL_VALUE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +import javax.servlet.http.HttpServletRequest; import org.apache.commons.exec.OS; import org.apache.commons.lang3.exception.ExceptionUtils; import org.owasp.webgoat.container.assignments.AssignmentEndpoint; @@ -36,67 +40,73 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; - -import static org.springframework.http.MediaType.ALL_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - - /** * @author nbaars * @since 4/8/17. */ @RestController -@AssignmentHints({"xxe.hints.simple.xxe.1", "xxe.hints.simple.xxe.2", "xxe.hints.simple.xxe.3", "xxe.hints.simple.xxe.4", "xxe.hints.simple.xxe.5", "xxe.hints.simple.xxe.6"}) +@AssignmentHints({ + "xxe.hints.simple.xxe.1", + "xxe.hints.simple.xxe.2", + "xxe.hints.simple.xxe.3", + "xxe.hints.simple.xxe.4", + "xxe.hints.simple.xxe.5", + "xxe.hints.simple.xxe.6" +}) public class SimpleXXE extends AssignmentEndpoint { - private static final String[] DEFAULT_LINUX_DIRECTORIES = {"usr", "etc", "var"}; - private static final String[] DEFAULT_WINDOWS_DIRECTORIES = {"Windows", "Program Files (x86)", "Program Files", "pagefile.sys"}; + private static final String[] DEFAULT_LINUX_DIRECTORIES = {"usr", "etc", "var"}; + private static final String[] DEFAULT_WINDOWS_DIRECTORIES = { + "Windows", "Program Files (x86)", "Program Files", "pagefile.sys" + }; - @Value("${webgoat.server.directory}") - private String webGoatHomeDirectory; + @Value("${webgoat.server.directory}") + private String webGoatHomeDirectory; - @Value("${webwolf.landingpage.url}") - private String webWolfURL; + @Value("${webwolf.landingpage.url}") + private String webWolfURL; + @Autowired private CommentsCache comments; - @Autowired - private CommentsCache comments; - - @PostMapping(path = "xxe/simple", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE) - @ResponseBody - public AttackResult createNewComment(HttpServletRequest request, @RequestBody String commentStr) { - String error = ""; - try { - var comment = comments.parseXml(commentStr); - comments.addComment(comment, false); - if (checkSolution(comment)) { - return success(this).build(); - } - } catch (Exception e) { - error = ExceptionUtils.getStackTrace(e); - } - return failed(this).output(error).build(); + @PostMapping(path = "xxe/simple", consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE) + @ResponseBody + public AttackResult createNewComment(HttpServletRequest request, @RequestBody String commentStr) { + String error = ""; + try { + var comment = comments.parseXml(commentStr); + comments.addComment(comment, false); + if (checkSolution(comment)) { + return success(this).build(); + } + } catch (Exception e) { + error = ExceptionUtils.getStackTrace(e); } + return failed(this).output(error).build(); + } - private boolean checkSolution(Comment comment) { - String[] directoriesToCheck = OS.isFamilyMac() || OS.isFamilyUnix() ? DEFAULT_LINUX_DIRECTORIES : DEFAULT_WINDOWS_DIRECTORIES; - boolean success = false; - for (String directory : directoriesToCheck) { - success |= org.apache.commons.lang3.StringUtils.contains(comment.getText(), directory); - } - return success; + private boolean checkSolution(Comment comment) { + String[] directoriesToCheck = + OS.isFamilyMac() || OS.isFamilyUnix() + ? DEFAULT_LINUX_DIRECTORIES + : DEFAULT_WINDOWS_DIRECTORIES; + boolean success = false; + for (String directory : directoriesToCheck) { + success |= org.apache.commons.lang3.StringUtils.contains(comment.getText(), directory); } + return success; + } - @RequestMapping(path = "/xxe/sampledtd", consumes = ALL_VALUE, produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - public String getSampleDTDFile() { - return """ + @RequestMapping( + path = "/xxe/sampledtd", + consumes = ALL_VALUE, + produces = MediaType.TEXT_PLAIN_VALUE) + @ResponseBody + public String getSampleDTDFile() { + return """ "> %all; """; - } - + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/User.java b/src/main/java/org/owasp/webgoat/lessons/xxe/User.java index d32a2ef37..bca81e474 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/User.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/User.java @@ -27,23 +27,22 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class User { - private String username = ""; - private String password = ""; + private String username = ""; + private String password = ""; - public String getPassword() { - return password; - } + public String getPassword() { + return password; + } - public void setPassword(String password) { - this.password = password; - } + public void setPassword(String password) { + this.password = password; + } - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } } diff --git a/src/main/java/org/owasp/webgoat/lessons/xxe/XXE.java b/src/main/java/org/owasp/webgoat/lessons/xxe/XXE.java index fd6d8f631..e44c31851 100644 --- a/src/main/java/org/owasp/webgoat/lessons/xxe/XXE.java +++ b/src/main/java/org/owasp/webgoat/lessons/xxe/XXE.java @@ -29,13 +29,13 @@ import org.springframework.stereotype.Component; @Component public class XXE extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.A3; - } + @Override + public Category getDefaultCategory() { + return Category.A3; + } - @Override - public String getTitle() { - return "xxe.title"; - } + @Override + public String getTitle() { + return "xxe.title"; + } } diff --git a/src/main/java/org/owasp/webgoat/server/ParentConfig.java b/src/main/java/org/owasp/webgoat/server/ParentConfig.java index be8199693..b4a62db4d 100644 --- a/src/main/java/org/owasp/webgoat/server/ParentConfig.java +++ b/src/main/java/org/owasp/webgoat/server/ParentConfig.java @@ -5,6 +5,4 @@ import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan("org.owasp.webgoat.server") -public class ParentConfig { - -} +public class ParentConfig {} diff --git a/src/main/java/org/owasp/webgoat/server/StartWebGoat.java b/src/main/java/org/owasp/webgoat/server/StartWebGoat.java index c62dc6414..845a057ac 100644 --- a/src/main/java/org/owasp/webgoat/server/StartWebGoat.java +++ b/src/main/java/org/owasp/webgoat/server/StartWebGoat.java @@ -35,13 +35,16 @@ import org.springframework.boot.builder.SpringApplicationBuilder; @Slf4j public class StartWebGoat { - public static void main(String[] args) { - new SpringApplicationBuilder().parent(ParentConfig.class) - .web(WebApplicationType.NONE).bannerMode(Banner.Mode.OFF) - .child(WebGoat.class) - .web(WebApplicationType.SERVLET) - .sibling(WebWolf.class).bannerMode(Banner.Mode.OFF) - .web(WebApplicationType.SERVLET) - .run(args); - } + public static void main(String[] args) { + new SpringApplicationBuilder() + .parent(ParentConfig.class) + .web(WebApplicationType.NONE) + .bannerMode(Banner.Mode.OFF) + .child(WebGoat.class) + .web(WebApplicationType.SERVLET) + .sibling(WebWolf.class) + .bannerMode(Banner.Mode.OFF) + .web(WebApplicationType.SERVLET) + .run(args); + } } diff --git a/src/main/java/org/owasp/webgoat/server/StartupMessage.java b/src/main/java/org/owasp/webgoat/server/StartupMessage.java index 9395d3bb4..409ffb377 100644 --- a/src/main/java/org/owasp/webgoat/server/StartupMessage.java +++ b/src/main/java/org/owasp/webgoat/server/StartupMessage.java @@ -13,21 +13,21 @@ import org.springframework.util.StringUtils; @NoArgsConstructor public class StartupMessage { - private String port; - private String address; + private String port; + private String address; - @EventListener - void onStartup(ApplicationReadyEvent event) { - if (StringUtils.hasText(port) && !StringUtils.hasText(System.getProperty("running.in.docker"))) { - log.info("Please browse to http://{}:{}/WebGoat to get started...", address, port); - } - if (event.getApplicationContext().getApplicationName().contains("WebGoat")) { - port = event.getApplicationContext().getEnvironment().getProperty("server.port"); - address = event.getApplicationContext().getEnvironment().getProperty("server.address"); - } + @EventListener + void onStartup(ApplicationReadyEvent event) { + if (StringUtils.hasText(port) + && !StringUtils.hasText(System.getProperty("running.in.docker"))) { + log.info("Please browse to http://{}:{}/WebGoat to get started...", address, port); } + if (event.getApplicationContext().getApplicationName().contains("WebGoat")) { + port = event.getApplicationContext().getEnvironment().getProperty("server.port"); + address = event.getApplicationContext().getEnvironment().getProperty("server.address"); + } + } - @EventListener - void onShutdown(ContextStoppedEvent event) { - } + @EventListener + void onShutdown(ContextStoppedEvent event) {} } diff --git a/src/main/java/org/owasp/webgoat/webwolf/FileServer.java b/src/main/java/org/owasp/webgoat/webwolf/FileServer.java index 4cb608545..a23af4ce7 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/FileServer.java +++ b/src/main/java/org/owasp/webgoat/webwolf/FileServer.java @@ -22,6 +22,12 @@ package org.owasp.webgoat.webwolf; +import static org.springframework.http.MediaType.ALL_VALUE; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import javax.servlet.http.HttpServletRequest; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -41,81 +47,77 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.view.RedirectView; -import javax.servlet.http.HttpServletRequest; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; - -import static org.springframework.http.MediaType.ALL_VALUE; - -/** - * Controller for uploading a file - */ +/** Controller for uploading a file */ @Controller @Slf4j public class FileServer { - @Value("${webwolf.fileserver.location}") - private String fileLocation; - @Value("${server.address}") - private String server; - @Value("${server.port}") - private int port; + @Value("${webwolf.fileserver.location}") + private String fileLocation; - @RequestMapping(path = "/file-server-location", consumes = ALL_VALUE, produces = MediaType.TEXT_PLAIN_VALUE) - @ResponseBody - public String getFileLocation() { - return fileLocation; + @Value("${server.address}") + private String server; + + @Value("${server.port}") + private int port; + + @RequestMapping( + path = "/file-server-location", + consumes = ALL_VALUE, + produces = MediaType.TEXT_PLAIN_VALUE) + @ResponseBody + public String getFileLocation() { + return fileLocation; + } + + @PostMapping(value = "/fileupload") + public ModelAndView importFile(@RequestParam("file") MultipartFile myFile) throws IOException { + var user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + var destinationDir = new File(fileLocation, user.getUsername()); + destinationDir.mkdirs(); + myFile.transferTo(new File(destinationDir, myFile.getOriginalFilename())); + log.debug("File saved to {}", new File(destinationDir, myFile.getOriginalFilename())); + + return new ModelAndView( + new RedirectView("files", true), + new ModelMap().addAttribute("uploadSuccess", "File uploaded successful")); + } + + @AllArgsConstructor + @Getter + private class UploadedFile { + private final String name; + private final String size; + private final String link; + } + + @GetMapping(value = "/files") + public ModelAndView getFiles(HttpServletRequest request) { + WebGoatUser user = + (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + String username = user.getUsername(); + File destinationDir = new File(fileLocation, username); + + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("files"); + File changeIndicatorFile = new File(destinationDir, user.getUsername() + "_changed"); + if (changeIndicatorFile.exists()) { + modelAndView.addObject("uploadSuccess", request.getParameter("uploadSuccess")); + } + changeIndicatorFile.delete(); + + var uploadedFiles = new ArrayList<>(); + File[] files = destinationDir.listFiles(File::isFile); + if (files != null) { + for (File file : files) { + String size = FileUtils.byteCountToDisplaySize(file.length()); + String link = String.format("files/%s/%s", username, file.getName()); + uploadedFiles.add(new UploadedFile(file.getName(), size, link)); + } } - @PostMapping(value = "/fileupload") - public ModelAndView importFile(@RequestParam("file") MultipartFile myFile) throws IOException { - var user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - var destinationDir = new File(fileLocation, user.getUsername()); - destinationDir.mkdirs(); - myFile.transferTo(new File(destinationDir, myFile.getOriginalFilename())); - log.debug("File saved to {}", new File(destinationDir, myFile.getOriginalFilename())); - - return new ModelAndView( - new RedirectView("files", true), - new ModelMap().addAttribute("uploadSuccess", "File uploaded successful") - ); - } - - @AllArgsConstructor - @Getter - private class UploadedFile { - private final String name; - private final String size; - private final String link; - } - - @GetMapping(value = "/files") - public ModelAndView getFiles(HttpServletRequest request) { - WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - String username = user.getUsername(); - File destinationDir = new File(fileLocation, username); - - ModelAndView modelAndView = new ModelAndView(); - modelAndView.setViewName("files"); - File changeIndicatorFile = new File(destinationDir, user.getUsername() + "_changed"); - if (changeIndicatorFile.exists()) { - modelAndView.addObject("uploadSuccess", request.getParameter("uploadSuccess")); - } - changeIndicatorFile.delete(); - - var uploadedFiles = new ArrayList<>(); - File[] files = destinationDir.listFiles(File::isFile); - if (files != null) { - for (File file : files) { - String size = FileUtils.byteCountToDisplaySize(file.length()); - String link = String.format("files/%s/%s", username, file.getName()); - uploadedFiles.add(new UploadedFile(file.getName(), size, link)); - } - } - - modelAndView.addObject("files", uploadedFiles); - modelAndView.addObject("webwolf_url", "http://" + server + ":" + port); - return modelAndView; - } + modelAndView.addObject("files", uploadedFiles); + modelAndView.addObject("webwolf_url", "http://" + server + ":" + port); + return modelAndView; + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/MvcConfiguration.java b/src/main/java/org/owasp/webgoat/webwolf/MvcConfiguration.java index 836c1413f..f5fec0777 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/MvcConfiguration.java +++ b/src/main/java/org/owasp/webgoat/webwolf/MvcConfiguration.java @@ -22,15 +22,14 @@ package org.owasp.webgoat.webwolf; +import java.io.File; +import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import javax.annotation.PostConstruct; -import java.io.File; - /** * @author nbaars * @since 8/13/17. @@ -38,29 +37,31 @@ import java.io.File; @Configuration public class MvcConfiguration implements WebMvcConfigurer { - @Value("${webwolf.fileserver.location}") - private String fileLocation; + @Value("${webwolf.fileserver.location}") + private String fileLocation; - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.addResourceHandler("/files/**").addResourceLocations("file:///" + fileLocation + "/"); + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/files/**").addResourceLocations("file:///" + fileLocation + "/"); - registry.addResourceHandler("/css/**").addResourceLocations("classpath:/webwolf/static/css/"); - registry.addResourceHandler("/js/**").addResourceLocations("classpath:/webwolf/static/js/"); - registry.addResourceHandler("/images/**").addResourceLocations("classpath:/webwolf/static/images/"); - } - - @Override - public void addViewControllers(ViewControllerRegistry registry) { - registry.addViewController("/login").setViewName("webwolf-login"); - registry.addViewController("/home").setViewName("home"); - } - - @PostConstruct - public void createDirectory() { - File file = new File(fileLocation); - if (!file.exists()) { - file.mkdirs(); - } + registry.addResourceHandler("/css/**").addResourceLocations("classpath:/webwolf/static/css/"); + registry.addResourceHandler("/js/**").addResourceLocations("classpath:/webwolf/static/js/"); + registry + .addResourceHandler("/images/**") + .addResourceLocations("classpath:/webwolf/static/images/"); + } + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/login").setViewName("webwolf-login"); + registry.addViewController("/home").setViewName("home"); + } + + @PostConstruct + public void createDirectory() { + File file = new File(fileLocation); + if (!file.exists()) { + file.mkdirs(); } + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/WebSecurityConfig.java b/src/main/java/org/owasp/webgoat/webwolf/WebSecurityConfig.java index f867ea0bd..7afa030af 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/WebSecurityConfig.java +++ b/src/main/java/org/owasp/webgoat/webwolf/WebSecurityConfig.java @@ -1,4 +1,3 @@ - /* * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ * @@ -37,55 +36,50 @@ import org.springframework.security.config.annotation.web.configurers.Expression import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.NoOpPasswordEncoder; -/** - * Security configuration for WebGoat. - */ +/** Security configuration for WebGoat. */ @Configuration @AllArgsConstructor @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - private final UserService userDetailsService; + private final UserService userDetailsService; - @Override - protected void configure(HttpSecurity http) throws Exception { - ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry security = http - .authorizeRequests() - .antMatchers("/css/**", "/images/**", "/js/**", "/fonts/**", "/webjars/**", "/home").permitAll() - .antMatchers(HttpMethod.GET, "/mail/**", "/requests/**").authenticated() - .antMatchers("/files").authenticated() - .anyRequest().permitAll(); - security.and().csrf().disable().formLogin() - .loginPage("/login").failureUrl("/login?error=true"); - security.and() - .formLogin() - .loginPage("/login") - .defaultSuccessUrl("/home", true) - .permitAll(); - security.and() - .logout() - .permitAll(); - } + @Override + protected void configure(HttpSecurity http) throws Exception { + ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry security = + http.authorizeRequests() + .antMatchers("/css/**", "/images/**", "/js/**", "/fonts/**", "/webjars/**", "/home") + .permitAll() + .antMatchers(HttpMethod.GET, "/mail/**", "/requests/**") + .authenticated() + .antMatchers("/files") + .authenticated() + .anyRequest() + .permitAll(); + security.and().csrf().disable().formLogin().loginPage("/login").failureUrl("/login?error=true"); + security.and().formLogin().loginPage("/login").defaultSuccessUrl("/home", true).permitAll(); + security.and().logout().permitAll(); + } - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.userDetailsService(userDetailsService); //.passwordEncoder(bCryptPasswordEncoder()); - } + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService); // .passwordEncoder(bCryptPasswordEncoder()); + } - @Bean - @Override - public UserDetailsService userDetailsServiceBean() throws Exception { - return userDetailsService; - } + @Bean + @Override + public UserDetailsService userDetailsServiceBean() throws Exception { + return userDetailsService; + } - @Override - @Bean - protected AuthenticationManager authenticationManager() throws Exception { - return super.authenticationManager(); - } + @Override + @Bean + protected AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } - @Bean - public NoOpPasswordEncoder passwordEncoder() { - return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); - } + @Bean + public NoOpPasswordEncoder passwordEncoder() { + return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/WebWolf.java b/src/main/java/org/owasp/webgoat/webwolf/WebWolf.java index 25429a664..fa5d488a3 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/WebWolf.java +++ b/src/main/java/org/owasp/webgoat/webwolf/WebWolf.java @@ -36,9 +36,8 @@ import org.springframework.context.annotation.PropertySource; @EnableAutoConfiguration public class WebWolf { - @Bean - public HttpTraceRepository traceRepository() { - return new WebWolfTraceRepository(); - } - + @Bean + public HttpTraceRepository traceRepository() { + return new WebWolfTraceRepository(); + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/jwt/JWTController.java b/src/main/java/org/owasp/webgoat/webwolf/jwt/JWTController.java index bc5c5f5c4..7d7ab61ba 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/jwt/JWTController.java +++ b/src/main/java/org/owasp/webgoat/webwolf/jwt/JWTController.java @@ -1,5 +1,8 @@ package org.owasp.webgoat.webwolf.jwt; +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -7,30 +10,32 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; - @RestController public class JWTController { - @GetMapping("/jwt") - public ModelAndView jwt() { - return new ModelAndView("jwt"); - } + @GetMapping("/jwt") + public ModelAndView jwt() { + return new ModelAndView("jwt"); + } - @PostMapping(value = "/jwt/decode", consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = APPLICATION_JSON_VALUE) - public JWTToken decode(@RequestBody MultiValueMap formData) { - var jwt = formData.getFirst("token"); - var secretKey = formData.getFirst("secretKey"); - return JWTToken.decode(jwt, secretKey); - } - - @PostMapping(value = "/jwt/encode", consumes = APPLICATION_FORM_URLENCODED_VALUE, produces = APPLICATION_JSON_VALUE) - public JWTToken encode(@RequestBody MultiValueMap formData) { - var header = formData.getFirst("header"); - var payload = formData.getFirst("payload"); - var secretKey = formData.getFirst("secretKey"); - return JWTToken.encode(header, payload, secretKey); - } + @PostMapping( + value = "/jwt/decode", + consumes = APPLICATION_FORM_URLENCODED_VALUE, + produces = APPLICATION_JSON_VALUE) + public JWTToken decode(@RequestBody MultiValueMap formData) { + var jwt = formData.getFirst("token"); + var secretKey = formData.getFirst("secretKey"); + return JWTToken.decode(jwt, secretKey); + } + @PostMapping( + value = "/jwt/encode", + consumes = APPLICATION_FORM_URLENCODED_VALUE, + produces = APPLICATION_JSON_VALUE) + public JWTToken encode(@RequestBody MultiValueMap formData) { + var header = formData.getFirst("header"); + var payload = formData.getFirst("payload"); + var secretKey = formData.getFirst("secretKey"); + return JWTToken.encode(header, payload, secretKey); + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/jwt/JWTToken.java b/src/main/java/org/owasp/webgoat/webwolf/jwt/JWTToken.java index ced8fcbf6..88fcdc1c5 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/jwt/JWTToken.java +++ b/src/main/java/org/owasp/webgoat/webwolf/jwt/JWTToken.java @@ -1,7 +1,13 @@ package org.owasp.webgoat.webwolf.jwt; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.springframework.util.Base64Utils.decodeFromUrlSafeString; +import static org.springframework.util.StringUtils.hasText; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Map; +import java.util.TreeMap; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -15,14 +21,6 @@ import org.jose4j.jwx.CompactSerializer; import org.jose4j.keys.HmacKey; import org.jose4j.lang.JoseException; -import java.util.Map; -import java.util.TreeMap; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.jose4j.jwx.CompactSerializer.serialize; -import static org.springframework.util.Base64Utils.decodeFromUrlSafeString; -import static org.springframework.util.StringUtils.hasText; - @NoArgsConstructor @AllArgsConstructor @Getter @@ -30,108 +28,111 @@ import static org.springframework.util.StringUtils.hasText; @Builder(toBuilder = true) public class JWTToken { - private String encoded = ""; - private String secretKey; - private String header; - private boolean validHeader; - private boolean validPayload; - private boolean validToken; - private String payload; - private boolean signatureValid = true; + private String encoded = ""; + private String secretKey; + private String header; + private boolean validHeader; + private boolean validPayload; + private boolean validToken; + private String payload; + private boolean signatureValid = true; - public static JWTToken decode(String jwt, String secretKey) { - var token = parseToken(jwt.trim().replace(System.getProperty("line.separator"), "")); - return token.toBuilder().signatureValid(validateSignature(secretKey, jwt)).build(); + public static JWTToken decode(String jwt, String secretKey) { + var token = parseToken(jwt.trim().replace(System.getProperty("line.separator"), "")); + return token.toBuilder().signatureValid(validateSignature(secretKey, jwt)).build(); + } + + private static Map parse(String header) { + var reader = new ObjectMapper(); + try { + return reader.readValue(header, TreeMap.class); + } catch (JsonProcessingException e) { + return Map.of(); + } + } + + private static String write(String originalValue, Map data) { + var writer = new ObjectMapper().writerWithDefaultPrettyPrinter(); + try { + if (data.isEmpty()) { + return originalValue; + } + return writer.writeValueAsString(data); + } catch (JsonProcessingException e) { + return originalValue; + } + } + + public static JWTToken encode(String header, String payloadAsString, String secretKey) { + var headers = parse(header); + var payload = parse(payloadAsString); + + var builder = + JWTToken.builder() + .header(write(header, headers)) + .payload(write(payloadAsString, payload)) + .validHeader(!hasText(header) || !headers.isEmpty()) + .validToken(true) + .validPayload(!hasText(payloadAsString) || !payload.isEmpty()); + + JsonWebSignature jws = new JsonWebSignature(); + jws.setPayload(payloadAsString); + headers.forEach((k, v) -> jws.setHeader(k, v)); + if (!headers.isEmpty()) { // otherwise e30 meaning {} will be shown as header + builder.encoded( + CompactSerializer.serialize( + new String[] {jws.getHeaders().getEncodedHeader(), jws.getEncodedPayload()})); } - private static Map parse(String header) { - var reader = new ObjectMapper(); - try { - return reader.readValue(header, TreeMap.class); - } catch (JsonProcessingException e) { - return Map.of(); - } + // Only sign when valid header and payload + if (!headers.isEmpty() && !payload.isEmpty() && hasText(secretKey)) { + jws.setDoKeyValidation(false); + jws.setKey(new HmacKey(secretKey.getBytes(UTF_8))); + try { + builder.encoded(jws.getCompactSerialization()); + builder.signatureValid(true); + } catch (JoseException e) { + // Do nothing + } } + return builder.build(); + } - private static String write(String originalValue, Map data) { - var writer = new ObjectMapper().writerWithDefaultPrettyPrinter(); - try { - if (data.isEmpty()) { - return originalValue; - } - return writer.writeValueAsString(data); - } catch (JsonProcessingException e) { - return originalValue; - } + private static JWTToken parseToken(String jwt) { + var token = jwt.split("\\."); + var builder = JWTToken.builder().encoded(jwt); + + if (token.length >= 2) { + var header = new String(decodeFromUrlSafeString(token[0]), UTF_8); + var payloadAsString = new String(decodeFromUrlSafeString(token[1]), UTF_8); + var headers = parse(header); + var payload = parse(payloadAsString); + builder.header(write(header, headers)); + builder.payload(write(payloadAsString, payload)); + builder.validHeader(!headers.isEmpty()); + builder.validPayload(!payload.isEmpty()); + builder.validToken(!headers.isEmpty() && !payload.isEmpty()); + } else { + builder.validToken(false); } + return builder.build(); + } - public static JWTToken encode(String header, String payloadAsString, String secretKey) { - var headers = parse(header); - var payload = parse(payloadAsString); - - var builder = JWTToken.builder() - .header(write(header, headers)) - .payload(write(payloadAsString, payload)) - .validHeader(!hasText(header) || !headers.isEmpty()) - .validToken(true) - .validPayload(!hasText(payloadAsString) || !payload.isEmpty()); - - JsonWebSignature jws = new JsonWebSignature(); - jws.setPayload(payloadAsString); - headers.forEach((k, v) -> jws.setHeader(k, v)); - if (!headers.isEmpty()) { //otherwise e30 meaning {} will be shown as header - builder.encoded(CompactSerializer.serialize(new String[]{jws.getHeaders().getEncodedHeader(), jws.getEncodedPayload()})); - } - - //Only sign when valid header and payload - if (!headers.isEmpty() && !payload.isEmpty() && hasText(secretKey)) { - jws.setDoKeyValidation(false); - jws.setKey(new HmacKey(secretKey.getBytes(UTF_8))); - try { - builder.encoded(jws.getCompactSerialization()); - builder.signatureValid(true); - } catch (JoseException e) { - //Do nothing - } - } - return builder.build(); - } - - private static JWTToken parseToken(String jwt) { - var token = jwt.split("\\."); - var builder = JWTToken.builder().encoded(jwt); - - if (token.length >= 2) { - var header = new String(decodeFromUrlSafeString(token[0]), UTF_8); - var payloadAsString = new String(decodeFromUrlSafeString(token[1]), UTF_8); - var headers = parse(header); - var payload = parse(payloadAsString); - builder.header(write(header, headers)); - builder.payload(write(payloadAsString, payload)); - builder.validHeader(!headers.isEmpty()); - builder.validPayload(!payload.isEmpty()); - builder.validToken(!headers.isEmpty() && !payload.isEmpty()); - } else { - builder.validToken(false); - } - return builder.build(); - } - - private static boolean validateSignature(String secretKey, String jwt) { - if (hasText(secretKey)) { - JwtConsumer jwtConsumer = new JwtConsumerBuilder() - .setSkipAllValidators() - .setVerificationKey(new HmacKey(secretKey.getBytes(UTF_8))) - .setRelaxVerificationKeyValidation() - .build(); - try { - jwtConsumer.processToClaims(jwt); - return true; - } catch (InvalidJwtException e) { - return false; - } - } + private static boolean validateSignature(String secretKey, String jwt) { + if (hasText(secretKey)) { + JwtConsumer jwtConsumer = + new JwtConsumerBuilder() + .setSkipAllValidators() + .setVerificationKey(new HmacKey(secretKey.getBytes(UTF_8))) + .setRelaxVerificationKeyValidation() + .build(); + try { + jwtConsumer.processToClaims(jwt); + return true; + } catch (InvalidJwtException e) { return false; + } } - + return false; + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/mailbox/Email.java b/src/main/java/org/owasp/webgoat/webwolf/mailbox/Email.java index 8b009ceae..4cca7856b 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/mailbox/Email.java +++ b/src/main/java/org/owasp/webgoat/webwolf/mailbox/Email.java @@ -23,16 +23,15 @@ package org.owasp.webgoat.webwolf.mailbox; import com.fasterxml.jackson.annotation.JsonIgnore; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import javax.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import javax.persistence.*; -import java.io.Serializable; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - /** * @author nbaars * @since 8/20/17. @@ -44,31 +43,32 @@ import java.time.format.DateTimeFormatter; @NoArgsConstructor public class Email implements Serializable { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - @JsonIgnore - private LocalDateTime time = LocalDateTime.now(); - @Column(length = 1024) - private String contents; - private String sender; - private String title; - private String recipient; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - public String getSummary() { - return "-" + this.contents.substring(0, Math.min(50, contents.length())); - } + @JsonIgnore private LocalDateTime time = LocalDateTime.now(); - public LocalDateTime getTimestamp() { - return time; - } + @Column(length = 1024) + private String contents; - public String getTime() { - return DateTimeFormatter.ofPattern("h:mm a").format(time); - } + private String sender; + private String title; + private String recipient; - public String getShortSender() { - return sender.substring(0, sender.indexOf("@")); - } + public String getSummary() { + return "-" + this.contents.substring(0, Math.min(50, contents.length())); + } + public LocalDateTime getTimestamp() { + return time; + } + + public String getTime() { + return DateTimeFormatter.ofPattern("h:mm a").format(time); + } + + public String getShortSender() { + return sender.substring(0, sender.indexOf("@")); + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/mailbox/MailboxController.java b/src/main/java/org/owasp/webgoat/webwolf/mailbox/MailboxController.java index 6f1fbafdf..6a3640bfd 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/mailbox/MailboxController.java +++ b/src/main/java/org/owasp/webgoat/webwolf/mailbox/MailboxController.java @@ -22,6 +22,7 @@ package org.owasp.webgoat.webwolf.mailbox; +import java.util.List; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -34,32 +35,30 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView; -import java.util.List; - @RestController @AllArgsConstructor @Slf4j public class MailboxController { - private final MailboxRepository mailboxRepository; + private final MailboxRepository mailboxRepository; - @GetMapping(value = "/mail") - public ModelAndView mail() { - UserDetails user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - ModelAndView modelAndView = new ModelAndView(); - List emails = mailboxRepository.findByRecipientOrderByTimeDesc(user.getUsername()); - if (emails != null && !emails.isEmpty()) { - modelAndView.addObject("total", emails.size()); - modelAndView.addObject("emails", emails); - } - modelAndView.setViewName("mailbox"); - return modelAndView; - } - - @PostMapping(value = "/mail") - public ResponseEntity sendEmail(@RequestBody Email email) { - mailboxRepository.save(email); - return ResponseEntity.status(HttpStatus.CREATED).build(); + @GetMapping(value = "/mail") + public ModelAndView mail() { + UserDetails user = + (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + ModelAndView modelAndView = new ModelAndView(); + List emails = mailboxRepository.findByRecipientOrderByTimeDesc(user.getUsername()); + if (emails != null && !emails.isEmpty()) { + modelAndView.addObject("total", emails.size()); + modelAndView.addObject("emails", emails); } + modelAndView.setViewName("mailbox"); + return modelAndView; + } + @PostMapping(value = "/mail") + public ResponseEntity sendEmail(@RequestBody Email email) { + mailboxRepository.save(email); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/mailbox/MailboxRepository.java b/src/main/java/org/owasp/webgoat/webwolf/mailbox/MailboxRepository.java index 436498dab..b1979ada8 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/mailbox/MailboxRepository.java +++ b/src/main/java/org/owasp/webgoat/webwolf/mailbox/MailboxRepository.java @@ -22,9 +22,8 @@ package org.owasp.webgoat.webwolf.mailbox; -import org.springframework.data.jpa.repository.JpaRepository; - import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; /** * @author nbaars @@ -32,6 +31,5 @@ import java.util.List; */ public interface MailboxRepository extends JpaRepository { - List findByRecipientOrderByTimeDesc(String recipient); - + List findByRecipientOrderByTimeDesc(String recipient); } diff --git a/src/main/java/org/owasp/webgoat/webwolf/requests/LandingPage.java b/src/main/java/org/owasp/webgoat/webwolf/requests/LandingPage.java index 763340376..6d46c014f 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/requests/LandingPage.java +++ b/src/main/java/org/owasp/webgoat/webwolf/requests/LandingPage.java @@ -22,26 +22,31 @@ package org.owasp.webgoat.webwolf.requests; +import java.util.concurrent.Callable; +import javax.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import javax.servlet.http.HttpServletRequest; -import java.util.concurrent.Callable; - @Controller @Slf4j @RequestMapping("/landing/**") public class LandingPage { - @RequestMapping(method = {RequestMethod.POST, RequestMethod.GET, RequestMethod.DELETE, RequestMethod.PATCH, RequestMethod.PUT}) - public Callable> ok(HttpServletRequest request) { - return () -> { - log.trace("Incoming request for: {}", request.getRequestURL()); - return ResponseEntity.ok().build(); - }; - } - + @RequestMapping( + method = { + RequestMethod.POST, + RequestMethod.GET, + RequestMethod.DELETE, + RequestMethod.PATCH, + RequestMethod.PUT + }) + public Callable> ok(HttpServletRequest request) { + return () -> { + log.trace("Incoming request for: {}", request.getRequestURL()); + return ResponseEntity.ok().build(); + }; + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/requests/Requests.java b/src/main/java/org/owasp/webgoat/webwolf/requests/Requests.java index 54c623dd2..f510ed7e9 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/requests/Requests.java +++ b/src/main/java/org/owasp/webgoat/webwolf/requests/Requests.java @@ -22,8 +22,11 @@ package org.owasp.webgoat.webwolf.requests; +import static java.util.stream.Collectors.toList; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import java.time.Instant; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -38,13 +41,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; -import java.time.Instant; - -import static java.util.stream.Collectors.toList; - /** - * Controller for fetching all the HTTP requests from WebGoat to WebWolf for a specific - * user. + * Controller for fetching all the HTTP requests from WebGoat to WebWolf for a specific user. * * @author nbaars * @since 8/13/17. @@ -55,52 +53,58 @@ import static java.util.stream.Collectors.toList; @RequestMapping(value = "/requests") public class Requests { - private final WebWolfTraceRepository traceRepository; - private final ObjectMapper objectMapper; + private final WebWolfTraceRepository traceRepository; + private final ObjectMapper objectMapper; - @AllArgsConstructor - @Getter - private class Tracert { - private final Instant date; - private final String path; - private final String json; + @AllArgsConstructor + @Getter + private class Tracert { + private final Instant date; + private final String path; + private final String json; + } + + @GetMapping + public ModelAndView get() { + var model = new ModelAndView("requests"); + var user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); + var traces = + traceRepository.findAllTraces().stream() + .filter(t -> allowedTrace(t, user)) + .map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t))) + .collect(toList()); + model.addObject("traces", traces); + + return model; + } + + private boolean allowedTrace(HttpTrace t, UserDetails user) { + Request req = t.getRequest(); + boolean allowed = true; + /* do not show certain traces to other users in a classroom setup */ + if (req.getUri().getPath().contains("/files") + && !req.getUri().getPath().contains(user.getUsername())) { + allowed = false; + } else if (req.getUri().getPath().contains("/landing") + && req.getUri().getQuery() != null + && req.getUri().getQuery().contains("uniqueCode") + && !req.getUri().getQuery().contains(StringUtils.reverse(user.getUsername()))) { + allowed = false; } - @GetMapping - public ModelAndView get() { - var model = new ModelAndView("requests"); - var user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - var traces = traceRepository.findAllTraces().stream() - .filter(t -> allowedTrace(t, user)) - .map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t))).collect(toList()); - model.addObject("traces", traces); + return allowed; + } - return model; - } - - private boolean allowedTrace(HttpTrace t, UserDetails user) { - Request req = t.getRequest(); - boolean allowed = true; - /* do not show certain traces to other users in a classroom setup */ - if (req.getUri().getPath().contains("/files") && !req.getUri().getPath().contains(user.getUsername())) { - allowed = false; - } else if (req.getUri().getPath().contains("/landing") && req.getUri().getQuery()!=null && req.getUri().getQuery().contains("uniqueCode") && !req.getUri().getQuery().contains(StringUtils.reverse(user.getUsername()))) { - allowed = false; - } - - return allowed; - } + private String path(HttpTrace t) { + return (String) t.getRequest().getUri().getPath(); + } - private String path(HttpTrace t) { - return (String) t.getRequest().getUri().getPath(); - } - - private String toJsonString(HttpTrace t) { - try { - return objectMapper.writeValueAsString(t); - } catch (JsonProcessingException e) { - log.error("Unable to create json", e); - } - return "No request(s) found"; + private String toJsonString(HttpTrace t) { + try { + return objectMapper.writeValueAsString(t); + } catch (JsonProcessingException e) { + log.error("Unable to create json", e); } + return "No request(s) found"; + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/requests/WebWolfTraceRepository.java b/src/main/java/org/owasp/webgoat/webwolf/requests/WebWolfTraceRepository.java index 5c117b666..bba73a890 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/requests/WebWolfTraceRepository.java +++ b/src/main/java/org/owasp/webgoat/webwolf/requests/WebWolfTraceRepository.java @@ -23,14 +23,12 @@ package org.owasp.webgoat.webwolf.requests; import com.google.common.collect.EvictingQueue; -import com.google.common.collect.Lists; +import java.util.ArrayList; +import java.util.List; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.actuate.trace.http.HttpTrace; import org.springframework.boot.actuate.trace.http.HttpTraceRepository; -import java.util.ArrayList; -import java.util.List; - /** * Keep track of all the incoming requests, we are only keeping track of request originating from * WebGoat. @@ -41,28 +39,38 @@ import java.util.List; @Slf4j public class WebWolfTraceRepository implements HttpTraceRepository { - private final EvictingQueue traces = EvictingQueue.create(10000); - private final List exclusionList = List.of("/tmpdir", "/home", "/files", - "/images/", "/favicon.ico", "/js/", "/webjars/", "/requests", "/css/", "/mail"); + private final EvictingQueue traces = EvictingQueue.create(10000); + private final List exclusionList = + List.of( + "/tmpdir", + "/home", + "/files", + "/images/", + "/favicon.ico", + "/js/", + "/webjars/", + "/requests", + "/css/", + "/mail"); - @Override - public List findAll() { - return List.of(); - } + @Override + public List findAll() { + return List.of(); + } - public List findAllTraces() { - return new ArrayList<>(traces); - } + public List findAllTraces() { + return new ArrayList<>(traces); + } - private boolean isInExclusionList(String path) { - return exclusionList.stream().anyMatch(e -> path.contains(e)); - } + private boolean isInExclusionList(String path) { + return exclusionList.stream().anyMatch(e -> path.contains(e)); + } - @Override - public void add(HttpTrace httpTrace) { - var path = httpTrace.getRequest().getUri().getPath(); - if (!isInExclusionList(path)) { - traces.add(httpTrace); - } + @Override + public void add(HttpTrace httpTrace) { + var path = httpTrace.getRequest().getUri().getPath(); + if (!isInExclusionList(path)) { + traces.add(httpTrace); } + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/user/UserRepository.java b/src/main/java/org/owasp/webgoat/webwolf/user/UserRepository.java index 33332a53e..c7e87b559 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/user/UserRepository.java +++ b/src/main/java/org/owasp/webgoat/webwolf/user/UserRepository.java @@ -30,5 +30,5 @@ import org.springframework.data.jpa.repository.JpaRepository; */ public interface UserRepository extends JpaRepository { - WebGoatUser findByUsername(String username); + WebGoatUser findByUsername(String username); } diff --git a/src/main/java/org/owasp/webgoat/webwolf/user/UserService.java b/src/main/java/org/owasp/webgoat/webwolf/user/UserService.java index d0799c5b1..a57980e9c 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/user/UserService.java +++ b/src/main/java/org/owasp/webgoat/webwolf/user/UserService.java @@ -33,24 +33,23 @@ import org.springframework.stereotype.Service; @Service public class UserService implements UserDetailsService { - private UserRepository userRepository; + private UserRepository userRepository; - public UserService(UserRepository userRepository) { - this.userRepository = userRepository; + public UserService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + public WebGoatUser loadUserByUsername(final String username) throws UsernameNotFoundException { + WebGoatUser webGoatUser = userRepository.findByUsername(username); + if (webGoatUser == null) { + throw new UsernameNotFoundException("User not found"); } + webGoatUser.createUser(); + return webGoatUser; + } - @Override - public WebGoatUser loadUserByUsername(final String username) throws UsernameNotFoundException { - WebGoatUser webGoatUser = userRepository.findByUsername(username); - if (webGoatUser == null) { - throw new UsernameNotFoundException("User not found"); - } - webGoatUser.createUser(); - return webGoatUser; - } - - - public void addUser(final String username, final String password) { - userRepository.save(new WebGoatUser(username, password)); - } + public void addUser(final String username, final String password) { + userRepository.save(new WebGoatUser(username, password)); + } } diff --git a/src/main/java/org/owasp/webgoat/webwolf/user/WebGoatUser.java b/src/main/java/org/owasp/webgoat/webwolf/user/WebGoatUser.java index e9da6eaf4..d432ff925 100644 --- a/src/main/java/org/owasp/webgoat/webwolf/user/WebGoatUser.java +++ b/src/main/java/org/owasp/webgoat/webwolf/user/WebGoatUser.java @@ -22,17 +22,15 @@ package org.owasp.webgoat.webwolf.user; -import lombok.Getter; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; - +import java.util.Collection; +import java.util.Collections; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Transient; -import java.util.Collection; -import java.util.Collections; +import lombok.Getter; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; /** * @author nbaars @@ -42,48 +40,43 @@ import java.util.Collections; @Entity public class WebGoatUser implements UserDetails { - @Id - private String username; - private String password; - @Transient - private User user; + @Id private String username; + private String password; + @Transient private User user; - protected WebGoatUser() { - } + protected WebGoatUser() {} - public WebGoatUser(String username, String password) { - this.username = username; - this.password = password; - createUser(); - } + public WebGoatUser(String username, String password) { + this.username = username; + this.password = password; + createUser(); + } - public void createUser() { - this.user = new User(username, password, getAuthorities()); - } + public void createUser() { + this.user = new User(username, password, getAuthorities()); + } - public Collection getAuthorities() { - return Collections.emptyList(); - } + public Collection getAuthorities() { + return Collections.emptyList(); + } - @Override - public boolean isAccountNonExpired() { - return this.user.isAccountNonExpired(); - } + @Override + public boolean isAccountNonExpired() { + return this.user.isAccountNonExpired(); + } - @Override - public boolean isAccountNonLocked() { - return this.user.isAccountNonLocked(); - } + @Override + public boolean isAccountNonLocked() { + return this.user.isAccountNonLocked(); + } - @Override - public boolean isCredentialsNonExpired() { - return this.user.isCredentialsNonExpired(); - } + @Override + public boolean isCredentialsNonExpired() { + return this.user.isCredentialsNonExpired(); + } - @Override - public boolean isEnabled() { - return this.user.isEnabled(); - } + @Override + public boolean isEnabled() { + return this.user.isEnabled(); + } } - - diff --git a/src/test/java/org/owasp/webgoat/container/WebGoatApplication.java b/src/test/java/org/owasp/webgoat/container/WebGoatApplication.java index 0fd8e65c1..49e287a30 100644 --- a/src/test/java/org/owasp/webgoat/container/WebGoatApplication.java +++ b/src/test/java/org/owasp/webgoat/container/WebGoatApplication.java @@ -5,6 +5,4 @@ import org.springframework.context.annotation.PropertySource; @SpringBootApplication(scanBasePackages = "org.owasp.webgoat.container") @PropertySource("classpath:application-webgoat.properties") -public class WebGoatApplication { - -} +public class WebGoatApplication {} diff --git a/src/test/java/org/owasp/webgoat/container/assignments/AssignmentEndpointTest.java b/src/test/java/org/owasp/webgoat/container/assignments/AssignmentEndpointTest.java index dd1fe4aa8..258919d81 100644 --- a/src/test/java/org/owasp/webgoat/container/assignments/AssignmentEndpointTest.java +++ b/src/test/java/org/owasp/webgoat/container/assignments/AssignmentEndpointTest.java @@ -25,47 +25,42 @@ package org.owasp.webgoat.container.assignments; +import java.util.Locale; import org.mockito.Mock; import org.owasp.webgoat.container.i18n.Language; import org.owasp.webgoat.container.i18n.Messages; import org.owasp.webgoat.container.i18n.PluginMessages; import org.owasp.webgoat.container.session.UserSessionData; -import org.owasp.webgoat.container.users.UserTracker; import org.owasp.webgoat.container.session.WebSession; +import org.owasp.webgoat.container.users.UserTracker; import org.owasp.webgoat.container.users.UserTrackerRepository; import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.servlet.i18n.FixedLocaleResolver; -import java.util.Locale; - -//Do not remove is the base class for all assignments tests +// Do not remove is the base class for all assignments tests public class AssignmentEndpointTest { - @Mock - protected UserTracker userTracker; - @Mock - protected UserTrackerRepository userTrackerRepository; - @Mock - protected WebSession webSession; - @Mock - protected UserSessionData userSessionData; + @Mock protected UserTracker userTracker; + @Mock protected UserTrackerRepository userTrackerRepository; + @Mock protected WebSession webSession; + @Mock protected UserSessionData userSessionData; - private Language language = new Language(new FixedLocaleResolver()) { + private Language language = + new Language(new FixedLocaleResolver()) { @Override public Locale getLocale() { - return Locale.ENGLISH; + return Locale.ENGLISH; } - }; - protected Messages messages = new Messages(language); - protected PluginMessages pluginMessages = new PluginMessages(messages, language, new ClassPathXmlApplicationContext()); - - public void init(AssignmentEndpoint a) { - messages.setBasenames("classpath:/i18n/messages", "classpath:/i18n/WebGoatLabels"); - ReflectionTestUtils.setField(a, "userSessionData", userSessionData); - ReflectionTestUtils.setField(a, "webSession", webSession); - ReflectionTestUtils.setField(a, "messages", pluginMessages); - } + }; + protected Messages messages = new Messages(language); + protected PluginMessages pluginMessages = + new PluginMessages(messages, language, new ClassPathXmlApplicationContext()); + public void init(AssignmentEndpoint a) { + messages.setBasenames("classpath:/i18n/messages", "classpath:/i18n/WebGoatLabels"); + ReflectionTestUtils.setField(a, "userSessionData", userSessionData); + ReflectionTestUtils.setField(a, "webSession", webSession); + ReflectionTestUtils.setField(a, "messages", pluginMessages); + } } diff --git a/src/test/java/org/owasp/webgoat/container/plugins/LessonTest.java b/src/test/java/org/owasp/webgoat/container/plugins/LessonTest.java index 89b2a3cb5..465046c67 100644 --- a/src/test/java/org/owasp/webgoat/container/plugins/LessonTest.java +++ b/src/test/java/org/owasp/webgoat/container/plugins/LessonTest.java @@ -1,5 +1,11 @@ package org.owasp.webgoat.container.plugins; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Locale; +import java.util.function.Function; +import javax.annotation.PostConstruct; import org.flywaydb.core.Flyway; import org.junit.jupiter.api.BeforeEach; import org.owasp.webgoat.container.WebGoat; @@ -17,50 +23,41 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.WebApplicationContext; -import javax.annotation.PostConstruct; -import java.util.List; -import java.util.Locale; -import java.util.function.Function; - -import static org.mockito.Mockito.when; - /** * @author nbaars * @since 5/20/17. */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebGoat.class) -@TestPropertySource(locations = {"classpath:/application-webgoat.properties", "classpath:/application-webgoat-test.properties"}) +@TestPropertySource( + locations = { + "classpath:/application-webgoat.properties", + "classpath:/application-webgoat-test.properties" + }) public abstract class LessonTest { - @LocalServerPort - protected int localPort; - protected MockMvc mockMvc; - @Autowired - protected WebApplicationContext wac; - @Autowired - protected PluginMessages messages; - @Autowired - private Function flywayLessons; - @Autowired - private List lessonInitializers; - @MockBean - protected WebSession webSession; - @MockBean - private Language language; - @Value("${webgoat.user.directory}") - protected String webGoatHomeDirectory; + @LocalServerPort protected int localPort; + protected MockMvc mockMvc; + @Autowired protected WebApplicationContext wac; + @Autowired protected PluginMessages messages; + @Autowired private Function flywayLessons; + @Autowired private List lessonInitializers; + @MockBean protected WebSession webSession; + @MockBean private Language language; - @BeforeEach - void init() { - var user = new WebGoatUser("unit-test", "test"); - when(webSession.getUserName()).thenReturn(user.getUsername()); - when(webSession.getUser()).thenReturn(user); - when(language.getLocale()).thenReturn(Locale.getDefault()); - lessonInitializers.forEach(init -> init.initialize(webSession.getUser())); - } + @Value("${webgoat.user.directory}") + protected String webGoatHomeDirectory; - @PostConstruct - public void createFlywayLessonTables() { - flywayLessons.apply("PUBLIC").migrate(); - } + @BeforeEach + void init() { + var user = new WebGoatUser("unit-test", "test"); + when(webSession.getUserName()).thenReturn(user.getUsername()); + when(webSession.getUser()).thenReturn(user); + when(language.getLocale()).thenReturn(Locale.getDefault()); + lessonInitializers.forEach(init -> init.initialize(webSession.getUser())); + } + + @PostConstruct + public void createFlywayLessonTables() { + flywayLessons.apply("PUBLIC").migrate(); + } } diff --git a/src/test/java/org/owasp/webgoat/container/service/HintServiceTest.java b/src/test/java/org/owasp/webgoat/container/service/HintServiceTest.java index d4b083f96..9ca5ffd05 100644 --- a/src/test/java/org/owasp/webgoat/container/service/HintServiceTest.java +++ b/src/test/java/org/owasp/webgoat/container/service/HintServiceTest.java @@ -1,5 +1,11 @@ package org.owasp.webgoat.container.service; +import static org.mockito.Mockito.when; +import static org.owasp.webgoat.container.service.HintService.URL_HINTS_MVC; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import com.beust.jcommander.internal.Lists; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; @@ -14,38 +20,30 @@ import org.owasp.webgoat.container.session.WebSession; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.mockito.Mockito.when; -import static org.owasp.webgoat.container.service.HintService.URL_HINTS_MVC; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - @ExtendWith(MockitoExtension.class) public class HintServiceTest { - private MockMvc mockMvc; - @Mock - private WebSession websession; - @Mock - private Lesson lesson; - @Mock - private Assignment assignment; + private MockMvc mockMvc; + @Mock private WebSession websession; + @Mock private Lesson lesson; + @Mock private Assignment assignment; - @BeforeEach - void setup() { - this.mockMvc = standaloneSetup(new HintService(websession)).build(); - } + @BeforeEach + void setup() { + this.mockMvc = standaloneSetup(new HintService(websession)).build(); + } - @Test - void hintsPerAssignment() throws Exception { - Assignment assignment = Mockito.mock(Assignment.class); - when(assignment.getPath()).thenReturn("/HttpBasics/attack1"); - when(assignment.getHints()).thenReturn(Lists.newArrayList("hint 1", "hint 2")); - when(lesson.getAssignments()).thenReturn(Lists.newArrayList(assignment)); - when(websession.getCurrentLesson()).thenReturn(lesson); - mockMvc.perform(MockMvcRequestBuilders.get(URL_HINTS_MVC)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].hint", CoreMatchers.is("hint 1"))) - .andExpect(jsonPath("$[0].assignmentPath", CoreMatchers.is("/HttpBasics/attack1"))); - } + @Test + void hintsPerAssignment() throws Exception { + Assignment assignment = Mockito.mock(Assignment.class); + when(assignment.getPath()).thenReturn("/HttpBasics/attack1"); + when(assignment.getHints()).thenReturn(Lists.newArrayList("hint 1", "hint 2")); + when(lesson.getAssignments()).thenReturn(Lists.newArrayList(assignment)); + when(websession.getCurrentLesson()).thenReturn(lesson); + mockMvc + .perform(MockMvcRequestBuilders.get(URL_HINTS_MVC)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hint", CoreMatchers.is("hint 1"))) + .andExpect(jsonPath("$[0].assignmentPath", CoreMatchers.is("/HttpBasics/attack1"))); + } } diff --git a/src/test/java/org/owasp/webgoat/container/service/LessonMenuServiceTest.java b/src/test/java/org/owasp/webgoat/container/service/LessonMenuServiceTest.java index 5f7e1e751..388b3081e 100644 --- a/src/test/java/org/owasp/webgoat/container/service/LessonMenuServiceTest.java +++ b/src/test/java/org/owasp/webgoat/container/service/LessonMenuServiceTest.java @@ -21,7 +21,15 @@ */ package org.owasp.webgoat.container.service; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.owasp.webgoat.container.service.LessonMenuService.URL_LESSONMENU_MVC; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import com.beust.jcommander.internal.Lists; +import java.util.Arrays; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -39,66 +47,63 @@ import org.owasp.webgoat.container.users.UserTrackerRepository; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import java.util.Arrays; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -import static org.owasp.webgoat.container.service.LessonMenuService.URL_LESSONMENU_MVC; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - @ExtendWith(MockitoExtension.class) public class LessonMenuServiceTest { - @Mock(lenient=true) - private LessonTracker lessonTracker; - @Mock - private Course course; - @Mock - private UserTracker userTracker; - @Mock - private UserTrackerRepository userTrackerRepository; - @Mock - private WebSession webSession; - private MockMvc mockMvc; + @Mock(lenient = true) + private LessonTracker lessonTracker; - @BeforeEach - void setup() { - this.mockMvc = standaloneSetup(new LessonMenuService(course, webSession, userTrackerRepository, Arrays.asList("none"), Arrays.asList("none"))).build(); - } + @Mock private Course course; + @Mock private UserTracker userTracker; + @Mock private UserTrackerRepository userTrackerRepository; + @Mock private WebSession webSession; + private MockMvc mockMvc; - @Test - void lessonsShouldBeOrdered() throws Exception { - Lesson l1 = Mockito.mock(Lesson.class); - Lesson l2 = Mockito.mock(Lesson.class); - when(l1.getTitle()).thenReturn("ZA"); - when(l2.getTitle()).thenReturn("AA"); - when(lessonTracker.isLessonSolved()).thenReturn(false); - when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2)); - when(course.getCategories()).thenReturn(Lists.newArrayList(Category.A1)); - when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); - when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); + @BeforeEach + void setup() { + this.mockMvc = + standaloneSetup( + new LessonMenuService( + course, + webSession, + userTrackerRepository, + Arrays.asList("none"), + Arrays.asList("none"))) + .build(); + } - mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].children[0].name", CoreMatchers.is("AA"))) - .andExpect(jsonPath("$[0].children[1].name", CoreMatchers.is("ZA"))); - } + @Test + void lessonsShouldBeOrdered() throws Exception { + Lesson l1 = Mockito.mock(Lesson.class); + Lesson l2 = Mockito.mock(Lesson.class); + when(l1.getTitle()).thenReturn("ZA"); + when(l2.getTitle()).thenReturn("AA"); + when(lessonTracker.isLessonSolved()).thenReturn(false); + when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1, l2)); + when(course.getCategories()).thenReturn(Lists.newArrayList(Category.A1)); + when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); + when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); - @Test - void lessonCompleted() throws Exception { - Lesson l1 = Mockito.mock(Lesson.class); - when(l1.getTitle()).thenReturn("ZA"); - when(lessonTracker.isLessonSolved()).thenReturn(true); - when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1)); - when(course.getCategories()).thenReturn(Lists.newArrayList(Category.A1)); - when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); - when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); + mockMvc + .perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].children[0].name", CoreMatchers.is("AA"))) + .andExpect(jsonPath("$[0].children[1].name", CoreMatchers.is("ZA"))); + } - mockMvc.perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC)) - .andExpect(status().isOk())//.andDo(print()) - .andExpect(jsonPath("$[0].children[0].complete", CoreMatchers.is(true))); - } + @Test + void lessonCompleted() throws Exception { + Lesson l1 = Mockito.mock(Lesson.class); + when(l1.getTitle()).thenReturn("ZA"); + when(lessonTracker.isLessonSolved()).thenReturn(true); + when(course.getLessons(any())).thenReturn(Lists.newArrayList(l1)); + when(course.getCategories()).thenReturn(Lists.newArrayList(Category.A1)); + when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); + when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); + + mockMvc + .perform(MockMvcRequestBuilders.get(URL_LESSONMENU_MVC)) + .andExpect(status().isOk()) // .andDo(print()) + .andExpect(jsonPath("$[0].children[0].complete", CoreMatchers.is(true))); + } } diff --git a/src/test/java/org/owasp/webgoat/container/service/LessonProgressServiceTest.java b/src/test/java/org/owasp/webgoat/container/service/LessonProgressServiceTest.java index 3672e733f..25043330a 100644 --- a/src/test/java/org/owasp/webgoat/container/service/LessonProgressServiceTest.java +++ b/src/test/java/org/owasp/webgoat/container/service/LessonProgressServiceTest.java @@ -1,13 +1,20 @@ package org.owasp.webgoat.container.service; +import static org.hamcrest.CoreMatchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.List; import org.assertj.core.util.Maps; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.owasp.webgoat.container.lessons.Lesson; import org.owasp.webgoat.container.lessons.Assignment; +import org.owasp.webgoat.container.lessons.Lesson; import org.owasp.webgoat.container.session.WebSession; import org.owasp.webgoat.container.users.LessonTracker; import org.owasp.webgoat.container.users.UserTracker; @@ -17,37 +24,30 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import java.util.List; - -import static org.hamcrest.CoreMatchers.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author nbaars @@ -57,35 +57,35 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @ExtendWith(MockitoExtension.class) class LessonProgressServiceTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - @Mock - private Lesson lesson; - @Mock - private UserTracker userTracker; - @Mock - private LessonTracker lessonTracker; - @Mock - private UserTrackerRepository userTrackerRepository; - @Mock - private WebSession websession; + @Mock private Lesson lesson; + @Mock private UserTracker userTracker; + @Mock private LessonTracker lessonTracker; + @Mock private UserTrackerRepository userTrackerRepository; + @Mock private WebSession websession; - @BeforeEach - void setup() { - Assignment assignment = new Assignment("test", "test", List.of()); - when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); - when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); - when(websession.getCurrentLesson()).thenReturn(lesson); - when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true)); - this.mockMvc = MockMvcBuilders.standaloneSetup(new LessonProgressService(userTrackerRepository, websession)).build(); - } - - @Test - void jsonLessonOverview() throws Exception { - this.mockMvc.perform(MockMvcRequestBuilders.get("/service/lessonoverview.mvc").accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].assignment.name", is("test"))) - .andExpect(jsonPath("$[0].solved", is(true))); - } + @BeforeEach + void setup() { + Assignment assignment = new Assignment("test", "test", List.of()); + when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); + when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); + when(websession.getCurrentLesson()).thenReturn(lesson); + when(lessonTracker.getLessonOverview()).thenReturn(Maps.newHashMap(assignment, true)); + this.mockMvc = + MockMvcBuilders.standaloneSetup( + new LessonProgressService(userTrackerRepository, websession)) + .build(); + } + @Test + void jsonLessonOverview() throws Exception { + this.mockMvc + .perform( + MockMvcRequestBuilders.get("/service/lessonoverview.mvc") + .accept(MediaType.APPLICATION_JSON_VALUE)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].assignment.name", is("test"))) + .andExpect(jsonPath("$[0].solved", is(true))); + } } diff --git a/src/test/java/org/owasp/webgoat/container/service/ReportCardServiceTest.java b/src/test/java/org/owasp/webgoat/container/service/ReportCardServiceTest.java index 86c0b57f0..3df0efb76 100644 --- a/src/test/java/org/owasp/webgoat/container/service/ReportCardServiceTest.java +++ b/src/test/java/org/owasp/webgoat/container/service/ReportCardServiceTest.java @@ -1,5 +1,14 @@ package org.owasp.webgoat.container.service; +import static org.hamcrest.CoreMatchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -16,57 +25,44 @@ import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import java.util.List; - -import static org.hamcrest.CoreMatchers.is; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - @ExtendWith(MockitoExtension.class) public class ReportCardServiceTest { - private MockMvc mockMvc; - @Mock - private Course course; - @Mock - private UserTracker userTracker; - @Mock - private Lesson lesson; - @Mock - private LessonTracker lessonTracker; - @Mock - private UserTrackerRepository userTrackerRepository; - @Mock - private WebSession websession; - @Mock - private PluginMessages pluginMessages; + private MockMvc mockMvc; + @Mock private Course course; + @Mock private UserTracker userTracker; + @Mock private Lesson lesson; + @Mock private LessonTracker lessonTracker; + @Mock private UserTrackerRepository userTrackerRepository; + @Mock private WebSession websession; + @Mock private PluginMessages pluginMessages; - @BeforeEach - void setup() { - this.mockMvc = standaloneSetup(new ReportCardService(websession, userTrackerRepository, course, pluginMessages)).build(); - when(pluginMessages.getMessage(anyString())).thenReturn("Test"); - } + @BeforeEach + void setup() { + this.mockMvc = + standaloneSetup( + new ReportCardService(websession, userTrackerRepository, course, pluginMessages)) + .build(); + when(pluginMessages.getMessage(anyString())).thenReturn("Test"); + } - @Test - @WithMockUser(username = "guest", password = "guest") - void withLessons() throws Exception { - when(lesson.getTitle()).thenReturn("Test"); - when(course.getTotalOfLessons()).thenReturn(1); - when(course.getTotalOfAssignments()).thenReturn(10); - when(course.getLessons()).thenAnswer(x -> List.of(lesson)); - when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); - when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); - mockMvc.perform(MockMvcRequestBuilders.get("/service/reportcard.mvc")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.totalNumberOfLessons", is(1))) - .andExpect(jsonPath("$.solvedLessons", is(0))) - .andExpect(jsonPath("$.numberOfAssignmentsSolved", is(0))) - .andExpect(jsonPath("$.totalNumberOfAssignments", is(10))) - .andExpect(jsonPath("$.lessonStatistics[0].name", is("Test"))) - .andExpect(jsonPath("$.numberOfAssignmentsSolved", is(0))); - } + @Test + @WithMockUser(username = "guest", password = "guest") + void withLessons() throws Exception { + when(lesson.getTitle()).thenReturn("Test"); + when(course.getTotalOfLessons()).thenReturn(1); + when(course.getTotalOfAssignments()).thenReturn(10); + when(course.getLessons()).thenAnswer(x -> List.of(lesson)); + when(userTrackerRepository.findByUser(any())).thenReturn(userTracker); + when(userTracker.getLessonTracker(any(Lesson.class))).thenReturn(lessonTracker); + mockMvc + .perform(MockMvcRequestBuilders.get("/service/reportcard.mvc")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.totalNumberOfLessons", is(1))) + .andExpect(jsonPath("$.solvedLessons", is(0))) + .andExpect(jsonPath("$.numberOfAssignmentsSolved", is(0))) + .andExpect(jsonPath("$.totalNumberOfAssignments", is(10))) + .andExpect(jsonPath("$.lessonStatistics[0].name", is("Test"))) + .andExpect(jsonPath("$.numberOfAssignmentsSolved", is(0))); + } } diff --git a/src/test/java/org/owasp/webgoat/container/session/LabelDebuggerTest.java b/src/test/java/org/owasp/webgoat/container/session/LabelDebuggerTest.java index 593e6d88d..8d2d02de5 100644 --- a/src/test/java/org/owasp/webgoat/container/session/LabelDebuggerTest.java +++ b/src/test/java/org/owasp/webgoat/container/session/LabelDebuggerTest.java @@ -5,41 +5,38 @@ import org.junit.jupiter.api.Test; class LabelDebuggerTest { - @Test - void testSetEnabledTrue() { - LabelDebugger ld = new LabelDebugger(); - ld.setEnabled(true); - Assertions.assertThat(ld.isEnabled()).isTrue(); - } + @Test + void testSetEnabledTrue() { + LabelDebugger ld = new LabelDebugger(); + ld.setEnabled(true); + Assertions.assertThat(ld.isEnabled()).isTrue(); + } - @Test - void testSetEnabledFalse() { - LabelDebugger ld = new LabelDebugger(); - ld.setEnabled(false); - Assertions.assertThat((ld.isEnabled())).isFalse(); - } - - @Test - void testSetEnabledNullThrowsException() { - LabelDebugger ld = new LabelDebugger(); - ld.setEnabled(true); - Assertions.assertThat((ld.isEnabled())).isTrue(); - } - - @Test - void testEnableIsTrue() { - LabelDebugger ld = new LabelDebugger(); - ld.enable(); - Assertions.assertThat((ld.isEnabled())).isTrue(); - } - - @Test - void testDisableIsFalse() { - LabelDebugger ld = new LabelDebugger(); - ld.disable(); - Assertions.assertThat((ld.isEnabled())).isFalse(); - } + @Test + void testSetEnabledFalse() { + LabelDebugger ld = new LabelDebugger(); + ld.setEnabled(false); + Assertions.assertThat((ld.isEnabled())).isFalse(); + } + @Test + void testSetEnabledNullThrowsException() { + LabelDebugger ld = new LabelDebugger(); + ld.setEnabled(true); + Assertions.assertThat((ld.isEnabled())).isTrue(); + } + @Test + void testEnableIsTrue() { + LabelDebugger ld = new LabelDebugger(); + ld.enable(); + Assertions.assertThat((ld.isEnabled())).isTrue(); + } + @Test + void testDisableIsFalse() { + LabelDebugger ld = new LabelDebugger(); + ld.disable(); + Assertions.assertThat((ld.isEnabled())).isFalse(); + } } diff --git a/src/test/java/org/owasp/webgoat/container/session/LessonTrackerTest.java b/src/test/java/org/owasp/webgoat/container/session/LessonTrackerTest.java index b02ba2e72..033b136e8 100644 --- a/src/test/java/org/owasp/webgoat/container/session/LessonTrackerTest.java +++ b/src/test/java/org/owasp/webgoat/container/session/LessonTrackerTest.java @@ -1,41 +1,41 @@ package org.owasp.webgoat.container.session; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Map; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.owasp.webgoat.container.lessons.Assignment; import org.owasp.webgoat.container.lessons.Lesson; import org.owasp.webgoat.container.users.LessonTracker; -import java.util.List; -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - /** * ************************************************************************************************ * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 2014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the + * + *

Copyright (c) 2002 - 2014 Bruce Mayhew + * + *

This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if + * + *

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + *

You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. + * + *

Getting Source ============== + * + *

Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + * *

* * @author nbaars @@ -44,43 +44,42 @@ import static org.mockito.Mockito.when; */ class LessonTrackerTest { - @Test - void allAssignmentsSolvedShouldMarkLessonAsComplete() { - Lesson lesson = mock(Lesson.class); - when(lesson.getAssignments()).thenReturn(List.of(new Assignment("assignment", "assignment", List.of("")))); - LessonTracker lessonTracker = new LessonTracker(lesson); - lessonTracker.assignmentSolved("assignment"); + @Test + void allAssignmentsSolvedShouldMarkLessonAsComplete() { + Lesson lesson = mock(Lesson.class); + when(lesson.getAssignments()) + .thenReturn(List.of(new Assignment("assignment", "assignment", List.of("")))); + LessonTracker lessonTracker = new LessonTracker(lesson); + lessonTracker.assignmentSolved("assignment"); - Assertions.assertThat(lessonTracker.isLessonSolved()).isTrue(); - } + Assertions.assertThat(lessonTracker.isLessonSolved()).isTrue(); + } - @Test - void noAssignmentsSolvedShouldMarkLessonAsInComplete() { - Lesson lesson = mock(Lesson.class); - Assignment a1 = new Assignment("a1"); - Assignment a2 = new Assignment("a2"); - List assignments = List.of(a1, a2); - when(lesson.getAssignments()).thenReturn(assignments); - LessonTracker lessonTracker = new LessonTracker(lesson); - lessonTracker.assignmentSolved("a1"); + @Test + void noAssignmentsSolvedShouldMarkLessonAsInComplete() { + Lesson lesson = mock(Lesson.class); + Assignment a1 = new Assignment("a1"); + Assignment a2 = new Assignment("a2"); + List assignments = List.of(a1, a2); + when(lesson.getAssignments()).thenReturn(assignments); + LessonTracker lessonTracker = new LessonTracker(lesson); + lessonTracker.assignmentSolved("a1"); - Map lessonOverview = lessonTracker.getLessonOverview(); - assertThat(lessonOverview.get(a1)).isTrue(); - assertThat(lessonOverview.get(a2)).isFalse(); - } - - @Test - void solvingSameAssignmentShouldNotAddItTwice() { - Lesson lesson = mock(Lesson.class); - Assignment a1 = new Assignment("a1"); - List assignments = List.of(a1); - when(lesson.getAssignments()).thenReturn(assignments); - LessonTracker lessonTracker = new LessonTracker(lesson); - lessonTracker.assignmentSolved("a1"); - lessonTracker.assignmentSolved("a1"); - - assertThat(lessonTracker.getLessonOverview().size()).isEqualTo(1); - } + Map lessonOverview = lessonTracker.getLessonOverview(); + assertThat(lessonOverview.get(a1)).isTrue(); + assertThat(lessonOverview.get(a2)).isFalse(); + } + @Test + void solvingSameAssignmentShouldNotAddItTwice() { + Lesson lesson = mock(Lesson.class); + Assignment a1 = new Assignment("a1"); + List assignments = List.of(a1); + when(lesson.getAssignments()).thenReturn(assignments); + LessonTracker lessonTracker = new LessonTracker(lesson); + lessonTracker.assignmentSolved("a1"); + lessonTracker.assignmentSolved("a1"); + assertThat(lessonTracker.getLessonOverview().size()).isEqualTo(1); + } } diff --git a/src/test/java/org/owasp/webgoat/container/users/UserRepositoryTest.java b/src/test/java/org/owasp/webgoat/container/users/UserRepositoryTest.java index 3025c243d..e8ef4b8ab 100644 --- a/src/test/java/org/owasp/webgoat/container/users/UserRepositoryTest.java +++ b/src/test/java/org/owasp/webgoat/container/users/UserRepositoryTest.java @@ -2,27 +2,24 @@ package org.owasp.webgoat.container.users; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import org.owasp.webgoat.container.WebGoat; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; @DataJpaTest @ActiveProfiles("webgoat-test") class UserRepositoryTest { - @Autowired - private UserRepository userRepository; + @Autowired private UserRepository userRepository; - @Test - void userShouldBeSaved() { - WebGoatUser user = new WebGoatUser("test", "password"); - userRepository.saveAndFlush(user); + @Test + void userShouldBeSaved() { + WebGoatUser user = new WebGoatUser("test", "password"); + userRepository.saveAndFlush(user); - user = userRepository.findByUsername("test"); + user = userRepository.findByUsername("test"); - Assertions.assertThat(user.getUsername()).isEqualTo("test"); - Assertions.assertThat(user.getPassword()).isEqualTo("password"); - } + Assertions.assertThat(user.getUsername()).isEqualTo("test"); + Assertions.assertThat(user.getPassword()).isEqualTo("password"); + } } diff --git a/src/test/java/org/owasp/webgoat/container/users/UserServiceTest.java b/src/test/java/org/owasp/webgoat/container/users/UserServiceTest.java index 29a8ed5f5..1bcef2496 100644 --- a/src/test/java/org/owasp/webgoat/container/users/UserServiceTest.java +++ b/src/test/java/org/owasp/webgoat/container/users/UserServiceTest.java @@ -1,37 +1,34 @@ package org.owasp.webgoat.container.users; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.function.Function; import org.assertj.core.api.Assertions; import org.flywaydb.core.Flyway; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.owasp.webgoat.container.lessons.Initializeable; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import java.util.List; -import java.util.function.Function; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class UserServiceTest { - @Mock - private UserRepository userRepository; - @Mock - private UserTrackerRepository userTrackerRepository; - @Mock - private JdbcTemplate jdbcTemplate; - @Mock - private Function flywayLessons; + @Mock private UserRepository userRepository; + @Mock private UserTrackerRepository userTrackerRepository; + @Mock private JdbcTemplate jdbcTemplate; + @Mock private Function flywayLessons; - @Test - void shouldThrowExceptionWhenUserIsNotFound() { - when(userRepository.findByUsername(any())).thenReturn(null); - UserService userService = new UserService(userRepository, userTrackerRepository, jdbcTemplate, flywayLessons, List.of()); - Assertions.assertThatThrownBy(() -> userService.loadUserByUsername("unknown")).isInstanceOf(UsernameNotFoundException.class); - } + @Test + void shouldThrowExceptionWhenUserIsNotFound() { + when(userRepository.findByUsername(any())).thenReturn(null); + UserService userService = + new UserService( + userRepository, userTrackerRepository, jdbcTemplate, flywayLessons, List.of()); + Assertions.assertThatThrownBy(() -> userService.loadUserByUsername("unknown")) + .isInstanceOf(UsernameNotFoundException.class); + } } diff --git a/src/test/java/org/owasp/webgoat/container/users/UserTrackerRepositoryTest.java b/src/test/java/org/owasp/webgoat/container/users/UserTrackerRepositoryTest.java index 9caa0ab2b..fd341a865 100644 --- a/src/test/java/org/owasp/webgoat/container/users/UserTrackerRepositoryTest.java +++ b/src/test/java/org/owasp/webgoat/container/users/UserTrackerRepositoryTest.java @@ -1,5 +1,6 @@ package org.owasp.webgoat.container.users; +import java.util.List; import org.assertj.core.api.Assertions; import org.assertj.core.util.Lists; import org.junit.jupiter.api.Test; @@ -10,74 +11,70 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.test.context.ActiveProfiles; -import java.util.List; - @DataJpaTest @ActiveProfiles("webgoat-test") class UserTrackerRepositoryTest { - private class TestLesson extends Lesson { + private class TestLesson extends Lesson { - @Override - public Category getDefaultCategory() { - return Category.CLIENT_SIDE; - } - - @Override - public String getTitle() { - return "test"; - } - - @Override - public List getAssignments() { - Assignment assignment = new Assignment("test", "test", Lists.newArrayList()); - return Lists.newArrayList(assignment); - } + @Override + public Category getDefaultCategory() { + return Category.CLIENT_SIDE; } - @Autowired - private UserTrackerRepository userTrackerRepository; - - @Test - void saveUserTracker() { - UserTracker userTracker = new UserTracker("test"); - - userTrackerRepository.save(userTracker); - - userTracker = userTrackerRepository.findByUser("test"); - Assertions.assertThat(userTracker.getLessonTracker("test")).isNotNull(); + @Override + public String getTitle() { + return "test"; } - @Test - void solvedAssignmentsShouldBeSaved() { - UserTracker userTracker = new UserTracker("test"); - TestLesson lesson = new TestLesson(); - userTracker.getLessonTracker(lesson); - userTracker.assignmentFailed(lesson); - userTracker.assignmentFailed(lesson); - userTracker.assignmentSolved(lesson, "test"); - - userTrackerRepository.saveAndFlush(userTracker); - - userTracker = userTrackerRepository.findByUser("test"); - Assertions.assertThat(userTracker.numberOfAssignmentsSolved()).isEqualTo(1); + @Override + public List getAssignments() { + Assignment assignment = new Assignment("test", "test", Lists.newArrayList()); + return Lists.newArrayList(assignment); } + } - @Test - void saveAndLoadShouldHaveCorrectNumberOfAttempts() { - UserTracker userTracker = new UserTracker("test"); - TestLesson lesson = new TestLesson(); - userTracker.getLessonTracker(lesson); - userTracker.assignmentFailed(lesson); - userTracker.assignmentFailed(lesson); - userTrackerRepository.saveAndFlush(userTracker); + @Autowired private UserTrackerRepository userTrackerRepository; - userTracker = userTrackerRepository.findByUser("test"); - userTracker.assignmentFailed(lesson); - userTracker.assignmentFailed(lesson); - userTrackerRepository.saveAndFlush(userTracker); + @Test + void saveUserTracker() { + UserTracker userTracker = new UserTracker("test"); - Assertions.assertThat(userTracker.getLessonTracker(lesson).getNumberOfAttempts()).isEqualTo(4); - } + userTrackerRepository.save(userTracker); + userTracker = userTrackerRepository.findByUser("test"); + Assertions.assertThat(userTracker.getLessonTracker("test")).isNotNull(); + } + + @Test + void solvedAssignmentsShouldBeSaved() { + UserTracker userTracker = new UserTracker("test"); + TestLesson lesson = new TestLesson(); + userTracker.getLessonTracker(lesson); + userTracker.assignmentFailed(lesson); + userTracker.assignmentFailed(lesson); + userTracker.assignmentSolved(lesson, "test"); + + userTrackerRepository.saveAndFlush(userTracker); + + userTracker = userTrackerRepository.findByUser("test"); + Assertions.assertThat(userTracker.numberOfAssignmentsSolved()).isEqualTo(1); + } + + @Test + void saveAndLoadShouldHaveCorrectNumberOfAttempts() { + UserTracker userTracker = new UserTracker("test"); + TestLesson lesson = new TestLesson(); + userTracker.getLessonTracker(lesson); + userTracker.assignmentFailed(lesson); + userTracker.assignmentFailed(lesson); + userTrackerRepository.saveAndFlush(userTracker); + + userTracker = userTrackerRepository.findByUser("test"); + userTracker.assignmentFailed(lesson); + userTracker.assignmentFailed(lesson); + userTrackerRepository.saveAndFlush(userTracker); + + Assertions.assertThat(userTracker.getLessonTracker(lesson).getNumberOfAttempts()).isEqualTo(4); + } } diff --git a/src/test/java/org/owasp/webgoat/container/users/UserValidatorTest.java b/src/test/java/org/owasp/webgoat/container/users/UserValidatorTest.java index e9c3c94e5..ec5957fa0 100644 --- a/src/test/java/org/owasp/webgoat/container/users/UserValidatorTest.java +++ b/src/test/java/org/owasp/webgoat/container/users/UserValidatorTest.java @@ -1,5 +1,9 @@ package org.owasp.webgoat.container.users; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -8,53 +12,48 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.Errors; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class UserValidatorTest { - @Mock - private UserRepository userRepository; + @Mock private UserRepository userRepository; - @Test - void passwordsShouldMatch() { - UserForm userForm = new UserForm(); - userForm.setAgree("true"); - userForm.setUsername("test1234"); - userForm.setPassword("test1234"); - userForm.setMatchingPassword("test1234"); - Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); - new UserValidator(userRepository).validate(userForm, errors); - Assertions.assertThat(errors.hasErrors()).isFalse(); - } + @Test + void passwordsShouldMatch() { + UserForm userForm = new UserForm(); + userForm.setAgree("true"); + userForm.setUsername("test1234"); + userForm.setPassword("test1234"); + userForm.setMatchingPassword("test1234"); + Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); + new UserValidator(userRepository).validate(userForm, errors); + Assertions.assertThat(errors.hasErrors()).isFalse(); + } - @Test - void shouldGiveErrorWhenPasswordsDoNotMatch() { - UserForm userForm = new UserForm(); - userForm.setAgree("true"); - userForm.setUsername("test1234"); - userForm.setPassword("test12345"); - userForm.setMatchingPassword("test1234"); - Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); - new UserValidator(userRepository).validate(userForm, errors); - Assertions.assertThat(errors.hasErrors()).isTrue(); - assertThat(errors.getFieldError("matchingPassword").getCode()).isEqualTo("password.diff"); - } - - @Test - void shouldGiveErrorWhenUserAlreadyExists() { - UserForm userForm = new UserForm(); - userForm.setAgree("true"); - userForm.setUsername("test12345"); - userForm.setPassword("test12345"); - userForm.setMatchingPassword("test12345"); - when(userRepository.findByUsername(anyString())).thenReturn(new WebGoatUser("test1245", "password")); - Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); - new UserValidator(userRepository).validate(userForm, errors); - Assertions.assertThat(errors.hasErrors()).isTrue(); - assertThat(errors.getFieldError("username").getCode()).isEqualTo("username.duplicate"); - } + @Test + void shouldGiveErrorWhenPasswordsDoNotMatch() { + UserForm userForm = new UserForm(); + userForm.setAgree("true"); + userForm.setUsername("test1234"); + userForm.setPassword("test12345"); + userForm.setMatchingPassword("test1234"); + Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); + new UserValidator(userRepository).validate(userForm, errors); + Assertions.assertThat(errors.hasErrors()).isTrue(); + assertThat(errors.getFieldError("matchingPassword").getCode()).isEqualTo("password.diff"); + } + @Test + void shouldGiveErrorWhenUserAlreadyExists() { + UserForm userForm = new UserForm(); + userForm.setAgree("true"); + userForm.setUsername("test12345"); + userForm.setPassword("test12345"); + userForm.setMatchingPassword("test12345"); + when(userRepository.findByUsername(anyString())) + .thenReturn(new WebGoatUser("test1245", "password")); + Errors errors = new BeanPropertyBindingResult(userForm, "userForm"); + new UserValidator(userRepository).validate(userForm, errors); + Assertions.assertThat(errors.hasErrors()).isTrue(); + assertThat(errors.getFieldError("username").getCode()).isEqualTo("username.duplicate"); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/authbypass/BypassVerificationTest.java b/src/test/java/org/owasp/webgoat/lessons/authbypass/BypassVerificationTest.java index 03d1be62f..7e3ba3961 100644 --- a/src/test/java/org/owasp/webgoat/lessons/authbypass/BypassVerificationTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/authbypass/BypassVerificationTest.java @@ -25,54 +25,57 @@ package org.owasp.webgoat.lessons.authbypass; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.owasp.webgoat.container.assignments.AssignmentEndpointTest; -import org.owasp.webgoat.lessons.authbypass.VerifyAccount; import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - @ExtendWith(MockitoExtension.class) public class BypassVerificationTest extends AssignmentEndpointTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - @BeforeEach - public void setup() { - VerifyAccount verifyAccount = new VerifyAccount(); - init(verifyAccount); - this.mockMvc = standaloneSetup(verifyAccount).build(); - } + @BeforeEach + public void setup() { + VerifyAccount verifyAccount = new VerifyAccount(); + init(verifyAccount); + this.mockMvc = standaloneSetup(verifyAccount).build(); + } - @Test - public void placeHolder() { - assert (true); - } + @Test + public void placeHolder() { + assert (true); + } -//TODO: Finish tests below ... getting null on injected/mocked userSession for some reason (in AssignmentEndpoint:58 even though it it mocked via AssignmentEncpointTest and works in other tests) -// @Test -// public void testCheatingDetection() throws Exception { -// ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/auth-bypass/verify-account") -// .param("secQuestion0","Dr. Watson") -// .param("secQuestion1","Baker Street") -// .param("verifyMethod","SEC_QUESTIONS") -// .param("userId","1223445")); -// -// results.andExpect(status().isOk()) -// .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("verify-account.cheated")))); -// } + // TODO: Finish tests below ... getting null on injected/mocked userSession for some reason (in + // AssignmentEndpoint:58 even though it it mocked via AssignmentEncpointTest and works in other + // tests) + // @Test + // public void testCheatingDetection() throws Exception { + // ResultActions results = + // mockMvc.perform(MockMvcRequestBuilders.post("/auth-bypass/verify-account") + // .param("secQuestion0","Dr. Watson") + // .param("secQuestion1","Baker Street") + // .param("verifyMethod","SEC_QUESTIONS") + // .param("userId","1223445")); + // + // results.andExpect(status().isOk()) + // .andExpect(jsonPath("$.feedback", + // CoreMatchers.is(messages.getMessage("verify-account.cheated")))); + // } -// @Test -// public void success() { -// -// } + // @Test + // public void success() { + // + // } -// @Test -// public void failure() { -// -// } + // @Test + // public void failure() { + // + // } } diff --git a/src/test/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFrontendValidationTest.java b/src/test/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFrontendValidationTest.java index a8e5a513a..d48df1629 100644 --- a/src/test/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFrontendValidationTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/bypassrestrictions/BypassRestrictionsFrontendValidationTest.java @@ -1,32 +1,33 @@ package org.owasp.webgoat.lessons.bypassrestrictions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.bypassrestrictions.BypassRestrictions; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + /** * @author nbaars * @since 6/16/17. */ public class BypassRestrictionsFrontendValidationTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new BypassRestrictions()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new BypassRestrictions()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - void noChangesShouldNotPassTheLesson() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation") + @Test + void noChangesShouldNotPassTheLesson() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation") .param("field1", "abc") .param("field2", "123") .param("field3", "abc ABC 123") @@ -35,12 +36,15 @@ public class BypassRestrictionsFrontendValidationTest extends LessonTest { .param("field6", "90201 1111") .param("field7", "301-604-4882") .param("error", "2")) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } - @Test - void bypassAllFieldShouldPass() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation") + @Test + void bypassAllFieldShouldPass() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation") .param("field1", "abcd") .param("field2", "1234") .param("field3", "abc $ABC 123") @@ -49,12 +53,15 @@ public class BypassRestrictionsFrontendValidationTest extends LessonTest { .param("field6", "90201 1111AA") .param("field7", "301-604-4882$$") .param("error", "0")) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - void notBypassingAllFieldShouldNotPass() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation") + @Test + void notBypassingAllFieldShouldNotPass() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation") .param("field1", "abc") .param("field2", "1234") .param("field3", "abc $ABC 123") @@ -63,8 +70,7 @@ public class BypassRestrictionsFrontendValidationTest extends LessonTest { .param("field6", "90201 1111AA") .param("field7", "301-604-4882AA") .param("error", "0")) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); - } - - + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/challenges/Assignment1Test.java b/src/test/java/org/owasp/webgoat/lessons/challenges/Assignment1Test.java index c52429491..3628cb904 100644 --- a/src/test/java/org/owasp/webgoat/lessons/challenges/Assignment1Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/challenges/Assignment1Test.java @@ -22,24 +22,21 @@ package org.owasp.webgoat.lessons.challenges; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + +import java.net.InetAddress; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.owasp.webgoat.container.assignments.AssignmentEndpointTest; -import org.owasp.webgoat.lessons.challenges.Flag; -import org.owasp.webgoat.lessons.challenges.SolutionConstants; import org.owasp.webgoat.lessons.challenges.challenge1.Assignment1; import org.owasp.webgoat.lessons.challenges.challenge1.ImageServlet; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import java.net.InetAddress; - -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - /** * @author nbaars * @since 5/2/17. @@ -47,54 +44,65 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal @ExtendWith(MockitoExtension.class) class Assignment1Test extends AssignmentEndpointTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - @BeforeEach - void setup() { - Assignment1 assignment1 = new Assignment1(); - init(assignment1); - new Flag().initFlags(); - this.mockMvc = standaloneSetup(assignment1).build(); - } + @BeforeEach + void setup() { + Assignment1 assignment1 = new Assignment1(); + init(assignment1); + new Flag().initFlags(); + this.mockMvc = standaloneSetup(assignment1).build(); + } - @Test - void success() throws Exception { - InetAddress addr = InetAddress.getLocalHost(); - String host = addr.getHostAddress(); - mockMvc.perform(MockMvcRequestBuilders.post("/challenge/1") + @Test + void success() throws Exception { + InetAddress addr = InetAddress.getLocalHost(); + String host = addr.getHostAddress(); + mockMvc + .perform( + MockMvcRequestBuilders.post("/challenge/1") .header("X-Forwarded-For", host) .param("username", "admin") - .param("password", SolutionConstants.PASSWORD.replace("1234", String.format("%04d",ImageServlet.PINCODE)))) - .andExpect(jsonPath("$.feedback", CoreMatchers.containsString("flag: " + Flag.FLAGS.get(1)))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .param( + "password", + SolutionConstants.PASSWORD.replace( + "1234", String.format("%04d", ImageServlet.PINCODE)))) + .andExpect( + jsonPath("$.feedback", CoreMatchers.containsString("flag: " + Flag.FLAGS.get(1)))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - void wrongPassword() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/challenge/1") + @Test + void wrongPassword() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/challenge/1") .param("username", "admin") .param("password", "wrong")) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect( + jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } -// @Test -// public void correctPasswordXForwardHeaderMissing() throws Exception { -// mockMvc.perform(MockMvcRequestBuilders.post("/challenge/1") -// .param("username", "admin") -// .param("password", SolutionConstants.PASSWORD)) -// .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("ip.address.unknown")))) -// .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); -// } + // @Test + // public void correctPasswordXForwardHeaderMissing() throws Exception { + // mockMvc.perform(MockMvcRequestBuilders.post("/challenge/1") + // .param("username", "admin") + // .param("password", SolutionConstants.PASSWORD)) + // .andExpect(jsonPath("$.feedback", + // CoreMatchers.is(messages.getMessage("ip.address.unknown")))) + // .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + // } -// @Test -// public void correctPasswordXForwardHeaderWrong() throws Exception { -// mockMvc.perform(MockMvcRequestBuilders.post("/challenge/1") -// .header("X-Forwarded-For", "127.0.1.2") -// .param("username", "admin") -// .param("password", SolutionConstants.PASSWORD)) -// .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("ip.address.unknown")))) -// .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); -// } + // @Test + // public void correctPasswordXForwardHeaderWrong() throws Exception { + // mockMvc.perform(MockMvcRequestBuilders.post("/challenge/1") + // .header("X-Forwarded-For", "127.0.1.2") + // .param("username", "admin") + // .param("password", SolutionConstants.PASSWORD)) + // .andExpect(jsonPath("$.feedback", + // CoreMatchers.is(messages.getMessage("ip.address.unknown")))) + // .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + // } } diff --git a/src/test/java/org/owasp/webgoat/lessons/chromedevtools/ChromeDevToolsTest.java b/src/test/java/org/owasp/webgoat/lessons/chromedevtools/ChromeDevToolsTest.java index cf15eb3d4..de4d93dd1 100644 --- a/src/test/java/org/owasp/webgoat/lessons/chromedevtools/ChromeDevToolsTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/chromedevtools/ChromeDevToolsTest.java @@ -1,20 +1,18 @@ package org.owasp.webgoat.lessons.chromedevtools; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.chromedevtools.ChromeDevTools; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - /** * @author Benedikt Stuhrmann * @since 13/03/19. @@ -22,28 +20,31 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @ExtendWith(SpringExtension.class) public class ChromeDevToolsTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new ChromeDevTools()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new ChromeDevTools()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void NetworkAssignmentTest_Success() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/ChromeDevTools/network") + @Test + public void NetworkAssignmentTest_Success() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/ChromeDevTools/network") .param("network_num", "123456") .param("number", "123456")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", Matchers.is(true))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", Matchers.is(true))); + } - @Test - public void NetworkAssignmentTest_Fail() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/ChromeDevTools/network") + @Test + public void NetworkAssignmentTest_Fail() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/ChromeDevTools/network") .param("network_num", "123456") .param("number", "654321")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", Matchers.is(false))); - } - + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", Matchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/cia/CIAQuizTest.java b/src/test/java/org/owasp/webgoat/lessons/cia/CIAQuizTest.java index 9ea02808c..1cf114376 100644 --- a/src/test/java/org/owasp/webgoat/lessons/cia/CIAQuizTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/cia/CIAQuizTest.java @@ -1,5 +1,11 @@ package org.owasp.webgoat.lessons.cia; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.is; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.owasp.webgoat.container.plugins.LessonTest; @@ -7,190 +13,201 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.CoreMatchers.is; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; /** * @author Benedikt Stuhrmann * @since 13/03/19. */ public class CIAQuizTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new CIA()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new CIA()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void allAnswersCorrectIsSuccess() throws Exception { - String[] solution0 = {"Solution 3"}; - String[] solution1 = {"Solution 1"}; - String[] solution2 = {"Solution 4"}; - String[] solution3 = {"Solution 2"}; + @Test + public void allAnswersCorrectIsSuccess() throws Exception { + String[] solution0 = {"Solution 3"}; + String[] solution1 = {"Solution 1"}; + String[] solution2 = {"Solution 4"}; + String[] solution3 = {"Solution 2"}; - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") + mockMvc + .perform( + MockMvcRequestBuilders.post("/cia/quiz") .param("question_0_solution", solution0) .param("question_1_solution", solution1) .param("question_2_solution", solution2) .param("question_3_solution", solution3)) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))); - } + @Test + public void oneAnswerWrongIsFailure() throws Exception { + String[] solution0 = {"Solution 1"}; + String[] solution1 = {"Solution 1"}; + String[] solution2 = {"Solution 4"}; + String[] solution3 = {"Solution 2"}; - @Test - public void oneAnswerWrongIsFailure() throws Exception { - String[] solution0 = {"Solution 1"}; - String[] solution1 = {"Solution 1"}; - String[] solution2 = {"Solution 4"}; - String[] solution3 = {"Solution 2"}; - - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") + mockMvc + .perform( + MockMvcRequestBuilders.post("/cia/quiz") .param("question_0_solution", solution0) .param("question_1_solution", solution1) .param("question_2_solution", solution2) .param("question_3_solution", solution3)) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))); - } + @Test + public void twoAnswersWrongIsFailure() throws Exception { + String[] solution0 = {"Solution 1"}; + String[] solution1 = {"Solution 1"}; + String[] solution2 = {"Solution 4"}; + String[] solution3 = {"Solution 3"}; - @Test - public void twoAnswersWrongIsFailure() throws Exception { - String[] solution0 = {"Solution 1"}; - String[] solution1 = {"Solution 1"}; - String[] solution2 = {"Solution 4"}; - String[] solution3 = {"Solution 3"}; - - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") + mockMvc + .perform( + MockMvcRequestBuilders.post("/cia/quiz") .param("question_0_solution", solution0) .param("question_1_solution", solution1) .param("question_2_solution", solution2) .param("question_3_solution", solution3)) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))); - } + @Test + public void threeAnswersWrongIsFailure() throws Exception { + String[] solution0 = {"Solution 1"}; + String[] solution1 = {"Solution 1"}; + String[] solution2 = {"Solution 1"}; + String[] solution3 = {"Solution 3"}; - @Test - public void threeAnswersWrongIsFailure() throws Exception { - String[] solution0 = {"Solution 1"}; - String[] solution1 = {"Solution 1"}; - String[] solution2 = {"Solution 1"}; - String[] solution3 = {"Solution 3"}; - - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") + mockMvc + .perform( + MockMvcRequestBuilders.post("/cia/quiz") .param("question_0_solution", solution0) .param("question_1_solution", solution1) .param("question_2_solution", solution2) .param("question_3_solution", solution3)) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))); - } + @Test + public void allAnswersWrongIsFailure() throws Exception { + String[] solution0 = {"Solution 2"}; + String[] solution1 = {"Solution 1"}; + String[] solution2 = {"Solution 3"}; + String[] solution3 = {"Solution 1"}; - @Test - public void allAnswersWrongIsFailure() throws Exception { - String[] solution0 = {"Solution 2"}; - String[] solution1 = {"Solution 1"}; - String[] solution2 = {"Solution 3"}; - String[] solution3 = {"Solution 1"}; - - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") + mockMvc + .perform( + MockMvcRequestBuilders.post("/cia/quiz") .param("question_0_solution", solution0) .param("question_1_solution", solution1) .param("question_2_solution", solution2) .param("question_3_solution", solution3)) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))); - } + @Test + public void allAnswersCorrectGetResultsReturnsTrueTrueTrueTrue() throws Exception { + String[] solution0 = {"Solution 3"}; + String[] solution1 = {"Solution 1"}; + String[] solution2 = {"Solution 4"}; + String[] solution3 = {"Solution 2"}; - @Test - public void allAnswersCorrectGetResultsReturnsTrueTrueTrueTrue() throws Exception { - String[] solution0 = {"Solution 3"}; - String[] solution1 = {"Solution 1"}; - String[] solution2 = {"Solution 4"}; - String[] solution3 = {"Solution 2"}; + mockMvc.perform( + MockMvcRequestBuilders.post("/cia/quiz") + .param("question_0_solution", solution0) + .param("question_1_solution", solution1) + .param("question_2_solution", solution2) + .param("question_3_solution", solution3)); - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") - .param("question_0_solution", solution0) - .param("question_1_solution", solution1) - .param("question_2_solution", solution2) - .param("question_3_solution", solution3)); + MvcResult result = + mockMvc + .perform(MockMvcRequestBuilders.get("/cia/quiz")) + .andExpect(status().isOk()) + .andReturn(); - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/cia/quiz")) - .andExpect(status().isOk()) - .andReturn(); + String responseString = result.getResponse().getContentAsString(); + assertThat(responseString).isEqualTo("[ true, true, true, true ]"); + } - String responseString = result.getResponse().getContentAsString(); - assertThat(responseString).isEqualTo("[ true, true, true, true ]"); - } + @Test + public void firstAnswerFalseGetResultsReturnsFalseTrueTrueTrue() throws Exception { + String[] solution0 = {"Solution 2"}; + String[] solution1 = {"Solution 1"}; + String[] solution2 = {"Solution 4"}; + String[] solution3 = {"Solution 2"}; - @Test - public void firstAnswerFalseGetResultsReturnsFalseTrueTrueTrue() throws Exception { - String[] solution0 = {"Solution 2"}; - String[] solution1 = {"Solution 1"}; - String[] solution2 = {"Solution 4"}; - String[] solution3 = {"Solution 2"}; + mockMvc.perform( + MockMvcRequestBuilders.post("/cia/quiz") + .param("question_0_solution", solution0) + .param("question_1_solution", solution1) + .param("question_2_solution", solution2) + .param("question_3_solution", solution3)); - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") - .param("question_0_solution", solution0) - .param("question_1_solution", solution1) - .param("question_2_solution", solution2) - .param("question_3_solution", solution3)); + MvcResult result = + mockMvc + .perform(MockMvcRequestBuilders.get("/cia/quiz")) + .andExpect(status().isOk()) + .andReturn(); - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/cia/quiz")) - .andExpect(status().isOk()) - .andReturn(); + String responseString = result.getResponse().getContentAsString(); + assertThat(responseString).isEqualTo("[ false, true, true, true ]"); + } - String responseString = result.getResponse().getContentAsString(); - assertThat(responseString).isEqualTo("[ false, true, true, true ]"); - } + @Test + public void secondAnswerFalseGetResultsReturnsTrueFalseTrueTrue() throws Exception { + String[] solution0 = {"Solution 3"}; + String[] solution1 = {"Solution 2"}; + String[] solution2 = {"Solution 4"}; + String[] solution3 = {"Solution 2"}; - @Test - public void secondAnswerFalseGetResultsReturnsTrueFalseTrueTrue() throws Exception { - String[] solution0 = {"Solution 3"}; - String[] solution1 = {"Solution 2"}; - String[] solution2 = {"Solution 4"}; - String[] solution3 = {"Solution 2"}; + mockMvc.perform( + MockMvcRequestBuilders.post("/cia/quiz") + .param("question_0_solution", solution0) + .param("question_1_solution", solution1) + .param("question_2_solution", solution2) + .param("question_3_solution", solution3)); - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") - .param("question_0_solution", solution0) - .param("question_1_solution", solution1) - .param("question_2_solution", solution2) - .param("question_3_solution", solution3)); + MvcResult result = + mockMvc + .perform(MockMvcRequestBuilders.get("/cia/quiz")) + .andExpect(status().isOk()) + .andReturn(); - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/cia/quiz")) - .andExpect(status().isOk()) - .andReturn(); + String responseString = result.getResponse().getContentAsString(); + assertThat(responseString).isEqualTo("[ true, false, true, true ]"); + } - String responseString = result.getResponse().getContentAsString(); - assertThat(responseString).isEqualTo("[ true, false, true, true ]"); - } + @Test + public void allAnswersFalseGetResultsReturnsFalseFalseFalseFalse() throws Exception { + String[] solution0 = {"Solution 1"}; + String[] solution1 = {"Solution 2"}; + String[] solution2 = {"Solution 1"}; + String[] solution3 = {"Solution 1"}; - @Test - public void allAnswersFalseGetResultsReturnsFalseFalseFalseFalse() throws Exception { - String[] solution0 = {"Solution 1"}; - String[] solution1 = {"Solution 2"}; - String[] solution2 = {"Solution 1"}; - String[] solution3 = {"Solution 1"}; + mockMvc.perform( + MockMvcRequestBuilders.post("/cia/quiz") + .param("question_0_solution", solution0) + .param("question_1_solution", solution1) + .param("question_2_solution", solution2) + .param("question_3_solution", solution3)); - mockMvc.perform(MockMvcRequestBuilders.post("/cia/quiz") - .param("question_0_solution", solution0) - .param("question_1_solution", solution1) - .param("question_2_solution", solution2) - .param("question_3_solution", solution3)); - - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/cia/quiz")) - .andExpect(status().isOk()) - .andReturn(); - - String responseString = result.getResponse().getContentAsString(); - assertThat(responseString).isEqualTo("[ false, false, false, false ]"); - } + MvcResult result = + mockMvc + .perform(MockMvcRequestBuilders.get("/cia/quiz")) + .andExpect(status().isOk()) + .andReturn(); + String responseString = result.getResponse().getContentAsString(); + assertThat(responseString).isEqualTo("[ false, false, false, false ]"); + } } // end class diff --git a/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringAssignmentTest.java b/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringAssignmentTest.java index b041fac21..fdce4532d 100644 --- a/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringAssignmentTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringAssignmentTest.java @@ -1,44 +1,45 @@ package org.owasp.webgoat.lessons.clientsidefiltering; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.clientsidefiltering.ClientSideFiltering; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - import static org.mockito.Mockito.when; import static org.owasp.webgoat.lessons.clientsidefiltering.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + /** * @author nbaars * @since 5/2/17. */ public class ClientSideFilteringAssignmentTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new ClientSideFiltering()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new ClientSideFiltering()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void success() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/clientSideFiltering/getItForFree") + @Test + public void success() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/clientSideFiltering/getItForFree") .param("checkoutCode", SUPER_COUPON_CODE)) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void wrongCouponCode() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/clientSideFiltering/getItForFree") + @Test + public void wrongCouponCode() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/clientSideFiltering/getItForFree") .param("checkoutCode", "test")) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect( + jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringFreeAssignmentTest.java b/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringFreeAssignmentTest.java index 4b67d534a..7cb34ceb4 100644 --- a/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringFreeAssignmentTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ClientSideFilteringFreeAssignmentTest.java @@ -1,47 +1,49 @@ package org.owasp.webgoat.lessons.clientsidefiltering; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; + import org.hamcrest.CoreMatchers; import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.clientsidefiltering.ClientSideFiltering; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; - public class ClientSideFilteringFreeAssignmentTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new ClientSideFiltering()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new ClientSideFiltering()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void success() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/clientSideFiltering/attack1") - .param("answer", "450000")) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + @Test + public void success() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/clientSideFiltering/attack1").param("answer", "450000")) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void wrongSalary() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/clientSideFiltering/attack1") - .param("answer", "10000")) - .andExpect(jsonPath("$.feedback", CoreMatchers.is("This is not the salary from Neville Bartholomew..."))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + @Test + public void wrongSalary() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/clientSideFiltering/attack1").param("answer", "10000")) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is("This is not the salary from Neville Bartholomew..."))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - public void getSalaries() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/salaries")) - .andExpect(jsonPath("$[0]", Matchers.hasKey("UserID"))) - .andExpect(jsonPath("$.length()", CoreMatchers.is(12))); - } + @Test + public void getSalaries() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.get("/clientSideFiltering/salaries")) + .andExpect(jsonPath("$[0]", Matchers.hasKey("UserID"))) + .andExpect(jsonPath("$.length()", CoreMatchers.is(12))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ShopEndpointTest.java b/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ShopEndpointTest.java index 0ac9cade0..b9ba65a95 100644 --- a/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ShopEndpointTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/clientsidefiltering/ShopEndpointTest.java @@ -22,21 +22,20 @@ package org.owasp.webgoat.lessons.clientsidefiltering; +import static org.hamcrest.Matchers.is; +import static org.owasp.webgoat.lessons.clientsidefiltering.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.clientsidefiltering.ShopEndpoint; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.hamcrest.Matchers.is; -import static org.owasp.webgoat.lessons.clientsidefiltering.ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - /** * @author nbaars * @since 5/2/17. @@ -44,38 +43,45 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal @ExtendWith(SpringExtension.class) public class ShopEndpointTest extends LessonTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - @BeforeEach - public void setup() { - this.mockMvc = standaloneSetup(new ShopEndpoint()).build(); - } + @BeforeEach + public void setup() { + this.mockMvc = standaloneSetup(new ShopEndpoint()).build(); + } - @Test - public void getSuperCoupon() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/" + SUPER_COUPON_CODE)) - .andExpect(jsonPath("$.code", CoreMatchers.is(SUPER_COUPON_CODE))) - .andExpect(jsonPath("$.discount", CoreMatchers.is(100))); - } + @Test + public void getSuperCoupon() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get( + "/clientSideFiltering/challenge-store/coupons/" + SUPER_COUPON_CODE)) + .andExpect(jsonPath("$.code", CoreMatchers.is(SUPER_COUPON_CODE))) + .andExpect(jsonPath("$.discount", CoreMatchers.is(100))); + } - @Test - public void getCoupon() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/webgoat")) - .andExpect(jsonPath("$.code", CoreMatchers.is("webgoat"))) - .andExpect(jsonPath("$.discount", CoreMatchers.is(25))); - } + @Test + public void getCoupon() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/webgoat")) + .andExpect(jsonPath("$.code", CoreMatchers.is("webgoat"))) + .andExpect(jsonPath("$.discount", CoreMatchers.is(25))); + } - @Test - public void askForUnknownCouponCode() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/does-not-exists")) - .andExpect(jsonPath("$.code", CoreMatchers.is("no"))) - .andExpect(jsonPath("$.discount", CoreMatchers.is(0))); - } - - @Test - public void fetchAllTheCouponsShouldContainGetItForFree() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/")) - .andExpect(jsonPath("$.codes[3].code", is("get_it_for_free"))); - } + @Test + public void askForUnknownCouponCode() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get( + "/clientSideFiltering/challenge-store/coupons/does-not-exists")) + .andExpect(jsonPath("$.code", CoreMatchers.is("no"))) + .andExpect(jsonPath("$.discount", CoreMatchers.is(0))); + } + @Test + public void fetchAllTheCouponsShouldContainGetItForFree() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.get("/clientSideFiltering/challenge-store/coupons/")) + .andExpect(jsonPath("$.codes[3].code", is("get_it_for_free"))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/cryptography/CryptoUtilTest.java b/src/test/java/org/owasp/webgoat/lessons/cryptography/CryptoUtilTest.java index 4e46cc406..51686debf 100644 --- a/src/test/java/org/owasp/webgoat/lessons/cryptography/CryptoUtilTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/cryptography/CryptoUtilTest.java @@ -1,33 +1,33 @@ package org.owasp.webgoat.lessons.cryptography; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; - -import javax.xml.bind.DatatypeConverter; -import java.security.KeyPair; -import java.security.PrivateKey; -import java.security.interfaces.RSAPublicKey; - import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.interfaces.RSAPublicKey; +import javax.xml.bind.DatatypeConverter; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + @Slf4j public class CryptoUtilTest { - @Test - public void testSigningAssignment() { - try { - KeyPair keyPair = CryptoUtil.generateKeyPair(); - RSAPublicKey rsaPubKey = (RSAPublicKey) keyPair.getPublic(); - PrivateKey privateKey = CryptoUtil.getPrivateKeyFromPEM(CryptoUtil.getPrivateKeyInPEM(keyPair)); - String modulus = DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()); - String signature = CryptoUtil.signMessage(modulus, privateKey); - log.debug("public exponent {}", rsaPubKey.getPublicExponent()); - assertTrue(CryptoUtil.verifyAssignment(modulus, signature, keyPair.getPublic())); - } catch (Exception e) { - log.error("signing failed", e);; - fail(); - } - } - + @Test + public void testSigningAssignment() { + try { + KeyPair keyPair = CryptoUtil.generateKeyPair(); + RSAPublicKey rsaPubKey = (RSAPublicKey) keyPair.getPublic(); + PrivateKey privateKey = + CryptoUtil.getPrivateKeyFromPEM(CryptoUtil.getPrivateKeyInPEM(keyPair)); + String modulus = DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()); + String signature = CryptoUtil.signMessage(modulus, privateKey); + log.debug("public exponent {}", rsaPubKey.getPublicExponent()); + assertTrue(CryptoUtil.verifyAssignment(modulus, signature, keyPair.getPublic())); + } catch (Exception e) { + log.error("signing failed", e); + ; + fail(); + } + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/csrf/CSRFFeedbackTest.java b/src/test/java/org/owasp/webgoat/lessons/csrf/CSRFFeedbackTest.java index 75fa827fd..fdc1d5cb3 100644 --- a/src/test/java/org/owasp/webgoat/lessons/csrf/CSRFFeedbackTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/csrf/CSRFFeedbackTest.java @@ -22,55 +22,57 @@ package org.owasp.webgoat.lessons.csrf; -import org.hamcrest.core.StringContains; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.csrf.CSRF; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import javax.servlet.http.Cookie; - import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import javax.servlet.http.Cookie; +import org.hamcrest.core.StringContains; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + /** * @author nbaars * @since 11/17/17. */ public class CSRFFeedbackTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new CSRF()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new CSRF()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void postingJsonMessageThroughWebGoatShouldWork() throws Exception { - mockMvc.perform(post("/csrf/feedback/message") + @Test + public void postingJsonMessageThroughWebGoatShouldWork() throws Exception { + mockMvc + .perform( + post("/csrf/feedback/message") .contentType(MediaType.APPLICATION_JSON) - .content("{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\": \"service\", \"message\":\"dsaffd\"}")) - .andExpect(status().isOk()); - } + .content( + "{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\":" + + " \"service\", \"message\":\"dsaffd\"}")) + .andExpect(status().isOk()); + } - - @Test - public void csrfAttack() throws Exception { - mockMvc.perform(post("/csrf/feedback/message") + @Test + public void csrfAttack() throws Exception { + mockMvc + .perform( + post("/csrf/feedback/message") .contentType(MediaType.TEXT_PLAIN) .cookie(new Cookie("JSESSIONID", "test")) .header("host", "localhost:8080") .header("referer", "webgoat.org") - .content("{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\": \"service\", \"message\":\"dsaffd\"}")) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("feedback", StringContains.containsString("the flag is: "))); - } + .content( + "{\"name\": \"Test\", \"email\": \"test1233@dfssdf.de\", \"subject\":" + + " \"service\", \"message\":\"dsaffd\"}")) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("feedback", StringContains.containsString("the flag is: "))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/deserialization/DeserializeTest.java b/src/test/java/org/owasp/webgoat/lessons/deserialization/DeserializeTest.java index 1840ce0b9..802c8c672 100644 --- a/src/test/java/org/owasp/webgoat/lessons/deserialization/DeserializeTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/deserialization/DeserializeTest.java @@ -1,5 +1,10 @@ package org.owasp.webgoat.lessons.deserialization; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import org.dummy.insecure.framework.VulnerableTaskHolder; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; @@ -10,72 +15,97 @@ import org.owasp.webgoat.container.assignments.AssignmentEndpointTest; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.hamcrest.Matchers.is; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - @ExtendWith(MockitoExtension.class) class DeserializeTest extends AssignmentEndpointTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - private static String OS = System.getProperty("os.name").toLowerCase(); + private static String OS = System.getProperty("os.name").toLowerCase(); - @BeforeEach - void setup() { - InsecureDeserializationTask insecureTask = new InsecureDeserializationTask(); - init(insecureTask); - this.mockMvc = standaloneSetup(insecureTask).build(); + @BeforeEach + void setup() { + InsecureDeserializationTask insecureTask = new InsecureDeserializationTask(); + init(insecureTask); + this.mockMvc = standaloneSetup(insecureTask).build(); + } + + @Test + void success() throws Exception { + if (OS.indexOf("win") > -1) { + mockMvc + .perform( + MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .param( + "token", + SerializationHelper.toString( + new VulnerableTaskHolder("wait", "ping localhost -n 5")))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } else { + mockMvc + .perform( + MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .param( + "token", + SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); } + } - @Test - void success() throws Exception { - if (OS.indexOf("win") > -1) { - mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") - .param("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "ping localhost -n 5")))) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); - } else { - mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") - .param("token", SerializationHelper.toString(new VulnerableTaskHolder("wait", "sleep 5")))) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); - } - } + @Test + void fail() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/InsecureDeserialization/task") + .param( + "token", + SerializationHelper.toString(new VulnerableTaskHolder("delete", "rm *")))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } - @Test - void fail() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") - .param("token", SerializationHelper.toString(new VulnerableTaskHolder("delete", "rm *")))) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); - } + @Test + void wrongVersion() throws Exception { + String token = + "rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAECAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfjCR4GIQgMLRSoeHQACmVjaG8gaGVsbG90AAhzYXlIZWxsbw"; + mockMvc + .perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task").param("token", token)) + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is( + pluginMessages.getMessage("insecure-deserialization.invalidversion")))) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } - @Test - void wrongVersion() throws Exception { - String token = "rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAECAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfjCR4GIQgMLRSoeHQACmVjaG8gaGVsbG90AAhzYXlIZWxsbw"; - mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("insecure-deserialization.invalidversion")))) - .andExpect(jsonPath("$.lessonCompleted", is(false))); - } + @Test + void expiredTask() throws Exception { + String token = + "rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAICAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfjCR4IDC0YfvNIeHQACmVjaG8gaGVsbG90AAhzYXlIZWxsbw"; + mockMvc + .perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task").param("token", token)) + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("insecure-deserialization.expired")))) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } - @Test - void expiredTask() throws Exception { - String token = "rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAICAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfjCR4IDC0YfvNIeHQACmVjaG8gaGVsbG90AAhzYXlIZWxsbw"; - mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("insecure-deserialization.expired")))) - .andExpect(jsonPath("$.lessonCompleted", is(false))); - } - - @Test - void checkOtherObject() throws Exception { - String token = "rO0ABXQAVklmIHlvdSBkZXNlcmlhbGl6ZSBtZSBkb3duLCBJIHNoYWxsIGJlY29tZSBtb3JlIHBvd2VyZnVsIHRoYW4geW91IGNhbiBwb3NzaWJseSBpbWFnaW5l"; - mockMvc.perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("insecure-deserialization.stringobject")))) - .andExpect(jsonPath("$.lessonCompleted", is(false))); - } + @Test + void checkOtherObject() throws Exception { + String token = + "rO0ABXQAVklmIHlvdSBkZXNlcmlhbGl6ZSBtZSBkb3duLCBJIHNoYWxsIGJlY29tZSBtb3JlIHBvd2VyZnVsIHRoYW4geW91IGNhbiBwb3NzaWJseSBpbWFnaW5l"; + mockMvc + .perform(MockMvcRequestBuilders.post("/InsecureDeserialization/task").param("token", token)) + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is( + pluginMessages.getMessage("insecure-deserialization.stringobject")))) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/hijacksession/HijackSessionAssignmentTest.java b/src/test/java/org/owasp/webgoat/lessons/hijacksession/HijackSessionAssignmentTest.java index 5074b23ea..c005b411b 100644 --- a/src/test/java/org/owasp/webgoat/lessons/hijacksession/HijackSessionAssignmentTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/hijacksession/HijackSessionAssignmentTest.java @@ -22,6 +22,15 @@ package org.owasp.webgoat.lessons.hijacksession; +import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.not; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + +import javax.servlet.http.Cookie; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -36,16 +45,6 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import javax.servlet.http.Cookie; - -import static org.hamcrest.Matchers.emptyString; -import static org.hamcrest.Matchers.not; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.lenient; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - /*** * * @author Angel Olle Blazquez @@ -55,54 +54,53 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal @ExtendWith(MockitoExtension.class) class HijackSessionAssignmentTest extends AssignmentEndpointTest { - private MockMvc mockMvc; - private static final String COOKIE_NAME = "hijack_cookie"; - private static final String LOGIN_CONTEXT_PATH = "/HijackSession/login"; + private MockMvc mockMvc; + private static final String COOKIE_NAME = "hijack_cookie"; + private static final String LOGIN_CONTEXT_PATH = "/HijackSession/login"; - @Mock - Authentication authenticationMock; + @Mock Authentication authenticationMock; - @Mock - HijackSessionAuthenticationProvider providerMock; + @Mock HijackSessionAuthenticationProvider providerMock; - HijackSessionAssignment assignment; + HijackSessionAssignment assignment; - @BeforeEach - void setup() { - assignment = new HijackSessionAssignment(); - init(assignment); - ReflectionTestUtils.setField(assignment, "provider", new HijackSessionAuthenticationProvider()); - mockMvc = standaloneSetup(assignment).build(); - } + @BeforeEach + void setup() { + assignment = new HijackSessionAssignment(); + init(assignment); + ReflectionTestUtils.setField(assignment, "provider", new HijackSessionAuthenticationProvider()); + mockMvc = standaloneSetup(assignment).build(); + } - @Test - void testValidCookie() throws Exception { - lenient().when(authenticationMock.isAuthenticated()).thenReturn(true); - lenient().when(providerMock.authenticate(any(Authentication.class))).thenReturn(authenticationMock); - ReflectionTestUtils.setField(assignment, "provider", providerMock); + @Test + void testValidCookie() throws Exception { + lenient().when(authenticationMock.isAuthenticated()).thenReturn(true); + lenient() + .when(providerMock.authenticate(any(Authentication.class))) + .thenReturn(authenticationMock); + ReflectionTestUtils.setField(assignment, "provider", providerMock); - Cookie cookie = new Cookie(COOKIE_NAME, "value"); + Cookie cookie = new Cookie(COOKIE_NAME, "value"); - ResultActions result = mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .cookie(cookie) - .param("username", "") - .param("password", "")); + ResultActions result = + mockMvc.perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .cookie(cookie) + .param("username", "") + .param("password", "")); - result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - } - - @Test - void testBlankCookie() throws Exception { - ResultActions result = mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .param("username", "webgoat") - .param("password", "webgoat")); - - result.andExpect(cookie().value(COOKIE_NAME, not(emptyString()))); - result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - - } + @Test + void testBlankCookie() throws Exception { + ResultActions result = + mockMvc.perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .param("username", "webgoat") + .param("password", "webgoat")); + result.andExpect(cookie().value(COOKIE_NAME, not(emptyString()))); + result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/hijacksession/cas/HijackSessionAuthenticationProviderTest.java b/src/test/java/org/owasp/webgoat/lessons/hijacksession/cas/HijackSessionAuthenticationProviderTest.java index 23bed9dce..e99477627 100644 --- a/src/test/java/org/owasp/webgoat/lessons/hijacksession/cas/HijackSessionAuthenticationProviderTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/hijacksession/cas/HijackSessionAuthenticationProviderTest.java @@ -28,16 +28,13 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import java.util.stream.Stream; - import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.owasp.webgoat.lessons.hijacksession.cas.Authentication; import org.owasp.webgoat.lessons.hijacksession.cas.Authentication.AuthenticationBuilder; -import org.owasp.webgoat.lessons.hijacksession.cas.HijackSessionAuthenticationProvider; /*** * @@ -47,72 +44,82 @@ import org.owasp.webgoat.lessons.hijacksession.cas.HijackSessionAuthenticationPr class HijackSessionAuthenticationProviderTest { - HijackSessionAuthenticationProvider provider = new HijackSessionAuthenticationProvider(); + HijackSessionAuthenticationProvider provider = new HijackSessionAuthenticationProvider(); - @ParameterizedTest - @DisplayName("Provider authentication test") - @MethodSource("authenticationForCookieValues") - void testProviderAuthenticationGeneratesCookie(Authentication authentication) { - Authentication auth = provider.authenticate(authentication); - assertThat(auth.getId(), not(StringUtils.isEmpty(auth.getId()))); - } + @ParameterizedTest + @DisplayName("Provider authentication test") + @MethodSource("authenticationForCookieValues") + void testProviderAuthenticationGeneratesCookie(Authentication authentication) { + Authentication auth = provider.authenticate(authentication); + assertThat(auth.getId(), not(StringUtils.isEmpty(auth.getId()))); + } - @Test - void testAuthenticated() { - String id = "anyId"; - provider.addSession(id); + @Test + void testAuthenticated() { + String id = "anyId"; + provider.addSession(id); - Authentication auth = provider.authenticate(Authentication.builder().id(id).build()); + Authentication auth = provider.authenticate(Authentication.builder().id(id).build()); - assertThat(auth.getId(), is(id)); - assertThat(auth.isAuthenticated(), is(true)); + assertThat(auth.getId(), is(id)); + assertThat(auth.isAuthenticated(), is(true)); - auth = provider.authenticate(Authentication.builder().id("otherId").build()); + auth = provider.authenticate(Authentication.builder().id("otherId").build()); - assertThat(auth.getId(), is("otherId")); - assertThat(auth.isAuthenticated(), is(false)); - } + assertThat(auth.getId(), is("otherId")); + assertThat(auth.isAuthenticated(), is(false)); + } - @Test - void testAuthenticationToString() { - AuthenticationBuilder authBuilder = Authentication.builder() + @Test + void testAuthenticationToString() { + AuthenticationBuilder authBuilder = + Authentication.builder() .name("expectedName") .credentials("expectedCredentials") .id("expectedId"); - Authentication auth = authBuilder.build(); + Authentication auth = authBuilder.build(); - String expected = "Authentication.AuthenticationBuilder(" - + "name=" + auth.getName() - + ", credentials=" + auth.getCredentials() - + ", id=" + auth.getId() + ")"; + String expected = + "Authentication.AuthenticationBuilder(" + + "name=" + + auth.getName() + + ", credentials=" + + auth.getCredentials() + + ", id=" + + auth.getId() + + ")"; - assertThat(authBuilder.toString(), is(expected)); + assertThat(authBuilder.toString(), is(expected)); - expected = "Authentication(authenticated=" + auth.isAuthenticated() - + ", name=" + auth.getName() - + ", credentials=" + auth.getCredentials() - + ", id=" + auth.getId() + ")"; + expected = + "Authentication(authenticated=" + + auth.isAuthenticated() + + ", name=" + + auth.getName() + + ", credentials=" + + auth.getCredentials() + + ", id=" + + auth.getId() + + ")"; - assertThat(auth.toString(), is(expected)); + assertThat(auth.toString(), is(expected)); + } + @Test + void testMaxSessions() { + for (int i = 0; i <= HijackSessionAuthenticationProvider.MAX_SESSIONS + 1; i++) { + provider.authorizedUserAutoLogin(); + provider.addSession(null); } - @Test - void testMaxSessions() { - for (int i = 0; i <= HijackSessionAuthenticationProvider.MAX_SESSIONS + 1; i++) { - provider.authorizedUserAutoLogin(); - provider.addSession(null); - } - - assertThat(provider.getSessionsSize(), is(HijackSessionAuthenticationProvider.MAX_SESSIONS)); - } - - private static Stream authenticationForCookieValues() { - return Stream.of( - Arguments.of((Object) null), - Arguments.of(Authentication.builder().name("any").credentials("any").build()), - Arguments.of(Authentication.builder().id("any").build())); - } + assertThat(provider.getSessionsSize(), is(HijackSessionAuthenticationProvider.MAX_SESSIONS)); + } + private static Stream authenticationForCookieValues() { + return Stream.of( + Arguments.of((Object) null), + Arguments.of(Authentication.builder().name("any").credentials("any").build()), + Arguments.of(Authentication.builder().id("any").build())); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/httpproxies/HttpBasicsInterceptRequestTest.java b/src/test/java/org/owasp/webgoat/lessons/httpproxies/HttpBasicsInterceptRequestTest.java index 8cbc86bb7..4ba92bf70 100644 --- a/src/test/java/org/owasp/webgoat/lessons/httpproxies/HttpBasicsInterceptRequestTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/httpproxies/HttpBasicsInterceptRequestTest.java @@ -22,77 +22,101 @@ package org.owasp.webgoat.lessons.httpproxies; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.owasp.webgoat.container.assignments.AssignmentEndpointTest; -import org.owasp.webgoat.lessons.httpproxies.HttpBasicsInterceptRequest; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - @ExtendWith(MockitoExtension.class) public class HttpBasicsInterceptRequestTest extends AssignmentEndpointTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - @BeforeEach - public void setup() { - HttpBasicsInterceptRequest httpBasicsInterceptRequest = new HttpBasicsInterceptRequest(); - init(httpBasicsInterceptRequest); - this.mockMvc = standaloneSetup(httpBasicsInterceptRequest).build(); - } + @BeforeEach + public void setup() { + HttpBasicsInterceptRequest httpBasicsInterceptRequest = new HttpBasicsInterceptRequest(); + init(httpBasicsInterceptRequest); + this.mockMvc = standaloneSetup(httpBasicsInterceptRequest).build(); + } - @Test - public void success() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/HttpProxies/intercept-request") + @Test + public void success() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/HttpProxies/intercept-request") .header("x-request-intercepted", "true") .param("changeMe", "Requests are tampered easily")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.success")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.success")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void failure() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/HttpProxies/intercept-request") + @Test + public void failure() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/HttpProxies/intercept-request") .header("x-request-intercepted", "false") .param("changeMe", "Requests are tampered easily")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.failure")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.failure")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - public void missingParam() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/HttpProxies/intercept-request") + @Test + public void missingParam() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/HttpProxies/intercept-request") .header("x-request-intercepted", "false")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.failure")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.failure")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - public void missingHeader() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/HttpProxies/intercept-request") + @Test + public void missingHeader() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/HttpProxies/intercept-request") .param("changeMe", "Requests are tampered easily")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.failure")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.failure")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - public void whenPostAssignmentShouldNotPass() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/HttpProxies/intercept-request") + @Test + public void whenPostAssignmentShouldNotPass() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/HttpProxies/intercept-request") .header("x-request-intercepted", "true") .param("changeMe", "Requests are tampered easily")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.failure")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("http-proxies.intercept.failure")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTDecodeEndpointTest.java b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTDecodeEndpointTest.java index 45ee41a7b..23afbc725 100644 --- a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTDecodeEndpointTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTDecodeEndpointTest.java @@ -1,43 +1,41 @@ package org.owasp.webgoat.lessons.jwt; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.jwt.JWT; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class JWTDecodeEndpointTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new JWT()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new JWT()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void solveAssignment() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/decode") - .param("jwt-encode-user", "user") - .content("")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))); - } + @Test + public void solveAssignment() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/decode").param("jwt-encode-user", "user").content("")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void wrongUserShouldNotSolveAssignment() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/decode") + @Test + public void wrongUserShouldNotSolveAssignment() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/decode") .param("jwt-encode-user", "wrong") .content("")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(false))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpointTest.java b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpointTest.java index 3fadcb10c..1c903c351 100644 --- a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpointTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTFinalEndpointTest.java @@ -1,71 +1,74 @@ package org.owasp.webgoat.lessons.jwt; -import io.jsonwebtoken.Jwts; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.jwt.JWT; -import org.owasp.webgoat.lessons.jwt.JWTFinalEndpoint; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import io.jsonwebtoken.Jwts; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class JWTFinalEndpointTest extends LessonTest { - private static final String TOKEN_JERRY = "eyJraWQiOiJ3ZWJnb2F0X2tleSIsImFsZyI6IkhTNTEyIn0.eyJhdWQiOiJ3ZWJnb2F0Lm9yZyIsImVtYWlsIjoiamVycnlAd2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IkplcnJ5In0.xBc5FFwaOcuxjdr_VJ16n8Jb7vScuaZulNTl66F2MWF1aBe47QsUosvbjWGORNcMPiPNwnMu1Yb0WZVNrp2ZXA"; + private static final String TOKEN_JERRY = + "eyJraWQiOiJ3ZWJnb2F0X2tleSIsImFsZyI6IkhTNTEyIn0.eyJhdWQiOiJ3ZWJnb2F0Lm9yZyIsImVtYWlsIjoiamVycnlAd2ViZ29hdC5jb20iLCJ1c2VybmFtZSI6IkplcnJ5In0.xBc5FFwaOcuxjdr_VJ16n8Jb7vScuaZulNTl66F2MWF1aBe47QsUosvbjWGORNcMPiPNwnMu1Yb0WZVNrp2ZXA"; - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new JWT()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new JWT()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void solveAssignment() throws Exception { - String key = "deletingTom"; - Map claims = new HashMap<>(); - claims.put("username", "Tom"); - String token = Jwts.builder() - .setHeaderParam("kid", "hacked' UNION select '" + key + "' from INFORMATION_SCHEMA.SYSTEM_USERS --") - .setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10))) - .setClaims(claims) - .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, key) - .compact(); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/final/delete") - .param("token", token) - .content("")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))); - } + @Test + public void solveAssignment() throws Exception { + String key = "deletingTom"; + Map claims = new HashMap<>(); + claims.put("username", "Tom"); + String token = + Jwts.builder() + .setHeaderParam( + "kid", "hacked' UNION select '" + key + "' from INFORMATION_SCHEMA.SYSTEM_USERS --") + .setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10))) + .setClaims(claims) + .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, key) + .compact(); + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/final/delete").param("token", token).content("")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void withJerrysKeyShouldNotSolveAssignment() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/final/delete") + @Test + public void withJerrysKeyShouldNotSolveAssignment() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/final/delete") .param("token", TOKEN_JERRY) .content("")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-final-jerry-account")))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", CoreMatchers.is(messages.getMessage("jwt-final-jerry-account")))); + } - @Test - public void shouldNotBeAbleToBypassWithSimpleToken() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/final/delete") + @Test + public void shouldNotBeAbleToBypassWithSimpleToken() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/final/delete") .param("token", ".eyJ1c2VybmFtZSI6IlRvbSJ9.") .content("")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpointTest.java b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpointTest.java index 0ecdaa28b..36eb18305 100644 --- a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpointTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTRefreshEndpointTest.java @@ -22,192 +22,230 @@ package org.owasp.webgoat.lessons.jwt; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.jwt.JWT; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.util.HashMap; -import java.util.Map; - import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; import static org.owasp.webgoat.lessons.jwt.JWTRefreshEndpoint.PASSWORD; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.HashMap; +import java.util.Map; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class JWTRefreshEndpointTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new JWT()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - when(webSession.getUserName()).thenReturn("unit-test"); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new JWT()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + when(webSession.getUserName()).thenReturn("unit-test"); + } - @Test - public void solveAssignment() throws Exception { - ObjectMapper objectMapper = new ObjectMapper(); + @Test + public void solveAssignment() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); - //First login to obtain tokens for Jerry - var loginJson = Map.of("user", "Jerry", "password", PASSWORD); - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(loginJson))) - .andExpect(status().isOk()) - .andReturn(); - Map tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); - String accessToken = tokens.get("access_token"); - String refreshToken = tokens.get("refresh_token"); + // First login to obtain tokens for Jerry + var loginJson = Map.of("user", "Jerry", "password", PASSWORD); + MvcResult result = + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginJson))) + .andExpect(status().isOk()) + .andReturn(); + Map tokens = + objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); + String accessToken = tokens.get("access_token"); + String refreshToken = tokens.get("refresh_token"); - //Now create a new refresh token for Tom based on Toms old access token and send the refresh token of Jerry - String accessTokenTom = "eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q"; - Map refreshJson = new HashMap<>(); - refreshJson.put("refresh_token", refreshToken); - result = mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/newToken") - .contentType(MediaType.APPLICATION_JSON) - .header("Authorization", "Bearer " + accessTokenTom) - .content(objectMapper.writeValueAsString(refreshJson))) - .andExpect(status().isOk()) - .andReturn(); - tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); - accessTokenTom = tokens.get("access_token"); + // Now create a new refresh token for Tom based on Toms old access token and send the refresh + // token of Jerry + String accessTokenTom = + "eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q"; + Map refreshJson = new HashMap<>(); + refreshJson.put("refresh_token", refreshToken); + result = + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/newToken") + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", "Bearer " + accessTokenTom) + .content(objectMapper.writeValueAsString(refreshJson))) + .andExpect(status().isOk()) + .andReturn(); + tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); + accessTokenTom = tokens.get("access_token"); - //Now checkout with the new token from Tom - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout") + // Now checkout with the new token from Tom + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/checkout") .header("Authorization", "Bearer " + accessTokenTom)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void checkoutWithTomsTokenFromAccessLogShouldFail() throws Exception { - String accessTokenTom = "eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q"; - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout") + @Test + public void checkoutWithTomsTokenFromAccessLogShouldFail() throws Exception { + String accessTokenTom = + "eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q"; + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/checkout") .header("Authorization", "Bearer " + accessTokenTom)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.output", CoreMatchers.containsString("JWT expired at"))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.output", CoreMatchers.containsString("JWT expired at"))); + } - @Test - public void checkoutWitRandomTokenShouldFail() throws Exception { - String accessTokenTom = "eyJhbGciOiJIUzUxMiJ9.eyJpLXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q"; - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout") + @Test + public void checkoutWitRandomTokenShouldFail() throws Exception { + String accessTokenTom = + "eyJhbGciOiJIUzUxMiJ9.eyJpLXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q"; + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/checkout") .header("Authorization", "Bearer " + accessTokenTom)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); + } - @Test - public void flowForJerryAlwaysWorks() throws Exception { - ObjectMapper objectMapper = new ObjectMapper(); + @Test + public void flowForJerryAlwaysWorks() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); - var loginJson = Map.of("user", "Jerry", "password", PASSWORD); - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(loginJson))) - .andExpect(status().isOk()) - .andReturn(); - Map tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); - String accessToken = tokens.get("access_token"); + var loginJson = Map.of("user", "Jerry", "password", PASSWORD); + MvcResult result = + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginJson))) + .andExpect(status().isOk()) + .andReturn(); + Map tokens = + objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); + String accessToken = tokens.get("access_token"); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout") + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/checkout") .header("Authorization", "Bearer " + accessToken)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", is("User is not Tom but Jerry, please try again"))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.feedback", is("User is not Tom but Jerry, please try again"))); + } - @Test - public void loginShouldNotWorkForJerryWithWrongPassword() throws Exception { - ObjectMapper objectMapper = new ObjectMapper(); + @Test + public void loginShouldNotWorkForJerryWithWrongPassword() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); - var loginJson = Map.of("user", "Jerry", "password", PASSWORD + "wrong"); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login") + var loginJson = Map.of("user", "Jerry", "password", PASSWORD + "wrong"); + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/login") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(loginJson))) - .andExpect(status().isUnauthorized()); - } + .andExpect(status().isUnauthorized()); + } - @Test - public void loginShouldNotWorkForTom() throws Exception { - ObjectMapper objectMapper = new ObjectMapper(); + @Test + public void loginShouldNotWorkForTom() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); - var loginJson = Map.of("user", "Tom", "password", PASSWORD); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login") + var loginJson = Map.of("user", "Tom", "password", PASSWORD); + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/login") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(loginJson))) - .andExpect(status().isUnauthorized()); - } + .andExpect(status().isUnauthorized()); + } - @Test - public void newTokenShouldWorkForJerry() throws Exception { - ObjectMapper objectMapper = new ObjectMapper(); - Map loginJson = new HashMap<>(); - loginJson.put("user", "Jerry"); - loginJson.put("password", PASSWORD); - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(loginJson))) - .andExpect(status().isOk()) - .andReturn(); - Map tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); - String accessToken = tokens.get("access_token"); - String refreshToken = tokens.get("refresh_token"); + @Test + public void newTokenShouldWorkForJerry() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + Map loginJson = new HashMap<>(); + loginJson.put("user", "Jerry"); + loginJson.put("password", PASSWORD); + MvcResult result = + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginJson))) + .andExpect(status().isOk()) + .andReturn(); + Map tokens = + objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); + String accessToken = tokens.get("access_token"); + String refreshToken = tokens.get("refresh_token"); - var refreshJson = Map.of("refresh_token", refreshToken); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/newToken") + var refreshJson = Map.of("refresh_token", refreshToken); + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/newToken") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + accessToken) .content(objectMapper.writeValueAsString(refreshJson))) - .andExpect(status().isOk()); - } + .andExpect(status().isOk()); + } - @Test - public void unknownRefreshTokenShouldGiveUnauthorized() throws Exception { - ObjectMapper objectMapper = new ObjectMapper(); - Map loginJson = new HashMap<>(); - loginJson.put("user", "Jerry"); - loginJson.put("password", PASSWORD); - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(loginJson))) - .andExpect(status().isOk()) - .andReturn(); - Map tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); - String accessToken = tokens.get("access_token"); + @Test + public void unknownRefreshTokenShouldGiveUnauthorized() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + Map loginJson = new HashMap<>(); + loginJson.put("user", "Jerry"); + loginJson.put("password", PASSWORD); + MvcResult result = + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginJson))) + .andExpect(status().isOk()) + .andReturn(); + Map tokens = + objectMapper.readValue(result.getResponse().getContentAsString(), Map.class); + String accessToken = tokens.get("access_token"); - var refreshJson = Map.of("refresh_token", "wrong_refresh_token"); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/newToken") + var refreshJson = Map.of("refresh_token", "wrong_refresh_token"); + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/refresh/newToken") .contentType(MediaType.APPLICATION_JSON) .header("Authorization", "Bearer " + accessToken) .content(objectMapper.writeValueAsString(refreshJson))) - .andExpect(status().isUnauthorized()); - } + .andExpect(status().isUnauthorized()); + } - @Test - public void noTokenWhileCheckoutShouldReturn401() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout")) - .andExpect(status().isUnauthorized()); - } + @Test + public void noTokenWhileCheckoutShouldReturn401() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout")) + .andExpect(status().isUnauthorized()); + } - @Test - public void noTokenWhileRequestingNewTokenShouldReturn401() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/newToken")) - .andExpect(status().isUnauthorized()); - } + @Test + public void noTokenWhileRequestingNewTokenShouldReturn401() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/refresh/newToken")) + .andExpect(status().isUnauthorized()); + } - @Test - public void noTokenWhileLoginShouldReturn401() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login")) - .andExpect(status().isUnauthorized()); - } + @Test + public void noTokenWhileLoginShouldReturn401() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/refresh/login")) + .andExpect(status().isUnauthorized()); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTSecretKeyEndpointTest.java b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTSecretKeyEndpointTest.java index b99b9f828..4c512ac22 100644 --- a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTSecretKeyEndpointTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTSecretKeyEndpointTest.java @@ -22,23 +22,6 @@ package org.owasp.webgoat.lessons.jwt; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.jwt.JWT; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.time.Duration; -import java.time.Instant; -import java.util.Date; - import static io.jsonwebtoken.SignatureAlgorithm.HS512; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; @@ -46,94 +29,114 @@ import static org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint.JWT_SECRET; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class JWTSecretKeyEndpointTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new JWT()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - when(webSession.getUserName()).thenReturn("unit-test"); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new JWT()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + when(webSession.getUserName()).thenReturn("unit-test"); + } - private Claims createClaims(String username) { - Claims claims = Jwts.claims(); - claims.put("admin", "true"); - claims.put("user", "Tom"); - claims.setExpiration(Date.from(Instant.now().plus(Duration.ofDays(1)))); - claims.setIssuedAt(Date.from(Instant.now().plus(Duration.ofDays(1)))); - claims.setIssuer("iss"); - claims.setAudience("aud"); - claims.setSubject("sub"); - claims.put("username", username); - claims.put("Email", "webgoat@webgoat.io"); - claims.put("Role", new String[]{"user"}); - return claims; - } + private Claims createClaims(String username) { + Claims claims = Jwts.claims(); + claims.put("admin", "true"); + claims.put("user", "Tom"); + claims.setExpiration(Date.from(Instant.now().plus(Duration.ofDays(1)))); + claims.setIssuedAt(Date.from(Instant.now().plus(Duration.ofDays(1)))); + claims.setIssuer("iss"); + claims.setAudience("aud"); + claims.setSubject("sub"); + claims.put("username", username); + claims.put("Email", "webgoat@webgoat.io"); + claims.put("Role", new String[] {"user"}); + return claims; + } - @Test - public void solveAssignment() throws Exception { - Claims claims = createClaims("WebGoat"); - String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact(); + @Test + public void solveAssignment() throws Exception { + Claims claims = createClaims("WebGoat"); + String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact(); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))); - } + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/secret").param("token", token)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void solveAssignmentWithLowercase() throws Exception { - Claims claims = createClaims("webgoat"); - String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact(); + @Test + public void solveAssignmentWithLowercase() throws Exception { + Claims claims = createClaims("webgoat"); + String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact(); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))); - } + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/secret").param("token", token)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void oneOfClaimIsMissingShouldNotSolveAssignment() throws Exception { - Claims claims = createClaims("WebGoat"); - claims.remove("aud"); - String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact(); + @Test + public void oneOfClaimIsMissingShouldNotSolveAssignment() throws Exception { + Claims claims = createClaims("WebGoat"); + claims.remove("aud"); + String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact(); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-secret-claims-missing")))); - } + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/secret").param("token", token)) + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", CoreMatchers.is(messages.getMessage("jwt-secret-claims-missing")))); + } - @Test - public void incorrectUser() throws Exception { - Claims claims = createClaims("Tom"); - String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact(); + @Test + public void incorrectUser() throws Exception { + Claims claims = createClaims("Tom"); + String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact(); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-secret-incorrect-user", "default", "Tom")))); - } + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/secret").param("token", token)) + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is( + messages.getMessage("jwt-secret-incorrect-user", "default", "Tom")))); + } - @Test - public void incorrectToken() throws Exception { - Claims claims = createClaims("Tom"); - String token = Jwts.builder().setClaims(claims).signWith(HS512, "wrong_password").compact(); + @Test + public void incorrectToken() throws Exception { + Claims claims = createClaims("Tom"); + String token = Jwts.builder().setClaims(claims).signWith(HS512, "wrong_password").compact(); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); - } + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/secret").param("token", token)) + .andExpect(status().isOk()) + .andExpect( + jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); + } - @Test - void unsignedToken() throws Exception { - Claims claims = createClaims("WebGoat"); - String token = Jwts.builder().setClaims(claims).compact(); + @Test + void unsignedToken() throws Exception { + Claims claims = createClaims("WebGoat"); + String token = Jwts.builder().setClaims(claims).compact(); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret") - .param("token", token)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); - } + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/secret").param("token", token)) + .andExpect(status().isOk()) + .andExpect( + jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTVotesEndpointTest.java b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTVotesEndpointTest.java index b2bddb59e..2d7b4c8d5 100644 --- a/src/test/java/org/owasp/webgoat/lessons/jwt/JWTVotesEndpointTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/jwt/JWTVotesEndpointTest.java @@ -22,22 +22,6 @@ package org.owasp.webgoat.lessons.jwt; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.jwt.JWT; -import org.springframework.http.MediaType; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import javax.servlet.http.Cookie; -import java.util.Map; - import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; @@ -47,174 +31,229 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import java.util.Map; +import javax.servlet.http.Cookie; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class JWTVotesEndpointTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new JWT()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - when(webSession.getUserName()).thenReturn("unit-test"); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new JWT()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + when(webSession.getUserName()).thenReturn("unit-test"); + } - @Test - public void solveAssignment() throws Exception { - //Create new token and set alg to none and do not sign it - Claims claims = Jwts.claims(); - claims.put("admin", "true"); - claims.put("user", "Tom"); - String token = Jwts.builder().setClaims(claims).setHeaderParam("alg", "none").compact(); + @Test + public void solveAssignment() throws Exception { + // Create new token and set alg to none and do not sign it + Claims claims = Jwts.claims(); + claims.put("admin", "true"); + claims.put("user", "Tom"); + String token = Jwts.builder().setClaims(claims).setHeaderParam("alg", "none").compact(); - //Call the reset endpoint - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings") + // Call the reset endpoint + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/votings") .contentType(MediaType.APPLICATION_JSON) .cookie(new Cookie("access_token", token))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void solveAssignmentWithBoolean() throws Exception { - //Create new token and set alg to none and do not sign it - Claims claims = Jwts.claims(); - claims.put("admin", true); - claims.put("user", "Tom"); - String token = Jwts.builder().setClaims(claims).setHeaderParam("alg", "none").compact(); + @Test + public void solveAssignmentWithBoolean() throws Exception { + // Create new token and set alg to none and do not sign it + Claims claims = Jwts.claims(); + claims.put("admin", true); + claims.put("user", "Tom"); + String token = Jwts.builder().setClaims(claims).setHeaderParam("alg", "none").compact(); - //Call the reset endpoint - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings") + // Call the reset endpoint + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/votings") .contentType(MediaType.APPLICATION_JSON) .cookie(new Cookie("access_token", token))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void resetWithoutTokenShouldNotWork() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); - } + @Test + public void resetWithoutTokenShouldNotWork() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/votings").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect( + jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token")))); + } - @Test - public void guestShouldNotGetAToken() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/login") + @Test + public void guestShouldNotGetAToken() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/JWT/votings/login") .contentType(MediaType.APPLICATION_JSON) .param("user", "Guest")) - .andExpect(status().isUnauthorized()).andExpect(cookie().value("access_token", "")); - } + .andExpect(status().isUnauthorized()) + .andExpect(cookie().value("access_token", "")); + } - @Test - public void tomShouldGetAToken() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/login") + @Test + public void tomShouldGetAToken() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/JWT/votings/login") .contentType(MediaType.APPLICATION_JSON) .param("user", "Tom")) - .andExpect(status().isOk()).andExpect(cookie().value("access_token", containsString("eyJhbGciOiJIUzUxMiJ9."))); - } + .andExpect(status().isOk()) + .andExpect(cookie().value("access_token", containsString("eyJhbGciOiJIUzUxMiJ9."))); + } - @Test - public void guestShouldNotSeeNumberOfVotes() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings") - .cookie(new Cookie("access_token", ""))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist()) - .andExpect(jsonPath("$[0].votingAllowed").doesNotExist()) - .andExpect(jsonPath("$[0].average").doesNotExist()); - } + @Test + public void guestShouldNotSeeNumberOfVotes() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.get("/JWT/votings").cookie(new Cookie("access_token", ""))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist()) + .andExpect(jsonPath("$[0].votingAllowed").doesNotExist()) + .andExpect(jsonPath("$[0].average").doesNotExist()); + } - @Test - public void tomShouldSeeNumberOfVotes() throws Exception { - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/login") - .contentType(MediaType.APPLICATION_JSON) - .param("user", "Tom")) - .andExpect(status().isOk()).andReturn(); + @Test + public void tomShouldSeeNumberOfVotes() throws Exception { + MvcResult result = + mockMvc + .perform( + MockMvcRequestBuilders.get("/JWT/votings/login") + .contentType(MediaType.APPLICATION_JSON) + .param("user", "Tom")) + .andExpect(status().isOk()) + .andReturn(); - mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings") - .cookie(result.getResponse().getCookies()[0])) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].numberOfVotes").exists()) - .andExpect(jsonPath("$[0].votingAllowed").exists()) - .andExpect(jsonPath("$[0].average").exists()); - } + mockMvc + .perform( + MockMvcRequestBuilders.get("/JWT/votings").cookie(result.getResponse().getCookies()[0])) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].numberOfVotes").exists()) + .andExpect(jsonPath("$[0].votingAllowed").exists()) + .andExpect(jsonPath("$[0].average").exists()); + } - @Test - public void invalidTokenShouldSeeGuestView() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings") + @Test + public void invalidTokenShouldSeeGuestView() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/JWT/votings") .cookie(new Cookie("access_token", "abcd.efgh.ijkl"))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist()) - .andExpect(jsonPath("$[0].votingAllowed").doesNotExist()) - .andExpect(jsonPath("$[0].average").doesNotExist()); + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist()) + .andExpect(jsonPath("$[0].votingAllowed").doesNotExist()) + .andExpect(jsonPath("$[0].average").doesNotExist()); + } + + @Test + public void tomShouldBeAbleToVote() throws Exception { + MvcResult result = + mockMvc + .perform( + MockMvcRequestBuilders.get("/JWT/votings/login") + .contentType(MediaType.APPLICATION_JSON) + .param("user", "Tom")) + .andExpect(status().isOk()) + .andReturn(); + Cookie cookie = result.getResponse().getCookie("access_token"); + + result = + mockMvc + .perform(MockMvcRequestBuilders.get("/JWT/votings").cookie(cookie)) + .andExpect(status().isOk()) + . + /*andDo(print()).*/ andReturn(); + Object[] nodes = + new ObjectMapper().readValue(result.getResponse().getContentAsString(), Object[].class); + int currentNumberOfVotes = + (int) findNodeByTitle(nodes, "Admin lost password").get("numberOfVotes"); + + mockMvc + .perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password").cookie(cookie)) + .andExpect(status().isAccepted()); + result = + mockMvc + .perform(MockMvcRequestBuilders.get("/JWT/votings").cookie(cookie)) + .andExpect(status().isOk()) + .andReturn(); + nodes = new ObjectMapper().readValue(result.getResponse().getContentAsString(), Object[].class); + int numberOfVotes = (int) findNodeByTitle(nodes, "Admin lost password").get("numberOfVotes"); + assertThat(numberOfVotes).isEqualTo(currentNumberOfVotes + 1); + } + + private Map findNodeByTitle(Object[] nodes, String title) { + for (Object n : nodes) { + Map node = (Map) n; + if (node.get("title").equals(title)) { + return node; + } } + return null; + } - @Test - public void tomShouldBeAbleToVote() throws Exception { - MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/login") - .contentType(MediaType.APPLICATION_JSON) - .param("user", "Tom")) - .andExpect(status().isOk()).andReturn(); - Cookie cookie = result.getResponse().getCookie("access_token"); - - result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings") - .cookie(cookie)) - .andExpect(status().isOk())./*andDo(print()).*/andReturn(); - Object[] nodes = new ObjectMapper().readValue(result.getResponse().getContentAsString(), Object[].class); - int currentNumberOfVotes = (int) findNodeByTitle(nodes, "Admin lost password").get("numberOfVotes"); - - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password") - .cookie(cookie)) - .andExpect(status().isAccepted()); - result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings") - .cookie(cookie)) - .andExpect(status().isOk()).andReturn(); - nodes = new ObjectMapper().readValue(result.getResponse().getContentAsString(), Object[].class); - int numberOfVotes = (int) findNodeByTitle(nodes, "Admin lost password").get("numberOfVotes"); - assertThat(numberOfVotes).isEqualTo(currentNumberOfVotes + 1); - } - - private Map findNodeByTitle(Object[] nodes, String title) { - for (Object n : nodes) { - Map node = (Map) n; - if (node.get("title").equals(title)) { - return node; - } - } - return null; - } - - @Test - public void guestShouldNotBeAbleToVote() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password") + @Test + public void guestShouldNotBeAbleToVote() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/votings/Admin lost password") .cookie(new Cookie("access_token", ""))) - .andExpect(status().isUnauthorized()); - } + .andExpect(status().isUnauthorized()); + } - @Test - public void unknownUserWithValidTokenShouldNotBeAbleToVote() throws Exception { - Claims claims = Jwts.claims(); - claims.put("admin", "true"); - claims.put("user", "Intruder"); - String token = Jwts.builder().signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD).setClaims(claims).compact(); + @Test + public void unknownUserWithValidTokenShouldNotBeAbleToVote() throws Exception { + Claims claims = Jwts.claims(); + claims.put("admin", "true"); + claims.put("user", "Intruder"); + String token = + Jwts.builder() + .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD) + .setClaims(claims) + .compact(); - mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password") + mockMvc + .perform( + MockMvcRequestBuilders.post("/JWT/votings/Admin lost password") .cookie(new Cookie("access_token", token))) - .andExpect(status().isUnauthorized()); - } - - @Test - public void unknownUserShouldSeeGuestView() throws Exception { - Claims claims = Jwts.claims(); - claims.put("admin", "true"); - claims.put("user", "Intruder"); - String token = Jwts.builder().signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD).setClaims(claims).compact(); - - mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/") - .cookie(new Cookie("access_token", token))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist()) - .andExpect(jsonPath("$[0].votingAllowed").doesNotExist()) - .andExpect(jsonPath("$[0].average").doesNotExist()); - } + .andExpect(status().isUnauthorized()); + } + @Test + public void unknownUserShouldSeeGuestView() throws Exception { + Claims claims = Jwts.claims(); + claims.put("admin", "true"); + claims.put("user", "Intruder"); + String token = + Jwts.builder() + .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD) + .setClaims(claims) + .compact(); + mockMvc + .perform( + MockMvcRequestBuilders.get("/JWT/votings/").cookie(new Cookie("access_token", token))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist()) + .andExpect(jsonPath("$[0].votingAllowed").doesNotExist()) + .andExpect(jsonPath("$[0].average").doesNotExist()); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/jwt/TokenTest.java b/src/test/java/org/owasp/webgoat/lessons/jwt/TokenTest.java index 577688400..fe4d100d0 100644 --- a/src/test/java/org/owasp/webgoat/lessons/jwt/TokenTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/jwt/TokenTest.java @@ -28,48 +28,55 @@ import io.jsonwebtoken.Jwt; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SigningKeyResolverAdapter; import io.jsonwebtoken.impl.TextCodec; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; - import java.time.Duration; import java.time.Instant; import java.util.Date; import java.util.Map; import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; @Slf4j public class TokenTest { - @Test - public void test() { - String key = "qwertyqwerty1234"; - Map claims = Map.of("username", "Jerry", "aud", "webgoat.org", "email", "jerry@webgoat.com"); - String token = Jwts.builder() - .setHeaderParam("kid", "webgoat_key") - .setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10))) - .setClaims(claims) - .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, key).compact(); - log.debug(token); - Jwt jwt = Jwts.parser().setSigningKey("qwertyqwerty1234").parse(token); - jwt = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() { - @Override - public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) { - return TextCodec.BASE64.decode(key); - } - }).parse(token); + @Test + public void test() { + String key = "qwertyqwerty1234"; + Map claims = + Map.of("username", "Jerry", "aud", "webgoat.org", "email", "jerry@webgoat.com"); + String token = + Jwts.builder() + .setHeaderParam("kid", "webgoat_key") + .setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10))) + .setClaims(claims) + .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, key) + .compact(); + log.debug(token); + Jwt jwt = Jwts.parser().setSigningKey("qwertyqwerty1234").parse(token); + jwt = + Jwts.parser() + .setSigningKeyResolver( + new SigningKeyResolverAdapter() { + @Override + public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) { + return TextCodec.BASE64.decode(key); + } + }) + .parse(token); + } - } - - @Test - public void testRefresh() { - Instant now = Instant.now(); //current date - Claims claims = Jwts.claims().setIssuedAt(Date.from(now.minus(Duration.ofDays(10)))); - claims.setExpiration(Date.from(now.minus(Duration.ofDays(9)))); - claims.put("admin", "false"); - claims.put("user", "Tom"); - String token = Jwts.builder().setClaims(claims) - .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, "bm5n3SkxCX4kKRy4") - .compact(); - log.debug(token); - } + @Test + public void testRefresh() { + Instant now = Instant.now(); // current date + Claims claims = Jwts.claims().setIssuedAt(Date.from(now.minus(Duration.ofDays(10)))); + claims.setExpiration(Date.from(now.minus(Duration.ofDays(9)))); + claims.put("admin", "false"); + claims.put("user", "Tom"); + String token = + Jwts.builder() + .setClaims(claims) + .signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, "bm5n3SkxCX4kKRy4") + .compact(); + log.debug(token); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/missingac/DisplayUserTest.java b/src/test/java/org/owasp/webgoat/lessons/missingac/DisplayUserTest.java index ecdbb165b..75805dcca 100644 --- a/src/test/java/org/owasp/webgoat/lessons/missingac/DisplayUserTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/missingac/DisplayUserTest.java @@ -26,20 +26,21 @@ import static org.owasp.webgoat.lessons.missingac.MissingFunctionAC.PASSWORD_SAL import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; -import org.owasp.webgoat.lessons.missingac.DisplayUser; -import org.owasp.webgoat.lessons.missingac.User; class DisplayUserTest { - @Test - void testDisplayUserCreation() { - DisplayUser displayUser = new DisplayUser(new User("user1", "password1", true), PASSWORD_SALT_SIMPLE); - Assertions.assertThat(displayUser.isAdmin()).isTrue(); - } + @Test + void testDisplayUserCreation() { + DisplayUser displayUser = + new DisplayUser(new User("user1", "password1", true), PASSWORD_SALT_SIMPLE); + Assertions.assertThat(displayUser.isAdmin()).isTrue(); + } - @Test - void testDisplayUserHash() { - DisplayUser displayUser = new DisplayUser(new User("user1", "password1", false), PASSWORD_SALT_SIMPLE); - Assertions.assertThat(displayUser.getUserHash()).isEqualTo("cplTjehjI/e5ajqTxWaXhU5NW9UotJfXj+gcbPvfWWc="); - } + @Test + void testDisplayUserHash() { + DisplayUser displayUser = + new DisplayUser(new User("user1", "password1", false), PASSWORD_SALT_SIMPLE); + Assertions.assertThat(displayUser.getUserHash()) + .isEqualTo("cplTjehjI/e5ajqTxWaXhU5NW9UotJfXj+gcbPvfWWc="); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACHiddenMenusTest.java b/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACHiddenMenusTest.java index a7aa0dfd7..d55c08814 100644 --- a/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACHiddenMenusTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACHiddenMenusTest.java @@ -22,56 +22,69 @@ package org.owasp.webgoat.lessons.missingac; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.owasp.webgoat.container.assignments.AssignmentEndpointTest; -import org.owasp.webgoat.lessons.missingac.MissingFunctionACHiddenMenus; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - @ExtendWith(MockitoExtension.class) public class MissingFunctionACHiddenMenusTest extends AssignmentEndpointTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - @BeforeEach - public void setup() { - MissingFunctionACHiddenMenus hiddenMenus = new MissingFunctionACHiddenMenus(); - init(hiddenMenus); - this.mockMvc = standaloneSetup(hiddenMenus).build(); - } + @BeforeEach + public void setup() { + MissingFunctionACHiddenMenus hiddenMenus = new MissingFunctionACHiddenMenus(); + init(hiddenMenus); + this.mockMvc = standaloneSetup(hiddenMenus).build(); + } - @Test - public void HiddenMenusSuccess() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/access-control/hidden-menu") + @Test + public void HiddenMenusSuccess() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/access-control/hidden-menu") .param("hiddenMenu1", "Users") .param("hiddenMenu2", "Config")) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("access-control.hidden-menus.success")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("access-control.hidden-menus.success")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void HiddenMenusClose() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/access-control/hidden-menu") + @Test + public void HiddenMenusClose() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/access-control/hidden-menu") .param("hiddenMenu1", "Config") .param("hiddenMenu2", "Users")) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("access-control.hidden-menus.close")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("access-control.hidden-menus.close")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - public void HiddenMenusFailure() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/access-control/hidden-menu") + @Test + public void HiddenMenusFailure() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/access-control/hidden-menu") .param("hiddenMenu1", "Foo") .param("hiddenMenu2", "Bar")) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(pluginMessages.getMessage("access-control.hidden-menus.failure")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } - + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(pluginMessages.getMessage("access-control.hidden-menus.failure")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACUsersTest.java b/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACUsersTest.java index 2c0d9ac13..166d080e6 100644 --- a/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACUsersTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACUsersTest.java @@ -22,51 +22,58 @@ package org.owasp.webgoat.lessons.missingac; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.missingac.MissingFunctionAC; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + class MissingFunctionACUsersTest extends LessonTest { - @BeforeEach - void setup() { - when(webSession.getCurrentLesson()).thenReturn(new MissingFunctionAC()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + void setup() { + when(webSession.getCurrentLesson()).thenReturn(new MissingFunctionAC()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - void getUsers() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/access-control/users") + @Test + void getUsers() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/access-control/users") .header("Content-type", "application/json")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$[0].username", CoreMatchers.is("Tom"))) - .andExpect(jsonPath("$[0].userHash", CoreMatchers.is("Mydnhcy00j2b0m6SjmPz6PUxF9WIeO7tzm665GiZWCo="))) - .andExpect(jsonPath("$[0].admin", CoreMatchers.is(false))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].username", CoreMatchers.is("Tom"))) + .andExpect( + jsonPath( + "$[0].userHash", CoreMatchers.is("Mydnhcy00j2b0m6SjmPz6PUxF9WIeO7tzm665GiZWCo="))) + .andExpect(jsonPath("$[0].admin", CoreMatchers.is(false))); + } - @Test - void addUser() throws Exception { - var user = """ + @Test + void addUser() throws Exception { + var user = + """ {"username":"newUser","password":"newUser12","admin": "true"} """; - mockMvc.perform(MockMvcRequestBuilders.post("/access-control/users") - .header("Content-type", "application/json").content(user)) - .andExpect(status().isOk()); + mockMvc + .perform( + MockMvcRequestBuilders.post("/access-control/users") + .header("Content-type", "application/json") + .content(user)) + .andExpect(status().isOk()); - mockMvc.perform(MockMvcRequestBuilders.get("/access-control/users") + mockMvc + .perform( + MockMvcRequestBuilders.get("/access-control/users") .header("Content-type", "application/json")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.size()", is(4))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.size()", is(4))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHashAdminTest.java b/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHashAdminTest.java index 074a0b734..58fb063b0 100644 --- a/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHashAdminTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionACYourHashAdminTest.java @@ -1,44 +1,49 @@ package org.owasp.webgoat.lessons.missingac; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.missingac.DisplayUser; -import org.owasp.webgoat.lessons.missingac.MissingFunctionAC; -import org.owasp.webgoat.lessons.missingac.User; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - import static org.mockito.Mockito.when; import static org.owasp.webgoat.lessons.missingac.MissingFunctionAC.PASSWORD_SALT_ADMIN; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + class MissingFunctionACYourHashAdminTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new MissingFunctionAC()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new MissingFunctionAC()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - void solve() throws Exception { - var userHash = new DisplayUser(new User("Jerry", "doesnotreallymatter", true), PASSWORD_SALT_ADMIN).getUserHash(); - mockMvc.perform(MockMvcRequestBuilders.post("/access-control/user-hash-fix") + @Test + void solve() throws Exception { + var userHash = + new DisplayUser(new User("Jerry", "doesnotreallymatter", true), PASSWORD_SALT_ADMIN) + .getUserHash(); + mockMvc + .perform( + MockMvcRequestBuilders.post("/access-control/user-hash-fix") .param("userHash", userHash)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.containsString("Congrats! You really succeeded when you added the user."))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.containsString( + "Congrats! You really succeeded when you added the user."))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - void wrongUserHash() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/access-control/user-hash-fix") - .param("userHash", "wrong")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + @Test + void wrongUserHash() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/access-control/user-hash-fix").param("userHash", "wrong")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionYourHashTest.java b/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionYourHashTest.java index 7c01d2c3b..bfb859d53 100644 --- a/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionYourHashTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/missingac/MissingFunctionYourHashTest.java @@ -22,40 +22,40 @@ package org.owasp.webgoat.lessons.missingac; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.missingac.MissingFunctionAC; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + class MissingFunctionYourHashTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new MissingFunctionAC()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new MissingFunctionAC()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - void hashDoesNotMatch() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/access-control/user-hash") - .param("userHash", "42")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + @Test + void hashDoesNotMatch() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/access-control/user-hash").param("userHash", "42")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - void hashMatches() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/access-control/user-hash") + @Test + void hashMatches() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/access-control/user-hash") .param("userHash", "SVtOlaa+ER+w2eoIIVE5/77umvhcsh5V8UyDLUa1Itg=")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/passwordreset/SecurityQuestionAssignmentTest.java b/src/test/java/org/owasp/webgoat/lessons/passwordreset/SecurityQuestionAssignmentTest.java index 072acc6d7..3111becd0 100644 --- a/src/test/java/org/owasp/webgoat/lessons/passwordreset/SecurityQuestionAssignmentTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/passwordreset/SecurityQuestionAssignmentTest.java @@ -1,84 +1,112 @@ package org.owasp.webgoat.lessons.passwordreset; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.passwordreset.PasswordReset; import org.springframework.mock.web.MockHttpSession; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @ExtendWith(SpringExtension.class) public class SecurityQuestionAssignmentTest extends LessonTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new PasswordReset()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new PasswordReset()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void oneQuestionShouldNotSolveTheAssignment() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") + @Test + public void oneQuestionShouldNotSolveTheAssignment() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") .param("question", "What is your favorite animal?")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("password-questions-one-successful")))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))) - .andExpect(jsonPath("$.output", CoreMatchers.notNullValue())); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(messages.getMessage("password-questions-one-successful")))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))) + .andExpect(jsonPath("$.output", CoreMatchers.notNullValue())); + } - @Test - public void twoQuestionsShouldSolveTheAssignment() throws Exception { - MockHttpSession mocksession = new MockHttpSession(); - mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") - .param("question", "What is your favorite animal?").session(mocksession)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + @Test + public void twoQuestionsShouldSolveTheAssignment() throws Exception { + MockHttpSession mocksession = new MockHttpSession(); + mockMvc + .perform( + MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") + .param("question", "What is your favorite animal?") + .session(mocksession)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") - .param("question", "In what year was your mother born?").session(mocksession)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.solved")))) - .andExpect(jsonPath("$.output", CoreMatchers.notNullValue())) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + mockMvc + .perform( + MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") + .param("question", "In what year was your mother born?") + .session(mocksession)) + .andExpect(status().isOk()) + .andExpect( + jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.solved")))) + .andExpect(jsonPath("$.output", CoreMatchers.notNullValue())) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void answeringSameQuestionTwiceShouldNotSolveAssignment() throws Exception { - MockHttpSession mocksession = new MockHttpSession(); - mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") - .param("question", "What is your favorite animal?").session(mocksession)) - .andExpect(status().isOk()); - mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") - .param("question", "What is your favorite animal?").session(mocksession)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("password-questions-one-successful")))) - .andExpect(jsonPath("$.output", CoreMatchers.notNullValue())) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + @Test + public void answeringSameQuestionTwiceShouldNotSolveAssignment() throws Exception { + MockHttpSession mocksession = new MockHttpSession(); + mockMvc + .perform( + MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") + .param("question", "What is your favorite animal?") + .session(mocksession)) + .andExpect(status().isOk()); + mockMvc + .perform( + MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") + .param("question", "What is your favorite animal?") + .session(mocksession)) + .andExpect(status().isOk()) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.is(messages.getMessage("password-questions-one-successful")))) + .andExpect(jsonPath("$.output", CoreMatchers.notNullValue())) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - public void solvingForOneUserDoesNotSolveForOtherUser() throws Exception { - MockHttpSession mocksession = new MockHttpSession(); - mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") - .param("question", "What is your favorite animal?").session(mocksession)); - mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") - .param("question", "In what year was your mother born?").session(mocksession)) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + @Test + public void solvingForOneUserDoesNotSolveForOtherUser() throws Exception { + MockHttpSession mocksession = new MockHttpSession(); + mockMvc.perform( + MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") + .param("question", "What is your favorite animal?") + .session(mocksession)); + mockMvc + .perform( + MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") + .param("question", "In what year was your mother born?") + .session(mocksession)) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - MockHttpSession mocksession2 = new MockHttpSession(); - mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") - .param("question", "What is your favorite animal?").session(mocksession2)). - andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + MockHttpSession mocksession2 = new MockHttpSession(); + mockMvc + .perform( + MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions") + .param("question", "What is your favorite animal?") + .session(mocksession2)) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadFixTest.java b/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadFixTest.java index bce4228f0..6954035f6 100644 --- a/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadFixTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadFixTest.java @@ -1,55 +1,59 @@ package org.owasp.webgoat.lessons.pathtraversal; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.pathtraversal.PathTraversal; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.io.File; - import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.io.File; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class ProfileUploadFixTest extends LessonTest { - @BeforeEach - public void setup() { - Mockito.when(webSession.getCurrentLesson()).thenReturn(new PathTraversal()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - Mockito.when(webSession.getUserName()).thenReturn("unit-test"); - } + @BeforeEach + public void setup() { + Mockito.when(webSession.getCurrentLesson()).thenReturn(new PathTraversal()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + Mockito.when(webSession.getUserName()).thenReturn("unit-test"); + } - @Test - public void solve() throws Exception { - var profilePicture = new MockMultipartFile("uploadedFileFix", "../picture.jpg", "text/plain", "an image".getBytes()); + @Test + public void solve() throws Exception { + var profilePicture = + new MockMultipartFile( + "uploadedFileFix", "../picture.jpg", "text/plain", "an image".getBytes()); - mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-fix") + mockMvc + .perform( + MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-fix") .file(profilePicture) .param("fullNameFix", "..././John Doe")) - .andExpect(status().is(200)) - .andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUploadFix"))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().is(200)) + .andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUploadFix"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void normalUpdate() throws Exception { - var profilePicture = new MockMultipartFile("uploadedFileFix", "picture.jpg", "text/plain", "an image".getBytes()); + @Test + public void normalUpdate() throws Exception { + var profilePicture = + new MockMultipartFile( + "uploadedFileFix", "picture.jpg", "text/plain", "an image".getBytes()); - mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-fix") + mockMvc + .perform( + MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-fix") .file(profilePicture) .param("fullNameFix", "John Doe")) - .andExpect(status().is(200)) - .andExpect(jsonPath("$.feedback", CoreMatchers.containsString("unit-test\\"+File.separator+"John Doe"))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } - - + .andExpect(status().is(200)) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.containsString("unit-test\\" + File.separator + "John Doe"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRemoveUserInputTest.java b/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRemoveUserInputTest.java index ae10174d4..70eff86ed 100644 --- a/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRemoveUserInputTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRemoveUserInputTest.java @@ -1,54 +1,59 @@ package org.owasp.webgoat.lessons.pathtraversal; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.pathtraversal.PathTraversal; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.io.File; - import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.io.File; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class ProfileUploadRemoveUserInputTest extends LessonTest { - @BeforeEach - public void setup() { - Mockito.when(webSession.getCurrentLesson()).thenReturn(new PathTraversal()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - Mockito.when(webSession.getUserName()).thenReturn("unit-test"); - } + @BeforeEach + public void setup() { + Mockito.when(webSession.getCurrentLesson()).thenReturn(new PathTraversal()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + Mockito.when(webSession.getUserName()).thenReturn("unit-test"); + } - @Test - public void solve() throws Exception { - var profilePicture = new MockMultipartFile("uploadedFileRemoveUserInput", "../picture.jpg", "text/plain", "an image".getBytes()); + @Test + public void solve() throws Exception { + var profilePicture = + new MockMultipartFile( + "uploadedFileRemoveUserInput", "../picture.jpg", "text/plain", "an image".getBytes()); - mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-remove-user-input") + mockMvc + .perform( + MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-remove-user-input") .file(profilePicture) .param("fullNameFix", "John Doe")) - .andExpect(status().is(200)) - .andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUploadRemoveUserInput"))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().is(200)) + .andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUploadRemoveUserInput"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void normalUpdate() throws Exception { - var profilePicture = new MockMultipartFile("uploadedFileRemoveUserInput", "picture.jpg", "text/plain", "an image".getBytes()); + @Test + public void normalUpdate() throws Exception { + var profilePicture = + new MockMultipartFile( + "uploadedFileRemoveUserInput", "picture.jpg", "text/plain", "an image".getBytes()); - mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-remove-user-input") + mockMvc + .perform( + MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload-remove-user-input") .file(profilePicture) .param("fullNameFix", "John Doe")) - .andExpect(status().is(200)) - .andExpect(jsonPath("$.feedback", CoreMatchers.containsString("unit-test\\"+File.separator+"picture.jpg"))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } - + .andExpect(status().is(200)) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.containsString("unit-test\\" + File.separator + "picture.jpg"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrievalTest.java b/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrievalTest.java index dba1586bc..8772b717d 100644 --- a/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrievalTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadRetrievalTest.java @@ -1,21 +1,5 @@ package org.owasp.webgoat.lessons.pathtraversal; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.pathtraversal.PathTraversal; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; -import org.springframework.security.core.token.Sha512DigestUtils; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.result.MockMvcResultHandlers; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.io.File; -import java.net.URI; - import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.containsString; @@ -26,57 +10,75 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.io.File; +import java.net.URI; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.http.MediaType; +import org.springframework.security.core.token.Sha512DigestUtils; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class ProfileUploadRetrievalTest extends LessonTest { - @BeforeEach - public void setup() { - Mockito.when(webSession.getCurrentLesson()).thenReturn(new PathTraversal()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - Mockito.when(webSession.getUserName()).thenReturn("unit-test"); - } + @BeforeEach + public void setup() { + Mockito.when(webSession.getCurrentLesson()).thenReturn(new PathTraversal()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + Mockito.when(webSession.getUserName()).thenReturn("unit-test"); + } - @Test - public void solve() throws Exception { - //Look at the response - mockMvc.perform(get("/PathTraversal/random-picture")) - .andExpect(status().is(200)) - .andExpect(header().exists("Location")) - .andExpect(header().string("Location", containsString("?id="))) - .andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG)); + @Test + public void solve() throws Exception { + // Look at the response + mockMvc + .perform(get("/PathTraversal/random-picture")) + .andExpect(status().is(200)) + .andExpect(header().exists("Location")) + .andExpect(header().string("Location", containsString("?id="))) + .andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG)); - //Browse the directories - var uri = new URI("/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2F"); - mockMvc.perform(get(uri)) - .andExpect(status().is(404)) - //.andDo(MockMvcResultHandlers.print()) - .andExpect(content().string(containsString("path-traversal-secret.jpg"))); + // Browse the directories + var uri = new URI("/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2F"); + mockMvc + .perform(get(uri)) + .andExpect(status().is(404)) + // .andDo(MockMvcResultHandlers.print()) + .andExpect(content().string(containsString("path-traversal-secret.jpg"))); - //Retrieve the secret file (note: .jpg is added by the server) - uri = new URI("/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret"); - mockMvc.perform(get(uri)) - .andExpect(status().is(200)) - .andExpect(content().string("You found it submit the SHA-512 hash of your username as answer")) - .andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG)); + // Retrieve the secret file (note: .jpg is added by the server) + uri = new URI("/PathTraversal/random-picture?id=%2E%2E%2F%2E%2E%2Fpath-traversal-secret"); + mockMvc + .perform(get(uri)) + .andExpect(status().is(200)) + .andExpect( + content().string("You found it submit the SHA-512 hash of your username as answer")) + .andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG)); - //Post flag - mockMvc.perform(post("/PathTraversal/random").param("secret", Sha512DigestUtils.shaHex("unit-test"))) - .andExpect(status().is(200)) - .andExpect(jsonPath("$.assignment", equalTo("ProfileUploadRetrieval"))) - .andExpect(jsonPath("$.lessonCompleted", is(true))); - } + // Post flag + mockMvc + .perform( + post("/PathTraversal/random").param("secret", Sha512DigestUtils.shaHex("unit-test"))) + .andExpect(status().is(200)) + .andExpect(jsonPath("$.assignment", equalTo("ProfileUploadRetrieval"))) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void shouldReceiveRandomPicture() throws Exception { - mockMvc.perform(get("/PathTraversal/random-picture")) - .andExpect(status().is(200)) - .andExpect(header().exists("Location")) - .andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG)); - } + @Test + public void shouldReceiveRandomPicture() throws Exception { + mockMvc + .perform(get("/PathTraversal/random-picture")) + .andExpect(status().is(200)) + .andExpect(header().exists("Location")) + .andExpect(content().contentTypeCompatibleWith(MediaType.IMAGE_JPEG)); + } - @Test - public void unknownFileShouldGiveDirectoryContents() throws Exception { - mockMvc.perform(get("/PathTraversal/random-picture?id=test")) - .andExpect(status().is(404)) - .andExpect(content().string(containsString("cats" + File.separator + "8.jpg"))); - } + @Test + public void unknownFileShouldGiveDirectoryContents() throws Exception { + mockMvc + .perform(get("/PathTraversal/random-picture?id=test")) + .andExpect(status().is(404)) + .andExpect(content().string(containsString("cats" + File.separator + "8.jpg"))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadTest.java b/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadTest.java index a3932cc83..c44379e65 100644 --- a/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/pathtraversal/ProfileUploadTest.java @@ -1,79 +1,98 @@ package org.owasp.webgoat.lessons.pathtraversal; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mockito; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.pathtraversal.PathTraversal; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.mock.web.MockMultipartFile; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import java.io.File; - import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.io.File; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + public class ProfileUploadTest extends LessonTest { - @BeforeEach - public void setup() { - Mockito.when(webSession.getCurrentLesson()).thenReturn(new PathTraversal()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - Mockito.when(webSession.getUserName()).thenReturn("unit-test"); - } + @BeforeEach + public void setup() { + Mockito.when(webSession.getCurrentLesson()).thenReturn(new PathTraversal()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + Mockito.when(webSession.getUserName()).thenReturn("unit-test"); + } - @Test - public void solve() throws Exception { - var profilePicture = new MockMultipartFile("uploadedFile", "../picture.jpg", "text/plain", "an image".getBytes()); + @Test + public void solve() throws Exception { + var profilePicture = + new MockMultipartFile( + "uploadedFile", "../picture.jpg", "text/plain", "an image".getBytes()); - mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload") + mockMvc + .perform( + MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload") .file(profilePicture) .param("fullName", "../John Doe")) - .andExpect(status().is(200)) - .andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUpload"))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().is(200)) + .andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUpload"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void attemptWithWrongDirectory() throws Exception { - var profilePicture = new MockMultipartFile("uploadedFile", "../picture.jpg", "text/plain", "an image".getBytes()); + @Test + public void attemptWithWrongDirectory() throws Exception { + var profilePicture = + new MockMultipartFile( + "uploadedFile", "../picture.jpg", "text/plain", "an image".getBytes()); - mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload") + mockMvc + .perform( + MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload") .file(profilePicture) .param("fullName", "../../" + webSession.getUserName())) - .andExpect(status().is(200)) - .andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUpload"))) - .andExpect(jsonPath("$.feedback", CoreMatchers.containsString("Nice try"))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect(status().is(200)) + .andExpect(jsonPath("$.assignment", CoreMatchers.equalTo("ProfileUpload"))) + .andExpect(jsonPath("$.feedback", CoreMatchers.containsString("Nice try"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - public void shouldNotOverrideExistingFile() throws Exception { - var profilePicture = new MockMultipartFile("uploadedFile", "picture.jpg", "text/plain", "an image".getBytes()); - mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload") + @Test + public void shouldNotOverrideExistingFile() throws Exception { + var profilePicture = + new MockMultipartFile("uploadedFile", "picture.jpg", "text/plain", "an image".getBytes()); + mockMvc + .perform( + MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload") .file(profilePicture) - .param("fullName", ".."+File.separator + webSession.getUserName())) - .andExpect(jsonPath("$.output", CoreMatchers.anyOf( - CoreMatchers.containsString("Is a directory"), - CoreMatchers.containsString("..\\\\"+ webSession.getUserName())))) - .andExpect(status().is(200)); - } + .param("fullName", ".." + File.separator + webSession.getUserName())) + .andExpect( + jsonPath( + "$.output", + CoreMatchers.anyOf( + CoreMatchers.containsString("Is a directory"), + CoreMatchers.containsString("..\\\\" + webSession.getUserName())))) + .andExpect(status().is(200)); + } - @Test - public void normalUpdate() throws Exception { - var profilePicture = new MockMultipartFile("uploadedFile", "picture.jpg", "text/plain", "an image".getBytes()); + @Test + public void normalUpdate() throws Exception { + var profilePicture = + new MockMultipartFile("uploadedFile", "picture.jpg", "text/plain", "an image".getBytes()); - mockMvc.perform(MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload") + mockMvc + .perform( + MockMvcRequestBuilders.multipart("/PathTraversal/profile-upload") .file(profilePicture) .param("fullName", "John Doe")) - .andExpect(status().is(200)) - .andExpect(jsonPath("$.feedback", CoreMatchers.containsStringIgnoringCase("PathTraversal\\"+File.separator+"unit-test\\"+File.separator+"John Doe"))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } - + .andExpect(status().is(200)) + .andExpect( + jsonPath( + "$.feedback", + CoreMatchers.containsStringIgnoringCase( + "PathTraversal\\" + + File.separator + + "unit-test\\" + + File.separator + + "John Doe"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookieAssignmentTest.java b/src/test/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookieAssignmentTest.java index e0cdf3113..80cad9d0e 100644 --- a/src/test/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookieAssignmentTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/spoofcookie/SpoofCookieAssignmentTest.java @@ -22,6 +22,16 @@ package org.owasp.webgoat.lessons.spoofcookie; +import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.not; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + +import java.util.stream.Stream; +import javax.servlet.http.Cookie; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -37,17 +47,6 @@ import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import javax.servlet.http.Cookie; -import java.util.stream.Stream; - -import static org.hamcrest.Matchers.emptyString; -import static org.hamcrest.Matchers.not; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - /*** * * @author Angel Olle Blazquez @@ -57,148 +56,150 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal @ExtendWith(MockitoExtension.class) class SpoofCookieAssignmentTest extends AssignmentEndpointTest { - private MockMvc mockMvc; - private static final String COOKIE_NAME = "spoof_auth"; - private static final String LOGIN_CONTEXT_PATH = "/SpoofCookie/login"; - private static final String ERASE_COOKIE_CONTEXT_PATH = "/SpoofCookie/cleanup"; + private MockMvc mockMvc; + private static final String COOKIE_NAME = "spoof_auth"; + private static final String LOGIN_CONTEXT_PATH = "/SpoofCookie/login"; + private static final String ERASE_COOKIE_CONTEXT_PATH = "/SpoofCookie/cleanup"; - @BeforeEach - void setup() { - SpoofCookieAssignment spoofCookieAssignment = new SpoofCookieAssignment(); - init(spoofCookieAssignment); - mockMvc = standaloneSetup(spoofCookieAssignment).build(); - } + @BeforeEach + void setup() { + SpoofCookieAssignment spoofCookieAssignment = new SpoofCookieAssignment(); + init(spoofCookieAssignment); + mockMvc = standaloneSetup(spoofCookieAssignment).build(); + } - @Test - @DisplayName("Lesson completed") - void success() throws Exception { - Cookie cookie = new Cookie(COOKIE_NAME, "NjI2MTcwNGI3YTQxNGE1OTU2NzQ2ZDZmNzQ="); + @Test + @DisplayName("Lesson completed") + void success() throws Exception { + Cookie cookie = new Cookie(COOKIE_NAME, "NjI2MTcwNGI3YTQxNGE1OTU2NzQ2ZDZmNzQ="); - ResultActions result = mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .cookie(cookie) - .param("username", "") - .param("password", "")); + ResultActions result = + mockMvc.perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .cookie(cookie) + .param("username", "") + .param("password", "")); - result.andExpect(status().isOk()); - result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + result.andExpect(status().isOk()); + result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - } + @Test + @DisplayName("Valid credentials login without authentication cookie") + void validLoginWithoutCookieTest() throws Exception { + String username = "webgoat"; + String password = "webgoat"; - @Test - @DisplayName("Valid credentials login without authentication cookie") - void validLoginWithoutCookieTest() throws Exception { - String username = "webgoat"; - String password = "webgoat"; + ResultActions result = + mockMvc.perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .param("username", username) + .param("password", password)); - ResultActions result = mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .param("username", username) - .param("password", password)); + result.andExpect(status().isOk()); + result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + result.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)); + result.andExpect(cookie().value(COOKIE_NAME, not(emptyString()))); + } - result.andExpect(status().isOk()); - result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - result.andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE)); - result.andExpect(cookie().value(COOKIE_NAME, not(emptyString()))); + @ParameterizedTest + @MethodSource("providedCookieValues") + @DisplayName( + "Tests different invalid/valid -but not solved- cookie flow scenarios: " + + "1.- Invalid encoded cookie sent. " + + "2.- Valid cookie login (not tom) sent. " + + "3.- Valid cookie with not known username sent ") + void cookieLoginNotSolvedFlow(String cookieValue) throws Exception { + Cookie cookie = new Cookie(COOKIE_NAME, cookieValue); + mockMvc + .perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .cookie(cookie) + .param("username", "") + .param("password", "")) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - } + @Test + @DisplayName("UnsatisfiedServletRequestParameterException test for missing username") + void invalidLoginWithUnsatisfiedServletRequestParameterExceptionOnUsernameMissing() + throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH).param("password", "anypassword")) + .andExpect(status().is4xxClientError()); + } - @ParameterizedTest - @MethodSource("providedCookieValues") - @DisplayName("Tests different invalid/valid -but not solved- cookie flow scenarios: " - + "1.- Invalid encoded cookie sent. " - + "2.- Valid cookie login (not tom) sent. " - + "3.- Valid cookie with not known username sent ") - void cookieLoginNotSolvedFlow(String cookieValue) throws Exception { - Cookie cookie = new Cookie(COOKIE_NAME, cookieValue); - mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .cookie(cookie) - .param("username", "") - .param("password", "")) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + @Test + @DisplayName("UnsatisfiedServletRequestParameterException test for missing password") + void invalidLoginWithUnsatisfiedServletRequestParameterExceptionOnPasswordMissing() + throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH).param("username", "webgoat")) + .andExpect(status().is4xxClientError()); + } - @Test - @DisplayName("UnsatisfiedServletRequestParameterException test for missing username") - void invalidLoginWithUnsatisfiedServletRequestParameterExceptionOnUsernameMissing() throws Exception { - mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .param("password", "anypassword")) - .andExpect(status().is4xxClientError()); - } + @Test + @DisplayName("Invalid blank credentials login") + void invalidLoginWithBlankCredentials() throws Exception { + ResultActions result = + mockMvc.perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .param("username", "") + .param("password", "")); - @Test - @DisplayName("UnsatisfiedServletRequestParameterException test for missing password") - void invalidLoginWithUnsatisfiedServletRequestParameterExceptionOnPasswordMissing() throws Exception { - mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .param("username", "webgoat")) - .andExpect(status().is4xxClientError()); - } + result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - @DisplayName("Invalid blank credentials login") - void invalidLoginWithBlankCredentials() throws Exception { - ResultActions result = mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .param("username", "") - .param("password", "")); + @Test + @DisplayName("Invalid blank password login") + void invalidLoginWithBlankPassword() throws Exception { + ResultActions result = + mockMvc.perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .param("username", "webgoat") + .param("password", "")); - result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - } + @Test + @DisplayName("cheater test") + void cheat() throws Exception { + ResultActions result = + mockMvc.perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .param("username", "tom") + .param("password", "apasswordfortom")); - @Test - @DisplayName("Invalid blank password login") - void invalidLoginWithBlankPassword() throws Exception { - ResultActions result = mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .param("username", "webgoat") - .param("password", "")); + result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + @Test + @DisplayName("Invalid login with tom username") + void invalidTomLogin() throws Exception { + ResultActions result = + mockMvc.perform( + MockMvcRequestBuilders.post(LOGIN_CONTEXT_PATH) + .param("username", "tom") + .param("password", "")); - } + result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - @DisplayName("cheater test") - void cheat() throws Exception { - ResultActions result = mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .param("username", "tom") - .param("password", "apasswordfortom")); - - result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } - - @Test - @DisplayName("Invalid login with tom username") - void invalidTomLogin() throws Exception { - ResultActions result = mockMvc.perform(MockMvcRequestBuilders - .post(LOGIN_CONTEXT_PATH) - .param("username", "tom") - .param("password", "")); - - result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } - - @Test - @DisplayName("Erase authentication cookie") - void eraseAuthenticationCookie() throws Exception { - mockMvc.perform(MockMvcRequestBuilders - .get(ERASE_COOKIE_CONTEXT_PATH)) - .andExpect(status().isOk()) - .andExpect(cookie().maxAge(COOKIE_NAME, 0)) - .andExpect(cookie().value(COOKIE_NAME, "")); - - } - - private static Stream providedCookieValues() { - return Stream.of( - Arguments.of("NjI2MTcwNGI3YTQxNGE1OTUNzQ2ZDZmNzQ="), - Arguments.of("NjI2MTcwNGI3YTQxNGE1OTU2NzQ3NDYxNmY2NzYyNjU3Nw=="), - Arguments.of("NmQ0NjQ1Njc0NjY4NGY2Mjc0NjQ2YzY1Njc2ZTYx")); - } + @Test + @DisplayName("Erase authentication cookie") + void eraseAuthenticationCookie() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.get(ERASE_COOKIE_CONTEXT_PATH)) + .andExpect(status().isOk()) + .andExpect(cookie().maxAge(COOKIE_NAME, 0)) + .andExpect(cookie().value(COOKIE_NAME, "")); + } + private static Stream providedCookieValues() { + return Stream.of( + Arguments.of("NjI2MTcwNGI3YTQxNGE1OTUNzQ2ZDZmNzQ="), + Arguments.of("NjI2MTcwNGI3YTQxNGE1OTU2NzQ3NDYxNmY2NzYyNjU3Nw=="), + Arguments.of("NmQ0NjQ1Njc0NjY4NGY2Mjc0NjQ2YzY1Njc2ZTYx")); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/spoofcookie/encoders/EncDecTest.java b/src/test/java/org/owasp/webgoat/lessons/spoofcookie/encoders/EncDecTest.java index f2c9e4a4d..69d7df255 100644 --- a/src/test/java/org/owasp/webgoat/lessons/spoofcookie/encoders/EncDecTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/spoofcookie/encoders/EncDecTest.java @@ -28,13 +28,11 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.stream.Stream; - import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.owasp.webgoat.lessons.spoofcookie.encoders.EncDec; /*** * @@ -44,47 +42,47 @@ import org.owasp.webgoat.lessons.spoofcookie.encoders.EncDec; class EncDecTest { - @ParameterizedTest - @DisplayName("Encode test") - @MethodSource("providedForEncValues") - void testEncode(String decoded, String encoded) { - String result = EncDec.encode(decoded); + @ParameterizedTest + @DisplayName("Encode test") + @MethodSource("providedForEncValues") + void testEncode(String decoded, String encoded) { + String result = EncDec.encode(decoded); - assertTrue(result.endsWith(encoded)); - } + assertTrue(result.endsWith(encoded)); + } - @ParameterizedTest - @DisplayName("Decode test") - @MethodSource("providedForDecValues") - void testDecode(String decoded, String encoded) { - String result = EncDec.decode(encoded); + @ParameterizedTest + @DisplayName("Decode test") + @MethodSource("providedForDecValues") + void testDecode(String decoded, String encoded) { + String result = EncDec.decode(encoded); - assertThat(decoded, is(result)); - } + assertThat(decoded, is(result)); + } - @Test - @DisplayName("null encode test") - void testNullEncode() { - assertNull(EncDec.encode(null)); - } + @Test + @DisplayName("null encode test") + void testNullEncode() { + assertNull(EncDec.encode(null)); + } - @Test - @DisplayName("null decode test") - void testNullDecode() { - assertNull(EncDec.decode(null)); - } + @Test + @DisplayName("null decode test") + void testNullDecode() { + assertNull(EncDec.decode(null)); + } - private static Stream providedForEncValues() { - return Stream.of( - Arguments.of("webgoat", "YxNmY2NzYyNjU3Nw=="), - Arguments.of("admin", "2ZTY5NmQ2NDYx"), - Arguments.of("tom", "2ZDZmNzQ=")); - } + private static Stream providedForEncValues() { + return Stream.of( + Arguments.of("webgoat", "YxNmY2NzYyNjU3Nw=="), + Arguments.of("admin", "2ZTY5NmQ2NDYx"), + Arguments.of("tom", "2ZDZmNzQ=")); + } - private static Stream providedForDecValues() { - return Stream.of( - Arguments.of("webgoat", "NjI2MTcwNGI3YTQxNGE1OTU2NzQ3NDYxNmY2NzYyNjU3Nw=="), - Arguments.of("admin", "NjI2MTcwNGI3YTQxNGE1OTU2NzQ2ZTY5NmQ2NDYx"), - Arguments.of("tom", "NjI2MTcwNGI3YTQxNGE1OTU2NzQ2ZDZmNzQ=")); - } + private static Stream providedForDecValues() { + return Stream.of( + Arguments.of("webgoat", "NjI2MTcwNGI3YTQxNGE1OTU2NzQ3NDYxNmY2NzYyNjU3Nw=="), + Arguments.of("admin", "NjI2MTcwNGI3YTQxNGE1OTU2NzQ2ZTY5NmQ2NDYx"), + Arguments.of("tom", "NjI2MTcwNGI3YTQxNGE1OTU2NzQ2ZDZmNzQ=")); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/SqlLessonTest.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/SqlLessonTest.java index c14ac348c..b63767042 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/SqlLessonTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/SqlLessonTest.java @@ -22,21 +22,18 @@ package org.owasp.webgoat.lessons.sqlinjection; +import static org.mockito.Mockito.when; + import org.junit.jupiter.api.BeforeEach; import org.owasp.webgoat.container.plugins.LessonTest; import org.owasp.webgoat.lessons.sqlinjection.introduction.SqlInjection; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import static org.mockito.Mockito.when; - public class SqlLessonTest extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new SqlInjection()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } - - + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new SqlInjection()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10Test.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10Test.java index 9187aed6c..8bb4444e2 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson10Test.java @@ -22,52 +22,49 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.CoreMatchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + /** * @author Benedikt Stuhrmann * @since 11/07/18. */ public class SqlInjectionLesson10Test extends SqlLessonTest { - private String completedError = "JSON path \"lessonCompleted\""; + private String completedError = "JSON path \"lessonCompleted\""; - @Test - public void tableExistsIsFailure() throws Exception { - try { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack10") - .param("action_string", "")) + @Test + public void tableExistsIsFailure() throws Exception { + try { + mockMvc + .perform(MockMvcRequestBuilders.post("/SqlInjection/attack10").param("action_string", "")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.10.entries")))); + } catch (AssertionError e) { + if (!e.getMessage().contains(completedError)) throw e; - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.10.entries")))); - } catch (AssertionError e) { - if (!e.getMessage().contains(completedError)) throw e; - - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack10") - .param("action_string", "")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.10.success")))); - } + mockMvc + .perform(MockMvcRequestBuilders.post("/SqlInjection/attack10").param("action_string", "")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.10.success")))); } + } - @Test - public void tableMissingIsSuccess() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack10") + @Test + public void tableMissingIsSuccess() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack10") .param("action_string", "%'; DROP TABLE access_log;--")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.10.success")))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.10.success")))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson2Test.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson2Test.java index 010be19f3..c71cc2d6c 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson2Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson2Test.java @@ -22,23 +22,23 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + public class SqlInjectionLesson2Test extends SqlLessonTest { - @Test - public void solution() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack2") + @Test + public void solution() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack2") .param("query", "SELECT department FROM employees WHERE userid=96134;")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5Test.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5Test.java index 43f08cbb3..3dcaafbc8 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5Test.java @@ -22,52 +22,57 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; -import org.hamcrest.CoreMatchers; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.LessonDataSource; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - -import java.sql.SQLException; - import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import java.sql.SQLException; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.LessonDataSource; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + public class SqlInjectionLesson5Test extends SqlLessonTest { - @Autowired - private LessonDataSource dataSource; + @Autowired private LessonDataSource dataSource; - @AfterEach - public void removeGrant() throws SQLException { - dataSource.getConnection().prepareStatement("revoke select on grant_rights from unauthorized_user cascade").execute(); - } + @AfterEach + public void removeGrant() throws SQLException { + dataSource + .getConnection() + .prepareStatement("revoke select on grant_rights from unauthorized_user cascade") + .execute(); + } - @Test - public void grantSolution() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5") + @Test + public void grantSolution() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack5") .param("query", "grant select on grant_rights to unauthorized_user")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void differentTableShouldNotSolveIt() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5") + @Test + public void differentTableShouldNotSolveIt() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack5") .param("query", "grant select on users to unauthorized_user")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - @Test - public void noGrantShouldNotSolveIt() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5") + @Test + public void noGrantShouldNotSolveIt() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack5") .param("query", "select * from grant_rights")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5aTest.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5aTest.java index b08c7c142..db48b6643 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5aTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson5aTest.java @@ -22,66 +22,78 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + public class SqlInjectionLesson5aTest extends SqlLessonTest { - @Test - public void knownAccountShouldDisplayData() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") + @Test + public void knownAccountShouldDisplayData() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/assignment5a") .param("account", "Smith") .param("operator", "") .param("injection", "")) - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("assignment.not.solved")))) - .andExpect(jsonPath("$.output", containsString("

USERID, FIRST_NAME"))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("assignment.not.solved")))) + .andExpect(jsonPath("$.output", containsString("

USERID, FIRST_NAME"))); + } - @Disabled - @Test - public void unknownAccount() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") + @Disabled + @Test + public void unknownAccount() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/assignment5a") .param("account", "Smith") - .param("operator", "").param("injection", "")) - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("NoResultsMatched")))) - .andExpect(jsonPath("$.output").doesNotExist()); - } + .param("operator", "") + .param("injection", "")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("NoResultsMatched")))) + .andExpect(jsonPath("$.output").doesNotExist()); + } - @Test - public void sqlInjection() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") + @Test + public void sqlInjection() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/assignment5a") .param("account", "'") .param("operator", "OR") .param("injection", "'1' = '1")) - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", containsString("You have succeed"))) - .andExpect(jsonPath("$.output").exists()); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", containsString("You have succeed"))) + .andExpect(jsonPath("$.output").exists()); + } - @Test - public void sqlInjectionWrongShouldDisplayError() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") + @Test + public void sqlInjectionWrongShouldDisplayError() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/assignment5a") .param("account", "Smith'") .param("operator", "OR") .param("injection", "'1' = '1'")) - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", containsString(messages.getMessage("assignment.not.solved")))) - .andExpect(jsonPath("$.output", is("malformed string: '1''
Your query was: SELECT * FROM user_data WHERE" + - " first_name = 'John' and last_name = 'Smith' OR '1' = '1''"))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect( + jsonPath("$.feedback", containsString(messages.getMessage("assignment.not.solved")))) + .andExpect( + jsonPath( + "$.output", + is( + "malformed string: '1''
Your query was: SELECT * FROM user_data WHERE" + + " first_name = 'John' and last_name = 'Smith' OR '1' = '1''"))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson6aTest.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson6aTest.java index a9020ee7f..4ca0469b8 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson6aTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson6aTest.java @@ -22,72 +22,89 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; -import org.junit.jupiter.api.Test; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + public class SqlInjectionLesson6aTest extends SqlLessonTest { - @Test - public void wrongSolution() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") + @Test + public void wrongSolution() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") .param("userid_6a", "John")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(false))); - } + @Test + public void wrongNumberOfColumns() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") + .param( + "userid_6a", + "Smith' union select userid,user_name, password,cookie from user_system_data" + + " --")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))) + .andExpect( + jsonPath( + "$.output", + containsString( + "column number mismatch detected in rows of UNION, INTERSECT, EXCEPT, or VALUES" + + " operation"))); + } - @Test - public void wrongNumberOfColumns() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") - .param("userid_6a", "Smith' union select userid,user_name, password,cookie from user_system_data --")) + @Test + public void wrongDataTypeOfColumns() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") + .param( + "userid_6a", + "Smith' union select 1,password, 1,'2','3', '4',1 from user_system_data --")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))) + .andExpect(jsonPath("$.output", containsString("incompatible data types in combination"))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(false))) - .andExpect(jsonPath("$.output", containsString("column number mismatch detected in rows of UNION, INTERSECT, EXCEPT, or VALUES operation"))); - } - - @Test - public void wrongDataTypeOfColumns() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") - .param("userid_6a", "Smith' union select 1,password, 1,'2','3', '4',1 from user_system_data --")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(false))) - .andExpect(jsonPath("$.output", containsString("incompatible data types in combination"))); - } - - @Test - public void correctSolution() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") + @Test + public void correctSolution() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") .param("userid_6a", "Smith'; SELECT * from user_system_data; --")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", containsString("passW0rD"))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", containsString("passW0rD"))); + } - @Test - public void noResultsReturned() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") + @Test + public void noResultsReturned() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") .param("userid_6a", "Smith' and 1 = 2 --")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.6a.no.results")))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.6a.no.results")))); - } - - @Test - public void noUnionUsed() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") + @Test + public void noUnionUsed() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6a") .param("userid_6a", "S'; Select * from user_system_data; --")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", containsString("UNION"))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", containsString("UNION"))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson6bTest.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson6bTest.java index 043bc2e23..6bb702178 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson6bTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson6bTest.java @@ -22,32 +22,33 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + public class SqlInjectionLesson6bTest extends SqlLessonTest { - @Test - public void submitCorrectPassword() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6b") + @Test + public void submitCorrectPassword() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6b") .param("userid_6b", "passW0rD")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); - } - - @Test - public void submitWrongPassword() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6b") + @Test + public void submitWrongPassword() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionAdvanced/attack6b") .param("userid_6b", "John")) - - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); - } - + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8Test.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8Test.java index f53768e34..8ab7e242e 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson8Test.java @@ -22,79 +22,86 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + /** * @author Benedikt Stuhrmann * @since 11/07/18. */ public class SqlInjectionLesson8Test extends SqlLessonTest { - @Test - public void oneAccount() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack8") + @Test + public void oneAccount() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack8") .param("name", "Smith") .param("auth_tan", "3SL99A")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.one")))) + .andExpect(jsonPath("$.output", containsString("
"))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.one")))) - .andExpect(jsonPath("$.output", containsString("
"))); - } - - @Test - public void multipleAccounts() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack8") + @Test + public void multipleAccounts() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack8") .param("name", "Smith") .param("auth_tan", "3SL99A' OR '1' = '1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.success")))) + .andExpect( + jsonPath( + "$.output", + containsString( + "
96134<\\/td>Bob<\\/td>Franco<\\/td>Marketing<\\/td>83700<\\/td>LO9S2V<\\/td><\\/tr>"))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.success")))) - .andExpect(jsonPath("$.output", containsString("
96134<\\/td>Bob<\\/td>Franco<\\/td>Marketing<\\/td>83700<\\/td>LO9S2V<\\/td><\\/tr>"))); - } - - @Test - public void wrongNameReturnsNoAccounts() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack8") + @Test + public void wrongNameReturnsNoAccounts() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack8") .param("name", "Smithh") .param("auth_tan", "3SL99A")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results")))) + .andExpect(jsonPath("$.output").doesNotExist()); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results")))) - .andExpect(jsonPath("$.output").doesNotExist()); - } - - @Test - public void wrongTANReturnsNoAccounts() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack8") + @Test + public void wrongTANReturnsNoAccounts() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack8") .param("name", "Smithh") .param("auth_tan", "")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results")))) + .andExpect(jsonPath("$.output").doesNotExist()); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results")))) - .andExpect(jsonPath("$.output").doesNotExist()); - } - - @Test - public void malformedQueryReturnsError() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack8") + @Test + public void malformedQueryReturnsError() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack8") .param("name", "Smith") .param("auth_tan", "3SL99A' OR '1' = '1'")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.output", containsString("feedback-negative"))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.output", containsString("feedback-negative"))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9Test.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9Test.java index baf3c9746..4cd0c368f 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/introduction/SqlInjectionLesson9Test.java @@ -22,158 +22,177 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + /** * @author Benedikt Stuhrmann * @since 11/07/18. */ public class SqlInjectionLesson9Test extends SqlLessonTest { - private String completedError = "JSON path \"lessonCompleted\""; + private String completedError = "JSON path \"lessonCompleted\""; - @Test - public void oneAccount() throws Exception { - try { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smith") - .param("auth_tan", "3SL99A")) + @Test + public void oneAccount() throws Exception { + try { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smith") + .param("auth_tan", "3SL99A")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one")))) + .andExpect(jsonPath("$.output", containsString("
"))); + } catch (AssertionError e) { + if (!e.getMessage().contains(completedError)) throw e; - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one")))) - .andExpect(jsonPath("$.output", containsString("
"))); - } catch (AssertionError e) { - if (!e.getMessage().contains(completedError)) throw e; - - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smith") - .param("auth_tan", "3SL99A")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) - .andExpect(jsonPath("$.output", containsString("
"))); - } + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smith") + .param("auth_tan", "3SL99A")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) + .andExpect(jsonPath("$.output", containsString("
"))); } + } - @Test - public void multipleAccounts() throws Exception { - try { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smith") - .param("auth_tan", "3SL99A' OR '1' = '1")) + @Test + public void multipleAccounts() throws Exception { + try { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smith") + .param("auth_tan", "3SL99A' OR '1' = '1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one")))) + .andExpect( + jsonPath( + "$.output", + containsString( + "
96134<\\/td>Bob<\\/td>Franco<\\/td>Marketing<\\/td>83700<\\/td>LO9S2V<\\/td><\\/tr>"))); + } catch (AssertionError e) { + if (!e.getMessage().contains(completedError)) throw e; - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one")))) - .andExpect(jsonPath("$.output", containsString("
96134<\\/td>Bob<\\/td>Franco<\\/td>Marketing<\\/td>83700<\\/td>LO9S2V<\\/td><\\/tr>"))); - } catch (AssertionError e) { - if (!e.getMessage().contains(completedError)) throw e; - - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smith") - .param("auth_tan", "3SL99A' OR '1' = '1")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) - .andExpect(jsonPath("$.output", containsString("
96134<\\/td>Bob<\\/td>Franco<\\/td>Marketing<\\/td>83700<\\/td>LO9S2V<\\/td><\\/tr>"))); - } + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smith") + .param("auth_tan", "3SL99A' OR '1' = '1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) + .andExpect( + jsonPath( + "$.output", + containsString( + "
96134<\\/td>Bob<\\/td>Franco<\\/td>Marketing<\\/td>83700<\\/td>LO9S2V<\\/td><\\/tr>"))); } + } - @Test - public void wrongNameReturnsNoAccounts() throws Exception { - try { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smithh") - .param("auth_tan", "3SL99A")) + @Test + public void wrongNameReturnsNoAccounts() throws Exception { + try { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smithh") + .param("auth_tan", "3SL99A")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results")))) + .andExpect(jsonPath("$.output").doesNotExist()); + } catch (AssertionError e) { + if (!e.getMessage().contains(completedError)) throw e; - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results")))) - .andExpect(jsonPath("$.output").doesNotExist()); - } catch (AssertionError e) { - if (!e.getMessage().contains(completedError)) throw e; - - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smithh") - .param("auth_tan", "3SL99A")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.success")))) - .andExpect(jsonPath("$.output").doesNotExist()); - } + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smithh") + .param("auth_tan", "3SL99A")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.success")))) + .andExpect(jsonPath("$.output").doesNotExist()); } + } - @Test - public void wrongTANReturnsNoAccounts() throws Exception { - try { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smithh") - .param("auth_tan", "")) + @Test + public void wrongTANReturnsNoAccounts() throws Exception { + try { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smithh") + .param("auth_tan", "")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results")))) + .andExpect(jsonPath("$.output").doesNotExist()); + } catch (AssertionError e) { + if (!e.getMessage().contains(completedError)) throw e; - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results")))) - .andExpect(jsonPath("$.output").doesNotExist()); - } catch (AssertionError e) { - if (!e.getMessage().contains(completedError)) throw e; - - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smithh") - .param("auth_tan", "")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) - .andExpect(jsonPath("$.output").doesNotExist()); - } + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smithh") + .param("auth_tan", "")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) + .andExpect(jsonPath("$.output").doesNotExist()); } + } - @Test - public void malformedQueryReturnsError() throws Exception { - try { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smith") - .param("auth_tan", "3SL99A' OR '1' = '1'")) + @Test + public void malformedQueryReturnsError() throws Exception { + try { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smith") + .param("auth_tan", "3SL99A' OR '1' = '1'")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.output", containsString("feedback-negative"))); + } catch (AssertionError e) { + if (!e.getMessage().contains(completedError)) throw e; - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.output", containsString("feedback-negative"))); - } catch (AssertionError e) { - if (!e.getMessage().contains(completedError)) throw e; - - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") - .param("name", "Smith") - .param("auth_tan", "3SL99A' OR '1' = '1'")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) - .andExpect(jsonPath("$.output", containsString("feedback-negative"))); - } + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") + .param("name", "Smith") + .param("auth_tan", "3SL99A' OR '1' = '1'")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) + .andExpect(jsonPath("$.output", containsString("feedback-negative"))); } + } - @Test - public void SmithIsMostEarningCompletesAssignment() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack9") + @Test + public void SmithIsMostEarningCompletesAssignment() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjection/attack9") .param("name", "Smith") - .param("auth_tan", "3SL99A'; UPDATE employees SET salary = '300000' WHERE last_name = 'Smith")) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) - .andExpect(jsonPath("$.output", containsString("300000"))); - } + .param( + "auth_tan", + "3SL99A'; UPDATE employees SET salary = '300000' WHERE last_name = 'Smith")) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success")))) + .andExpect(jsonPath("$.output", containsString("300000"))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson13Test.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson13Test.java index 333a93515..c319ba89e 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson13Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlInjectionLesson13Test.java @@ -1,102 +1,138 @@ package org.owasp.webgoat.lessons.sqlinjection.mitigation; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + /** * @author nbaars * @since 5/21/17. */ public class SqlInjectionLesson13Test extends SqlLessonTest { - @Test - public void knownAccountShouldDisplayData() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") - .param("column", "id")) + @Test + public void knownAccountShouldDisplayData() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers").param("column", "id")) + .andExpect(status().isOk()); + } - .andExpect(status().isOk()); - } + @Test + public void addressCorrectShouldOrderByHostname() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") + .param( + "column", + "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '104.%'" + + " THEN hostname ELSE id END")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); + } - @Test - public void addressCorrectShouldOrderByHostname() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") - .param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '104.%' THEN hostname ELSE id END")) + @Test + public void addressCorrectShouldOrderByHostnameUsingSubstr() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") + .param( + "column", + "case when (select ip from servers where hostname='webgoat-prd' and" + + " substr(ip,1,1) = '1') IS NOT NULL then hostname else id end")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); - .andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); - } + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") + .param( + "column", + "case when (select ip from servers where hostname='webgoat-prd' and" + + " substr(ip,2,1) = '0') IS NOT NULL then hostname else id end")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); - @Test - public void addressCorrectShouldOrderByHostnameUsingSubstr() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") - .param("column", "case when (select ip from servers where hostname='webgoat-prd' and substr(ip,1,1) = '1') IS NOT NULL then hostname else id end")) + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") + .param( + "column", + "case when (select ip from servers where hostname='webgoat-prd' and" + + " substr(ip,3,1) = '4') IS NOT NULL then hostname else id end")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); + } - .andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); + @Test + public void addressIncorrectShouldOrderByIdUsingSubstr() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") + .param( + "column", + "case when (select ip from servers where hostname='webgoat-prd' and" + + " substr(ip,1,1) = '9') IS NOT NULL then hostname else id end")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hostname", is("webgoat-dev"))); + } - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") - .param("column", "case when (select ip from servers where hostname='webgoat-prd' and substr(ip,2,1) = '0') IS NOT NULL then hostname else id end")) - - .andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); - - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") - .param("column", "case when (select ip from servers where hostname='webgoat-prd' and substr(ip,3,1) = '4') IS NOT NULL then hostname else id end")) - - .andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); - } - - @Test - public void addressIncorrectShouldOrderByIdUsingSubstr() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") - .param("column", "case when (select ip from servers where hostname='webgoat-prd' and substr(ip,1,1) = '9') IS NOT NULL then hostname else id end")) - - .andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-dev"))); - } - - @Test - public void trueShouldSortByHostname() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") + @Test + public void trueShouldSortByHostname() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") .param("column", "(case when (true) then hostname else id end)")) + .andExpect(status().isOk()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); + } - .andExpect(status().isOk()) - .andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); - } - - @Test - public void falseShouldSortById() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") + @Test + public void falseShouldSortById() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") .param("column", "(case when (true) then hostname else id end)")) + .andExpect(status().isOk()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); + } - .andExpect(status().isOk()) - .andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc"))); - } + @Test + public void addressIncorrectShouldOrderByHostname() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") + .param( + "column", + "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '192.%'" + + " THEN hostname ELSE id END")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$[0].hostname", is("webgoat-dev"))); + } - @Test - public void addressIncorrectShouldOrderByHostname() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjectionMitigations/servers") - .param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '192.%' THEN hostname ELSE id END")) - - .andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-dev"))); - } - - @Test - public void postingCorrectAnswerShouldPassTheLesson() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionMitigations/attack12a") + @Test + public void postingCorrectAnswerShouldPassTheLesson() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionMitigations/attack12a") .param("ip", "104.130.219.202")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); - } - - @Test - public void postingWrongAnswerShouldNotPassTheLesson() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjectionMitigations/attack12a") + @Test + public void postingWrongAnswerShouldNotPassTheLesson() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlInjectionMitigations/attack12a") .param("ip", "192.168.219.202")) - - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); - } + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywordsTest.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywordsTest.java index 1b71b8a3f..c160f2a94 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywordsTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationOnKeywordsTest.java @@ -1,33 +1,45 @@ package org.owasp.webgoat.lessons.sqlinjection.mitigation; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + public class SqlOnlyInputValidationOnKeywordsTest extends SqlLessonTest { - @Test - public void solve() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlOnlyInputValidationOnKeywords/attack") - .param("userid_sql_only_input_validation_on_keywords", "Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", containsString("passW0rD"))); - } + @Test + public void solve() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlOnlyInputValidationOnKeywords/attack") + .param( + "userid_sql_only_input_validation_on_keywords", + "Smith';SESELECTLECT/**/*/**/FRFROMOM/**/user_system_data;--")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", containsString("passW0rD"))); + } - @Test - public void containsForbiddenSqlKeyword() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlOnlyInputValidationOnKeywords/attack") - .param("userid_sql_only_input_validation_on_keywords", "Smith';SELECT/**/*/**/from/**/user_system_data;--")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(false))) - .andExpect(jsonPath("$.output", containsString("unexpected token: *
Your query was: SELECT * FROM user_data WHERE last_name = 'SMITH';\\\\\\/**\\\\\\/*\\\\\\/**\\\\\\/\\\\\\/**\\\\\\/USER_SYSTEM_DATA;--'"))); - } + @Test + public void containsForbiddenSqlKeyword() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlOnlyInputValidationOnKeywords/attack") + .param( + "userid_sql_only_input_validation_on_keywords", + "Smith';SELECT/**/*/**/from/**/user_system_data;--")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))) + .andExpect( + jsonPath( + "$.output", + containsString( + "unexpected token: *
Your query was: SELECT * FROM user_data WHERE" + + " last_name =" + + " 'SMITH';\\\\\\/**\\\\\\/*\\\\\\/**\\\\\\/\\\\\\/**\\\\\\/USER_SYSTEM_DATA;--'"))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationTest.java b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationTest.java index 323fcb301..48888f3de 100644 --- a/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/sqlinjection/mitigation/SqlOnlyInputValidationTest.java @@ -1,33 +1,38 @@ package org.owasp.webgoat.lessons.sqlinjection.mitigation; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; - import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.lessons.sqlinjection.SqlLessonTest; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + public class SqlOnlyInputValidationTest extends SqlLessonTest { - @Test - public void solve() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlOnlyInputValidation/attack") - .param("userid_sql_only_input_validation", "Smith';SELECT/**/*/**/from/**/user_system_data;--")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", containsString("passW0rD"))); - } + @Test + public void solve() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlOnlyInputValidation/attack") + .param( + "userid_sql_only_input_validation", + "Smith';SELECT/**/*/**/from/**/user_system_data;--")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", containsString("passW0rD"))); + } - @Test - public void containsSpace() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SqlOnlyInputValidation/attack") - .param("userid_sql_only_input_validation", "Smith' ;SELECT from user_system_data;--")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", containsString("Using spaces is not allowed!"))); - } + @Test + public void containsSpace() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/SqlOnlyInputValidation/attack") + .param( + "userid_sql_only_input_validation", "Smith' ;SELECT from user_system_data;--")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", containsString("Using spaces is not allowed!"))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/ssrf/SSRFTest1.java b/src/test/java/org/owasp/webgoat/lessons/ssrf/SSRFTest1.java index a87ef50ab..80c29e6dd 100644 --- a/src/test/java/org/owasp/webgoat/lessons/ssrf/SSRFTest1.java +++ b/src/test/java/org/owasp/webgoat/lessons/ssrf/SSRFTest1.java @@ -1,51 +1,52 @@ package org.owasp.webgoat.lessons.ssrf; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.ssrf.SSRF; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + /** - * @author afry + * @author afry * @since 12/28/18. */ @ExtendWith(SpringExtension.class) public class SSRFTest1 extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new SSRF()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new SSRF()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void modifyUrlTom() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SSRF/task1") - .param("url", "images/tom.png")) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); - } + @Test + public void modifyUrlTom() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/SSRF/task1").param("url", "images/tom.png")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } - @Test - public void modifyUrlJerry() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SSRF/task1") - .param("url", "images/jerry.png")) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); - } + @Test + public void modifyUrlJerry() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/SSRF/task1").param("url", "images/jerry.png")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void modifyUrlCat() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SSRF/task1") - .param("url", "images/cat.jpg")) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); - } + @Test + public void modifyUrlCat() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/SSRF/task1").param("url", "images/cat.jpg")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/ssrf/SSRFTest2.java b/src/test/java/org/owasp/webgoat/lessons/ssrf/SSRFTest2.java index 3820dc704..4f689ef5e 100644 --- a/src/test/java/org/owasp/webgoat/lessons/ssrf/SSRFTest2.java +++ b/src/test/java/org/owasp/webgoat/lessons/ssrf/SSRFTest2.java @@ -22,45 +22,45 @@ package org.owasp.webgoat.lessons.ssrf; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.owasp.webgoat.container.plugins.LessonTest; -import org.owasp.webgoat.lessons.ssrf.SSRF; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.owasp.webgoat.container.plugins.LessonTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + /** - * @author afry + * @author afry * @since 12/28/18. */ @ExtendWith(SpringExtension.class) public class SSRFTest2 extends LessonTest { - @BeforeEach - public void setup() { - when(webSession.getCurrentLesson()).thenReturn(new SSRF()); - this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); - } + @BeforeEach + public void setup() { + when(webSession.getCurrentLesson()).thenReturn(new SSRF()); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } - @Test - public void modifyUrlIfconfigPro() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SSRF/task2") - .param("url", "http://ifconfig.pro")) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true))); - } + @Test + public void modifyUrlIfconfigPro() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/SSRF/task2").param("url", "http://ifconfig.pro")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(true))); + } - @Test - public void modifyUrlCat() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/SSRF/task2") - .param("url", "images/cat.jpg")) - .andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false))); - } + @Test + public void modifyUrlCat() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post("/SSRF/task2").param("url", "images/cat.jpg")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLessonTest.java b/src/test/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLessonTest.java index eed97faab..3c8c69711 100644 --- a/src/test/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLessonTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/vulnerablecomponents/VulnerableComponentsLessonTest.java @@ -22,60 +22,63 @@ package org.owasp.webgoat.lessons.vulnerablecomponents; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.StreamException; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.owasp.webgoat.lessons.vulnerablecomponents.Contact; -import org.owasp.webgoat.lessons.vulnerablecomponents.ContactImpl; - import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.StreamException; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + public class VulnerableComponentsLessonTest { - String strangeContact = "\n" + - "org.owasp.webgoat.vulnerablecomponents.Contact\n" + - " \n" + - " \n" + - " \n" + - " calc.exe\n" + - " \n" + - " \n" + - " start\n" + - " \n" + - ""; - String contact = "\n"+ - ""; - - @Test - public void testTransformation() throws Exception { - XStream xstream = new XStream(); - xstream.setClassLoader(Contact.class.getClassLoader()); - xstream.alias("contact", ContactImpl.class); - xstream.ignoreUnknownElements(); - assertNotNull(xstream.fromXML(contact)); - } - - @Test - @Disabled - public void testIllegalTransformation() throws Exception { - XStream xstream = new XStream(); - xstream.setClassLoader(Contact.class.getClassLoader()); - xstream.alias("contact", ContactImpl.class); - xstream.ignoreUnknownElements(); - Exception e = assertThrows(RuntimeException.class, ()->((Contact)xstream.fromXML(strangeContact)).getFirstName()); - assertTrue(e.getCause().getMessage().contains("calc.exe")); - } - - @Test - public void testIllegalPayload() throws Exception { - XStream xstream = new XStream(); - xstream.setClassLoader(Contact.class.getClassLoader()); - xstream.alias("contact", ContactImpl.class); - xstream.ignoreUnknownElements(); - Exception e = assertThrows(StreamException.class, ()->((Contact)xstream.fromXML("bullssjfs")).getFirstName()); - assertTrue(e.getCause().getMessage().contains("START_DOCUMENT")); - } + String strangeContact = + "\n" + + "org.owasp.webgoat.vulnerablecomponents.Contact\n" + + " \n" + + " \n" + + " \n" + + " calc.exe\n" + + " \n" + + " \n" + + " start\n" + + " \n" + + ""; + String contact = "\n" + ""; + + @Test + public void testTransformation() throws Exception { + XStream xstream = new XStream(); + xstream.setClassLoader(Contact.class.getClassLoader()); + xstream.alias("contact", ContactImpl.class); + xstream.ignoreUnknownElements(); + assertNotNull(xstream.fromXML(contact)); + } + + @Test + @Disabled + public void testIllegalTransformation() throws Exception { + XStream xstream = new XStream(); + xstream.setClassLoader(Contact.class.getClassLoader()); + xstream.alias("contact", ContactImpl.class); + xstream.ignoreUnknownElements(); + Exception e = + assertThrows( + RuntimeException.class, + () -> ((Contact) xstream.fromXML(strangeContact)).getFirstName()); + assertTrue(e.getCause().getMessage().contains("calc.exe")); + } + + @Test + public void testIllegalPayload() throws Exception { + XStream xstream = new XStream(); + xstream.setClassLoader(Contact.class.getClassLoader()); + xstream.alias("contact", ContactImpl.class); + xstream.ignoreUnknownElements(); + Exception e = + assertThrows( + StreamException.class, () -> ((Contact) xstream.fromXML("bullssjfs")).getFirstName()); + assertTrue(e.getCause().getMessage().contains("START_DOCUMENT")); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson1Test.java b/src/test/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson1Test.java index f137c66d2..3f5f1d22e 100644 --- a/src/test/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson1Test.java +++ b/src/test/java/org/owasp/webgoat/lessons/xss/CrossSiteScriptingLesson1Test.java @@ -23,6 +23,10 @@ package org.owasp.webgoat.lessons.xss; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -33,44 +37,36 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - /** - * * @author Angel Olle Blazquez - * */ - @ExtendWith(MockitoExtension.class) class CrossSiteScriptingLesson1Test extends AssignmentEndpointTest { - private static final String CONTEXT_PATH = "/CrossSiteScripting/attack1"; + private static final String CONTEXT_PATH = "/CrossSiteScripting/attack1"; - @Autowired - private MockMvc mockMvc; + @Autowired private MockMvc mockMvc; - @BeforeEach - public void setup() { - CrossSiteScriptingLesson1 crossSiteScriptingLesson1 = new CrossSiteScriptingLesson1(); - init(crossSiteScriptingLesson1); - mockMvc = standaloneSetup(crossSiteScriptingLesson1).build(); - } + @BeforeEach + public void setup() { + CrossSiteScriptingLesson1 crossSiteScriptingLesson1 = new CrossSiteScriptingLesson1(); + init(crossSiteScriptingLesson1); + mockMvc = standaloneSetup(crossSiteScriptingLesson1).build(); + } - @Test - void success() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post(CONTEXT_PATH) - .param("checkboxAttack1", "value")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } - - @Test - void failure() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post(CONTEXT_PATH)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } + @Test + void success() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post(CONTEXT_PATH).param("checkboxAttack1", "value")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } + @Test + void failure() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.post(CONTEXT_PATH)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/xss/DOMCrossSiteScriptingTest.java b/src/test/java/org/owasp/webgoat/lessons/xss/DOMCrossSiteScriptingTest.java index 17163e109..77122ba95 100644 --- a/src/test/java/org/owasp/webgoat/lessons/xss/DOMCrossSiteScriptingTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/xss/DOMCrossSiteScriptingTest.java @@ -22,56 +22,57 @@ package org.owasp.webgoat.lessons.xss; +import static org.mockito.Mockito.lenient; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.owasp.webgoat.container.assignments.AssignmentEndpointTest; -import org.owasp.webgoat.lessons.xss.CrossSiteScripting; -import org.owasp.webgoat.lessons.xss.DOMCrossSiteScripting; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.mockito.Mockito.lenient; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - - @ExtendWith(MockitoExtension.class) public class DOMCrossSiteScriptingTest extends AssignmentEndpointTest { - private MockMvc mockMvc; - private String randVal = "12034837"; + private MockMvc mockMvc; + private String randVal = "12034837"; - @BeforeEach - public void setup() { - DOMCrossSiteScripting domXss = new DOMCrossSiteScripting(); - init(domXss); - this.mockMvc = standaloneSetup(domXss).build(); - CrossSiteScripting xss = new CrossSiteScripting(); - lenient().when(userSessionData.getValue("randValue")).thenReturn(randVal); - } + @BeforeEach + public void setup() { + DOMCrossSiteScripting domXss = new DOMCrossSiteScripting(); + init(domXss); + this.mockMvc = standaloneSetup(domXss).build(); + CrossSiteScripting xss = new CrossSiteScripting(); + lenient().when(userSessionData.getValue("randValue")).thenReturn(randVal); + } - @Test - public void success() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScripting/phone-home-xss") + @Test + public void success() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/CrossSiteScripting/phone-home-xss") .header("webgoat-requested-by", "dom-xss-vuln") .param("param1", "42") .param("param2", "24")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.output", CoreMatchers.containsString("phoneHome Response is " + randVal))) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); - } + .andExpect(status().isOk()) + .andExpect( + jsonPath("$.output", CoreMatchers.containsString("phoneHome Response is " + randVal))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void failure() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScripting/phone-home-xss") + @Test + public void failure() throws Exception { + mockMvc + .perform( + MockMvcRequestBuilders.post("/CrossSiteScripting/phone-home-xss") .header("webgoat-requested-by", "wrong-value") .param("param1", "22") .param("param2", "20")) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); - } - + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } } diff --git a/src/test/java/org/owasp/webgoat/lessons/xss/StoredXssCommentsTest.java b/src/test/java/org/owasp/webgoat/lessons/xss/StoredXssCommentsTest.java index a8db45a36..5c54a3157 100644 --- a/src/test/java/org/owasp/webgoat/lessons/xss/StoredXssCommentsTest.java +++ b/src/test/java/org/owasp/webgoat/lessons/xss/StoredXssCommentsTest.java @@ -22,6 +22,10 @@ package org.owasp.webgoat.lessons.xss; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -35,62 +39,66 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; - - @ExtendWith(MockitoExtension.class) public class StoredXssCommentsTest extends AssignmentEndpointTest { - private MockMvc mockMvc; + private MockMvc mockMvc; - @BeforeEach - public void setup() { - StoredXssComments storedXssComments = new StoredXssComments(); - init(storedXssComments); - this.mockMvc = standaloneSetup(storedXssComments).build(); - } + @BeforeEach + public void setup() { + StoredXssComments storedXssComments = new StoredXssComments(); + init(storedXssComments); + this.mockMvc = standaloneSetup(storedXssComments).build(); + } - @Test - public void success() throws Exception { - ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScriptingStored/stored-xss") - .content("{\"text\":\"someTextHereMoreTextHere\"}") + @Test + public void success() throws Exception { + ResultActions results = + mockMvc.perform( + MockMvcRequestBuilders.post("/CrossSiteScriptingStored/stored-xss") + .content( + "{\"text\":\"someTextHereMoreTextHere\"}") .contentType(MediaType.APPLICATION_JSON)); - results.andExpect(status().isOk()); - results.andExpect(jsonPath("$.lessonCompleted",CoreMatchers.is(true))); - } + results.andExpect(status().isOk()); + results.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } - @Test - public void failure() throws Exception { - ResultActions results = mockMvc.perform(MockMvcRequestBuilders.post("/CrossSiteScriptingStored/stored-xss") + @Test + public void failure() throws Exception { + ResultActions results = + mockMvc.perform( + MockMvcRequestBuilders.post("/CrossSiteScriptingStored/stored-xss") .content("{\"text\":\"someTextHereMoreTextHere\"}") .contentType(MediaType.APPLICATION_JSON)); - results.andExpect(status().isOk()); - results.andExpect(jsonPath("$.lessonCompleted",CoreMatchers.is(false))); - } + results.andExpect(status().isOk()); + results.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } - /* For the next two tests there is a comment seeded ... - comments.add(new Comment("secUriTy", DateTime.now().toString(fmt), "Comment for Unit Testing")); - ... the isEncoded method will remain commented out as it will fail (because WebGoat isn't supposed to be secure) - */ + /* For the next two tests there is a comment seeded ... + comments.add(new Comment("secUriTy", DateTime.now().toString(fmt), "Comment for Unit Testing")); + ... the isEncoded method will remain commented out as it will fail (because WebGoat isn't supposed to be secure) + */ - //Ensures it is vulnerable - @Test - public void isNotEncoded() throws Exception { - //do get to get comments after posting xss payload - ResultActions taintedResults = mockMvc.perform(MockMvcRequestBuilders.get("/CrossSiteScriptingStored/stored-xss")); - MvcResult mvcResult = taintedResults.andReturn(); - assert(mvcResult.getResponse().getContentAsString().contains("