diff --git a/src/it/java/org/owasp/webgoat/integration/ChallengeIntegrationTest.java b/src/it/java/org/owasp/webgoat/integration/ChallengeIntegrationTest.java index 1c5add18e..3cbac7cee 100644 --- a/src/it/java/org/owasp/webgoat/integration/ChallengeIntegrationTest.java +++ b/src/it/java/org/owasp/webgoat/integration/ChallengeIntegrationTest.java @@ -4,12 +4,9 @@ */ package org.owasp.webgoat.integration; -import static org.junit.jupiter.api.Assertions.assertTrue; - import io.restassured.RestAssured; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; @@ -21,7 +18,7 @@ public class ChallengeIntegrationTest extends IntegrationTest { void testChallenge1() { startLesson("Challenge1"); - byte[] resultBytes = + byte[] resultBytes = RestAssured.given() .when() .relaxedHTTPSValidation() @@ -38,8 +35,8 @@ public class ChallengeIntegrationTest extends IntegrationTest { params.put("username", "admin"); params.put("password", "!!webgoat_admin_1234!!".replace("1234", pincode)); - checkAssignment(webGoatUrlConfig.url("challenge/1"), params, true); - String result = + checkAssignment(webGoatUrlConfig.url("challenge/1"), params, true); + String result = RestAssured.given() .when() .relaxedHTTPSValidation() @@ -54,22 +51,9 @@ public class ChallengeIntegrationTest extends IntegrationTest { String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42); params.clear(); params.put("flag", flag); - checkAssignment(webGoatUrlConfig.url("challenge/flag/1"), params, true); + checkAssignment(webGoatUrlConfig.url("challenge/flag/1"), params, true); checkResults("Challenge1"); - - List capturefFlags = - RestAssured.given() - .when() - .relaxedHTTPSValidation() - .cookie("JSESSIONID", getWebGoatCookie()) - .get(webGoatUrlConfig.url("scoreboard-data")) - .then() - .statusCode(200) - .extract() - .jsonPath() - .get("find { it.username == \"" + this.getUser() + "\" }.flagsCaptured"); - assertTrue(capturefFlags.contains("Admin lost password")); } @Test @@ -81,7 +65,7 @@ public class ChallengeIntegrationTest extends IntegrationTest { params.put("username_login", "Larry"); params.put("password_login", "1' or '1'='1"); - String result = + String result = RestAssured.given() .when() .relaxedHTTPSValidation() @@ -96,22 +80,9 @@ public class ChallengeIntegrationTest extends IntegrationTest { String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42); params.clear(); params.put("flag", flag); - checkAssignment(webGoatUrlConfig.url("challenge/flag/5"), params, true); + checkAssignment(webGoatUrlConfig.url("challenge/flag/5"), params, true); checkResults("Challenge5"); - - List capturefFlags = - RestAssured.given() - .when() - .relaxedHTTPSValidation() - .cookie("JSESSIONID", getWebGoatCookie()) - .get(webGoatUrlConfig.url("scoreboard-data")) - .then() - .statusCode(200) - .extract() - .jsonPath() - .get("find { it.username == \"" + this.getUser() + "\" }.flagsCaptured"); - assertTrue(capturefFlags.contains("Without password")); } @Test @@ -120,7 +91,7 @@ public class ChallengeIntegrationTest extends IntegrationTest { cleanMailbox(); // One should first be able to download git.zip from WebGoat - RestAssured.given() + RestAssured.given() .when() .relaxedHTTPSValidation() .cookie("JSESSIONID", getWebGoatCookie()) @@ -131,7 +102,7 @@ public class ChallengeIntegrationTest extends IntegrationTest { .asString(); // Should email WebWolf inbox this should give a hint to the link being static - RestAssured.given() + RestAssured.given() .when() .relaxedHTTPSValidation() .cookie("JSESSIONID", getWebGoatCookie()) @@ -157,18 +128,20 @@ public class ChallengeIntegrationTest extends IntegrationTest { Assertions.assertThat(responseBody).contains("Hi, you requested a password reset link"); // Call reset link with admin link - String result = + String result = RestAssured.given() .when() .relaxedHTTPSValidation() .cookie("JSESSIONID", getWebGoatCookie()) - .get(webGoatUrlConfig.url("challenge/7/reset-password/{link}"), "375afe1104f4a487a73823c50a9292a2") + .get( + webGoatUrlConfig.url("challenge/7/reset-password/{link}"), + "375afe1104f4a487a73823c50a9292a2") .then() .statusCode(HttpStatus.ACCEPTED.value()) .extract() .asString(); String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42); - checkAssignment(webGoatUrlConfig.url("challenge/flag/7"), Map.of("flag", flag), true); + checkAssignment(webGoatUrlConfig.url("challenge/flag/7"), Map.of("flag", flag), true); } } diff --git a/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java b/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java index 24c6ee3d4..52df5a233 100644 --- a/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java +++ b/src/main/java/org/owasp/webgoat/container/MvcConfiguration.java @@ -53,7 +53,6 @@ public class MvcConfiguration implements WebMvcConfigurer { 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 diff --git a/src/main/java/org/owasp/webgoat/container/users/LessonProgress.java b/src/main/java/org/owasp/webgoat/container/users/LessonProgress.java index da76a5574..601f24c4c 100644 --- a/src/main/java/org/owasp/webgoat/container/users/LessonProgress.java +++ b/src/main/java/org/owasp/webgoat/container/users/LessonProgress.java @@ -84,6 +84,6 @@ public class LessonProgress { } long numberOfSolvedAssignments() { - return assignments.size(); + return assignments.stream().filter(AssignmentProgress::isSolved).count(); } } diff --git a/src/main/java/org/owasp/webgoat/container/users/Scoreboard.java b/src/main/java/org/owasp/webgoat/container/users/Scoreboard.java deleted file mode 100644 index bd74fdffa..000000000 --- a/src/main/java/org/owasp/webgoat/container/users/Scoreboard.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright © 2017 WebGoat authors - * SPDX-License-Identifier: GPL-2.0-or-later - */ -package org.owasp.webgoat.container.users; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.owasp.webgoat.container.i18n.PluginMessages; -import org.owasp.webgoat.container.lessons.Lesson; -import org.owasp.webgoat.container.session.Course; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -/** - * Temp endpoint just for the CTF. - * - * @author nbaars - * @since 3/23/17. - */ -@RestController -@AllArgsConstructor -public class Scoreboard { - - private final UserProgressRepository userTrackerRepository; - private final UserRepository userRepository; - private final Course course; - private final PluginMessages pluginMessages; - - @AllArgsConstructor - @Getter - private class Ranking { - private String username; - private List flagsCaptured; - } - - @GetMapping("/scoreboard-data") - public List getRankings() { - return userRepository.findAll().stream() - .filter(user -> !user.getUsername().startsWith("csrf-")) - .map( - user -> - new Ranking( - user.getUsername(), - challengesSolved(userTrackerRepository.findByUser(user.getUsername())))) - .sorted((o1, o2) -> o2.getFlagsCaptured().size() - o1.getFlagsCaptured().size()) - .collect(Collectors.toList()); - } - - private List challengesSolved(UserProgress userTracker) { - List challenges = - List.of( - "Challenge1", - "Challenge2", - "Challenge3", - "Challenge4", - "Challenge5", - "Challenge6", - "Challenge7", - "Challenge8", - "Challenge9"); - return challenges.stream() - .map(userTracker::getLessonProgress) - .flatMap(Optional::stream) - .filter(LessonProgress::isLessonSolved) - .map(LessonProgress::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); - } -} diff --git a/src/main/java/org/owasp/webgoat/container/users/UserProgress.java b/src/main/java/org/owasp/webgoat/container/users/UserProgress.java index 34ff667fb..37ae1c8a4 100644 --- a/src/main/java/org/owasp/webgoat/container/users/UserProgress.java +++ b/src/main/java/org/owasp/webgoat/container/users/UserProgress.java @@ -41,7 +41,7 @@ public class UserProgress { } /** - * Returns an existing lesson tracker or create a new one based on the lesson + * Returns an existing lesson progress or create a new one based on the lesson * * @param lesson the lesson * @return a lesson tracker created if not already present @@ -49,7 +49,7 @@ public class UserProgress { public LessonProgress getLessonProgress(Lesson lesson) { Optional progress = lessonProgress.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst(); - if (!progress.isPresent()) { + if (progress.isEmpty()) { LessonProgress newLessonTracker = new LessonProgress(lesson); lessonProgress.add(newLessonTracker); return newLessonTracker; @@ -58,16 +58,6 @@ public class UserProgress { } } - /** - * 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 getLessonProgress(String id) { - return lessonProgress.stream().filter(l -> l.getLessonName().equals(id)).findFirst(); - } - public void assignmentSolved(Lesson lesson, String assignmentName) { LessonProgress progress = getLessonProgress(lesson); progress.incrementAttempts(); diff --git a/src/main/resources/lessons/challenges/documentation/Challenge_introduction.adoc b/src/main/resources/lessons/challenges/documentation/Challenge_introduction.adoc index fd2cd92f4..cd23abfe7 100644 --- a/src/main/resources/lessons/challenges/documentation/Challenge_introduction.adoc +++ b/src/main/resources/lessons/challenges/documentation/Challenge_introduction.adoc @@ -4,7 +4,7 @@ The challenges contain more a CTF like lessons where we do not provide any explanations what you need to do, no hints will be provided. You can use these challenges in a CTF style where you can run WebGoat on one server and all -participants can join and hack the challenges. A scoreboard is available at link:scoreboard["scoreboard",window=_blank] +participants can join and hack the challenges. :hardbreaks: In this CTF you will need to solve a couple of challenges, each challenge will give you a flag which you will diff --git a/src/main/resources/webgoat/static/css/main.css b/src/main/resources/webgoat/static/css/main.css index 77b2c38f7..6fc2baa4d 100644 --- a/src/main/resources/webgoat/static/css/main.css +++ b/src/main/resources/webgoat/static/css/main.css @@ -1172,46 +1172,10 @@ span.show-next-page, span.show-prev-page { width: 95% !important } -/* scoreboard */ -div.scoreboard-title { - font-size: xx-large; -} - -.scoreboard-table tr { -} - -div.scoreboard-username { - background-color: #222; - color: aliceblue; - padding: 4px; - padding-left: 8px; - font-size: medium; - border-radius: 6px; -} - th.username { padding-bottom: 6px; } -td.user-flags { - padding-left: 8px; - padding-bottom: 6px; -} - -div.captured-flag { - border-radius: 6px; - background-color: #444; - color: white; - padding: 4px; - font-size: medium; - display: inline-block; -} - -.scoreboard-page { - background-color: #e0dfdc; - padding: 20px; -} - .fa-flag { color: red } diff --git a/src/main/resources/webgoat/static/js/goatApp/model/FlagModel.js b/src/main/resources/webgoat/static/js/goatApp/model/FlagModel.js deleted file mode 100644 index 24837360f..000000000 --- a/src/main/resources/webgoat/static/js/goatApp/model/FlagModel.js +++ /dev/null @@ -1,9 +0,0 @@ -define(['jquery', - 'underscore', - 'backbone'], - function($, - _, - Backbone) { - return Backbone.Model.extend({ - }); -}); diff --git a/src/main/resources/webgoat/static/js/goatApp/model/FlagsCollection.js b/src/main/resources/webgoat/static/js/goatApp/model/FlagsCollection.js deleted file mode 100644 index 00250b9e9..000000000 --- a/src/main/resources/webgoat/static/js/goatApp/model/FlagsCollection.js +++ /dev/null @@ -1,13 +0,0 @@ -define(['jquery', - 'underscore', - 'backbone', - 'goatApp/model/FlagModel'], - function($, - _, - Backbone, - FlagModel) { - return Backbone.Collection.extend({ - url:'scoreboard-data', - model:FlagModel - }); -}); diff --git a/src/main/resources/webgoat/static/js/goatApp/scoreboardApp.js b/src/main/resources/webgoat/static/js/goatApp/scoreboardApp.js deleted file mode 100644 index b37351cc9..000000000 --- a/src/main/resources/webgoat/static/js/goatApp/scoreboardApp.js +++ /dev/null @@ -1,16 +0,0 @@ -define(['underscore', - 'goatApp/support/goatAsyncErrorHandler', - 'goatApp/view/ScoreboardView'], - function ( - _, - asyncErrorHandler, - ScoreboardView) { - 'use strict' - class ScoreboardApp { - initApp() { - asyncErrorHandler.init(); - this.scoreboard = new ScoreboardView(); - } - } - return new ScoreboardApp(); - }); diff --git a/src/main/resources/webgoat/static/js/goatApp/templates/scoreboard.html b/src/main/resources/webgoat/static/js/goatApp/templates/scoreboard.html deleted file mode 100644 index d1d32c1a9..000000000 --- a/src/main/resources/webgoat/static/js/goatApp/templates/scoreboard.html +++ /dev/null @@ -1,14 +0,0 @@ - - <% _.each(rankings, function(userRanking, index) { %> - - - - - <% }); %> -
<%= index+1%> - <%=userRanking.username %>
<% _.each(userRanking.flagsCaptured, function(flag) { %> - -
- - <%=flag%>
- <% }); %> -
diff --git a/src/main/resources/webgoat/static/js/goatApp/view/ScoreboardView.js b/src/main/resources/webgoat/static/js/goatApp/view/ScoreboardView.js deleted file mode 100644 index 1e5cc7d4d..000000000 --- a/src/main/resources/webgoat/static/js/goatApp/view/ScoreboardView.js +++ /dev/null @@ -1,32 +0,0 @@ -define(['jquery', - 'underscore', - 'backbone', - 'goatApp/model/FlagsCollection', - 'text!templates/scoreboard.html'], -function($, - _, - Backbone, - FlagsCollection, - ScoreboardTemplate) { - return Backbone.View.extend({ - el:'#scoreboard', - - initialize: function() { - this.template = ScoreboardTemplate, - this.collection = new FlagsCollection(); - this.listenTo(this.collection,'reset',this.render) - this.collection.fetch({reset:true}); - }, - - render: function() { - //this.$el.html('test'); - var t = _.template(this.template); - this.$el.html(t({'rankings':this.collection.toJSON()})); - setTimeout(this.pollData.bind(this), 5000); - }, - - pollData: function() { - this.collection.fetch({reset:true}); - } - }); -}); diff --git a/src/main/resources/webgoat/static/js/scoreboard.js b/src/main/resources/webgoat/static/js/scoreboard.js deleted file mode 100644 index fe09c9eb5..000000000 --- a/src/main/resources/webgoat/static/js/scoreboard.js +++ /dev/null @@ -1,44 +0,0 @@ -//main.js -/* -/js -js/main.js << main file for require.js ---/libs/(jquery,backbone,etc.) << base libs ---/goatApp/ << base dir for goat application, js-wise ---/goatApp/model ---/goatApp/view ---/goatApp/support ---/goatApp/controller -*/ - -require.config({ - baseUrl: "js/", - paths: { - jquery: 'libs/jquery.min', - jqueryvuln: 'libs/jquery-2.1.4.min', - jqueryuivuln: 'libs/jquery-ui-1.10.4', - jqueryui: 'libs/jquery-ui.min', - underscore: 'libs/underscore-min', - backbone: 'libs/backbone-min', - text: 'libs/text', - templates: 'goatApp/templates', - polyglot: 'libs/polyglot.min' - }, - - shim: { - "jqueryui": { - exports:"$", - deps: ['jquery'] - }, - underscore: { - exports: "_" - }, - backbone: { - deps: ['underscore', 'jquery'], - exports: 'Backbone' - } - } -}); - -require(['underscore','backbone','goatApp/scoreboardApp'], function(_,Backbone,ScoreboardApp){ - ScoreboardApp.initApp(); -}); diff --git a/src/main/resources/webgoat/templates/scoreboard.html b/src/main/resources/webgoat/templates/scoreboard.html deleted file mode 100644 index d273c99c2..000000000 --- a/src/main/resources/webgoat/templates/scoreboard.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - WebGoat - - - - -
- -
-
- -
-
- -
-
- -
-
-
- - - - - diff --git a/src/test/java/org/owasp/webgoat/container/users/UserProgressRepositoryTest.java b/src/test/java/org/owasp/webgoat/container/users/UserProgressRepositoryTest.java new file mode 100644 index 000000000..9bc411ebc --- /dev/null +++ b/src/test/java/org/owasp/webgoat/container/users/UserProgressRepositoryTest.java @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: Copyright © 2017 WebGoat authors + * SPDX-License-Identifier: GPL-2.0-or-later + */ +package org.owasp.webgoat.container.users; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.assertj.core.util.Lists; +import org.junit.jupiter.api.Test; +import org.owasp.webgoat.container.lessons.Assignment; +import org.owasp.webgoat.container.lessons.Category; +import org.owasp.webgoat.container.lessons.Lesson; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; + +@DataJpaTest +@ActiveProfiles("webgoat-test") +class UserProgressRepositoryTest { + + private static class TestLesson extends Lesson { + + @Override + public Category getDefaultCategory() { + return Category.CLIENT_SIDE; + } + + @Override + public String getTitle() { + return "test"; + } + + @Override + public List getAssignments() { + var assignment1 = new Assignment("test1", "test1", Lists.newArrayList()); + var assignment2 = new Assignment("test2", "test2", Lists.newArrayList()); + + return List.of(assignment1, assignment2); + } + } + + private static final String USER = "user"; + @Autowired private UserProgressRepository userProgressRepository; + + @Test + void saveUserTracker() { + var userProgress = new UserProgress(USER); + userProgressRepository.save(userProgress); + + userProgress = userProgressRepository.findByUser(USER); + + assertThat(userProgress.getLessonProgress(new TestLesson())).isNotNull(); + } + + @Test + void solvedAssignmentsShouldBeSaved() { + var userProgress = new UserProgress(USER); + var lesson = new TestLesson(); + userProgress.getLessonProgress(lesson); + userProgress.assignmentFailed(lesson); + userProgress.assignmentFailed(lesson); + userProgress.assignmentSolved(lesson, "test1"); + userProgress.assignmentSolved(lesson, "test2"); + userProgressRepository.saveAndFlush(userProgress); + + userProgress = userProgressRepository.findByUser(USER); + + assertThat(userProgress.numberOfAssignmentsSolved()).isEqualTo(2); + } + + @Test + void saveAndLoadShouldHaveCorrectNumberOfAttempts() { + UserProgress userProgress = new UserProgress(USER); + TestLesson lesson = new TestLesson(); + userProgress.getLessonProgress(lesson); + userProgress.assignmentFailed(lesson); + userProgress.assignmentFailed(lesson); + userProgressRepository.saveAndFlush(userProgress); + + userProgress = userProgressRepository.findByUser(USER); + userProgress.assignmentFailed(lesson); + userProgress.assignmentFailed(lesson); + userProgressRepository.saveAndFlush(userProgress); + + assertThat(userProgress.getLessonProgress(lesson).getNumberOfAttempts()).isEqualTo(4); + } +} diff --git a/src/test/java/org/owasp/webgoat/container/users/UserTrackerRepositoryTest.java b/src/test/java/org/owasp/webgoat/container/users/UserTrackerRepositoryTest.java deleted file mode 100644 index ab8f4f674..000000000 --- a/src/test/java/org/owasp/webgoat/container/users/UserTrackerRepositoryTest.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright © 2017 WebGoat authors - * SPDX-License-Identifier: GPL-2.0-or-later - */ -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; -import org.owasp.webgoat.container.lessons.Assignment; -import org.owasp.webgoat.container.lessons.Category; -import org.owasp.webgoat.container.lessons.Lesson; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.test.context.ActiveProfiles; - -@DataJpaTest -@ActiveProfiles("webgoat-test") -class UserTrackerRepositoryTest { - - 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); - } - } - - @Autowired private UserProgressRepository userTrackerRepository; - - @Test - void saveUserTracker() { - UserProgress userTracker = new UserProgress("test"); - - userTrackerRepository.save(userTracker); - - userTracker = userTrackerRepository.findByUser("test"); - Assertions.assertThat(userTracker.getLessonProgress("test")).isNotNull(); - } - - @Test - void solvedAssignmentsShouldBeSaved() { - UserProgress userTracker = new UserProgress("test"); - TestLesson lesson = new TestLesson(); - userTracker.getLessonProgress(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() { - UserProgress userTracker = new UserProgress("test"); - TestLesson lesson = new TestLesson(); - userTracker.getLessonProgress(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.getLessonProgress(lesson).getNumberOfAttempts()).isEqualTo(4); - } -}