Remove WebGoat session object (#1929)

* refactor: modernize code

* refactor: move to Tomcat

* chore: bump to Spring Boot 3.3.3

* refactor: use Testcontainers to run integration tests

* refactor: lesson/assignment progress

* chore: format code

* refactor: first step into removing base class for assignment

Always been a bit of an ugly construction, as none of the dependencies are clear. The constructors are hidden due to autowiring the base class. This PR removes two of the fields.

As a bonus we now wire the authentication principal directly in the controllers.

* refactor: use authentication principal directly.

* refactor: pass lesson to the endpoints

No more need to get the current lesson set in a session. The lesson is now passed to the endpoints.

* fix: Testcontainers cannot run on Windows host in Github actions.

Since we have Windows specific paths let's run it standalone for now. We need to run these tests on Docker as well (for now disabled)
This commit is contained in:
Nanne Baars
2024-10-26 10:54:21 +02:00
committed by GitHub
parent cb7c508046
commit ab068901f1
156 changed files with 1076 additions and 1235 deletions

View File

@ -15,7 +15,7 @@ class AccessControlIntegrationTest extends IntegrationTest {
assignment2();
assignment3();
checkResults("/access-control");
checkResults("MissingFunctionAC");
}
private void assignment3() {

View File

@ -86,7 +86,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
// logout();
login(); // because old cookie got replaced and invalidated
startLesson("CSRF", false);
checkResults("/csrf");
checkResults("CSRF");
}
private void uploadTrickHtml(String htmlName, String htmlContent) throws IOException {
@ -103,7 +103,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.multiPart("file", htmlName, htmlContent.getBytes())
.post(webWolfUrl("fileupload"))
.post(new WebWolfUrlBuilder().path("fileupload").build())
.then()
.extract()
.response()
@ -118,7 +118,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("files/" + this.getUser() + "/" + htmlName))
.get(new WebWolfUrlBuilder().path("files/%s/%s", this.getUser(), htmlName).build())
.then()
.extract()
.response()
@ -136,7 +136,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("files/fake.html"))
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
.post(goatURL)
.then()
.extract()
@ -163,7 +163,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("files/fake.html"))
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
.formParams(params)
.post(goatURL)
.then()
@ -184,7 +184,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("files/fake.html"))
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
.contentType(ContentType.TEXT)
.body(
"{\"name\":\"WebGoat\",\"email\":\"webgoat@webgoat.org\",\"content\":\"WebGoat is"
@ -217,7 +217,7 @@ public class CSRFIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.header("Referer", webWolfUrl("files/fake.html"))
.header("Referer", new WebWolfUrlBuilder().path("files/fake.html").build())
.params(params)
.post(goatURL)
.then()
@ -254,15 +254,15 @@ public class CSRFIntegrationTest extends IntegrationTest {
RestAssured.given()
.cookie("JSESSIONID", getWebGoatCookie())
.relaxedHTTPSValidation()
.get(url("service/lessonoverview.mvc"))
.get(url("service/lessonoverview.mvc/CSRF"))
.then()
.extract()
.jsonPath()
.getObject("$", Overview[].class);
// assertThat(assignments)
// .filteredOn(a -> a.getAssignment().getName().equals("CSRFLogin"))
// .extracting(o -> o.solved)
// .containsExactly(true);
assertThat(assignments)
.filteredOn(a -> a.getAssignment().getName().equals("CSRFLogin"))
.extracting(o -> o.solved)
.containsExactly(true);
}
@Data

View File

@ -50,9 +50,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(url("challenge/flag"), params, true);
checkAssignment(url("challenge/flag/1"), params, true);
checkResults("/challenge/1");
checkResults("Challenge1");
List<String> capturefFlags =
RestAssured.given()
@ -92,9 +92,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(url("challenge/flag"), params, true);
checkAssignment(url("challenge/flag/5"), params, true);
checkResults("/challenge/5");
checkResults("Challenge5");
List<String> capturefFlags =
RestAssured.given()
@ -126,7 +126,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
.extract()
.asString();
// Should send an email to WebWolf inbox this should give a hint to the link being static
// Should email WebWolf inbox this should give a hint to the link being static
RestAssured.given()
.when()
.relaxedHTTPSValidation()
@ -144,7 +144,7 @@ public class ChallengeIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("mail"))
.get(new WebWolfUrlBuilder().path("mail").build())
.then()
.extract()
.response()
@ -165,6 +165,6 @@ public class ChallengeIntegrationTest extends IntegrationTest {
.asString();
String flag = result.substring(result.indexOf("flag") + 6, result.indexOf("flag") + 42);
checkAssignment(url("challenge/flag"), Map.of("flag", flag), true);
checkAssignment(url("challenge/flag/7"), Map.of("flag", flag), true);
}
}

View File

@ -42,7 +42,7 @@ public class CryptoIntegrationTest extends IntegrationTest {
checkAssignmentDefaults();
checkResults("/crypto");
checkResults("Cryptography");
}
private void checkAssignment2() {

View File

@ -28,6 +28,6 @@ public class DeserializationIntegrationTest extends IntegrationTest {
}
checkAssignment(url("InsecureDeserialization/task"), params, true);
checkResults("/InsecureDeserialization/");
checkResults("InsecureDeserialization");
}
}

View File

@ -31,7 +31,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.put("magic_num", "33");
checkAssignment(url("HttpBasics/attack2"), params, true);
checkResults("/HttpBasics/");
checkResults("HttpBasics");
}
@Test
@ -51,7 +51,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
.path("lessonCompleted"),
CoreMatchers.is(true));
checkResults("/HttpProxies/");
checkResults("HttpProxies");
}
@Test
@ -73,7 +73,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
"question_3_solution",
"Solution 2: The systems security is compromised even if only one goal is harmed.");
checkAssignment(url("cia/quiz"), params, true);
checkResults("/cia/");
checkResults("CIA");
}
@Test
@ -96,7 +96,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.clear();
params.put("payload", solution);
checkAssignment(url("VulnerableComponents/attack1"), params, true);
checkResults("/VulnerableComponents/");
checkResults("VulnerableComponents");
}
}
@ -108,7 +108,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.put("username", "CaptainJack");
params.put("password", "BlackPearl");
checkAssignment(url("InsecureLogin/task"), params, true);
checkResults("/InsecureLogin/");
checkResults("InsecureLogin");
}
@Test
@ -118,7 +118,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.clear();
params.put("password", "ajnaeliclm^&&@kjn.");
checkAssignment(url("SecurePasswords/assignment"), params, true);
checkResults("SecurePasswords/");
checkResults("SecurePasswords");
startLesson("AuthBypass");
params.clear();
@ -128,7 +128,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.put("verifyMethod", "SEC_QUESTIONS");
params.put("userId", "12309746");
checkAssignment(url("auth-bypass/verify-account"), params, true);
checkResults("/auth-bypass/");
checkResults("AuthBypass");
startLesson("HttpProxies");
MatcherAssert.assertThat(
@ -144,7 +144,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
.extract()
.path("lessonCompleted"),
CoreMatchers.is(true));
checkResults("/HttpProxies/");
checkResults("HttpProxies");
}
@Test
@ -180,7 +180,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.put("network_num", "24");
checkAssignment(url("ChromeDevTools/network"), params, true);
checkResults("/ChromeDevTools/");
checkResults("ChromeDevTools");
}
@Test
@ -194,7 +194,7 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.put("verifyMethod", "SEC_QUESTIONS");
params.put("userId", "12309746");
checkAssignment(url("auth-bypass/verify-account"), params, true);
checkResults("/auth-bypass/");
checkResults("AuthBypass");
}
@Test
@ -205,6 +205,6 @@ public class GeneralLessonIntegrationTest extends IntegrationTest {
params.put("param1", "secr37Value");
params.put("param2", "Main");
checkAssignment(url("lesson-template/sample-attack"), params, true);
checkResults("/lesson-template/");
checkResults("LessonTemplate");
}
}

View File

@ -30,7 +30,7 @@ public class IDORIntegrationTest extends IntegrationTest {
@AfterEach
public void shutdown() {
checkResults("/IDOR");
checkResults("IDOR");
}
private void loginIDOR() {

View File

@ -3,6 +3,7 @@ package org.owasp.webgoat;
import static io.restassured.RestAssured.given;
import io.restassured.RestAssured;
import io.restassured.filter.log.LogDetail;
import io.restassured.http.ContentType;
import java.util.Map;
import lombok.Getter;
@ -15,40 +16,73 @@ import org.springframework.http.HttpStatus;
public abstract class IntegrationTest {
private static String webGoatPort = System.getenv().getOrDefault("WEBGOAT_PORT", "8080");
private static String webGoatContext =
System.getenv().getOrDefault("WEBGOAT_CONTEXT", "/WebGoat/");
@Getter private static String webWolfPort = System.getenv().getOrDefault("WEBWOLF_PORT", "9090");
@Getter
private static String webWolfHost = System.getenv().getOrDefault("WEBWOLF_HOST", "127.0.0.1");
@Getter
private static String webGoatHost = System.getenv().getOrDefault("WEBGOAT_HOST", "127.0.0.1");
private static String webGoatContext =
System.getenv().getOrDefault("WEBGOAT_CONTEXT", "/WebGoat/");
private static String webWolfContext =
System.getenv().getOrDefault("WEBWOLF_CONTEXT", "/WebWolf/");
private static boolean useSSL =
Boolean.valueOf(System.getenv().getOrDefault("WEBGOAT_SSLENABLED", "false"));
private static String webgoatUrl =
(useSSL ? "https://" : "http://") + webGoatHost + ":" + webGoatPort + webGoatContext;
private static String webWolfUrl = "http://" + webWolfHost + ":" + webWolfPort + webWolfContext;
@Getter private String webGoatCookie;
@Getter private String webWolfCookie;
@Getter private final String user = "webgoat";
protected String url(String url) {
return webgoatUrl + url;
return "http://localhost:%s%s%s".formatted(webGoatPort, webGoatContext, url);
}
protected String webWolfUrl(String url) {
return webWolfUrl + url;
protected class WebWolfUrlBuilder {
private boolean attackMode = false;
private String path = null;
protected String build() {
return "http://localhost:%s%s%s"
.formatted(webWolfPort, webWolfContext, path != null ? path : "");
}
/**
* In attack mode it means WebGoat calls WebWolf to perform an attack. In this case we need to
* use port 9090 in a Docker environment.
*/
protected WebWolfUrlBuilder attackMode() {
attackMode = true;
return this;
}
protected WebWolfUrlBuilder path(String path) {
this.path = path;
return this;
}
protected WebWolfUrlBuilder path(String path, String... uriVariables) {
this.path = path.formatted(uriVariables);
return this;
}
}
protected String webWolfFileUrl(String fileName) {
return webWolfUrl("files") + "/" + getUser() + "/" + fileName;
}
/**
* Debugging options: install TestContainers Desktop and map port 5005 to the host machine with
* https://newsletter.testcontainers.com/announcements/set-fixed-ports-to-easily-debug-development-services
*
* <p>Start the test and connect a remote debugger in IntelliJ to localhost:5005 and attach it.
*/
// private static GenericContainer<?> webGoatContainer =
// new GenericContainer(new ImageFromDockerfile("webgoat").withFileFromPath("/",
// Paths.get(".")))
// .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("webgoat")))
// .withExposedPorts(8080, 9090, 5005)
// .withEnv(
// "_JAVA_OPTIONS",
// "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=0.0.0.0:5005")
// .waitingFor(Wait.forHealthcheck());
//
// static {
// webGoatContainer.start();
// }
@BeforeEach
public void login() {
@ -60,6 +94,8 @@ public abstract class IntegrationTest {
.formParam("password", "password")
.post(url("login"))
.then()
.log()
.ifValidationFails(LogDetail.ALL) // Log the response details if validation fails
.cookie("JSESSIONID")
.statusCode(302)
.extract()
@ -100,7 +136,7 @@ public abstract class IntegrationTest {
.relaxedHTTPSValidation()
.formParam("username", user)
.formParam("password", "password")
.post(webWolfUrl("login"))
.post(new WebWolfUrlBuilder().path("login").build())
.then()
.statusCode(302)
.cookie("WEBWOLFSESSION")
@ -131,7 +167,7 @@ public abstract class IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/restartlesson.mvc"))
.get(url("service/restartlesson.mvc/%s.lesson".formatted(lessonName)))
.then()
.statusCode(200);
}
@ -167,23 +203,18 @@ public abstract class IntegrationTest {
CoreMatchers.is(expectedResult));
}
// TODO is prefix useful? not every lesson endpoint needs to start with a certain prefix (they are
// only required to be in the same package)
public void checkResults(String prefix) {
checkResults();
MatcherAssert.assertThat(
public void checkResults(String lesson) {
var result =
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/lessonoverview.mvc"))
.then()
.statusCode(200)
.extract()
.jsonPath()
.getList("assignment.path"),
CoreMatchers.everyItem(CoreMatchers.startsWith(prefix)));
.get(url("service/lessonoverview.mvc/%s.lesson".formatted(lesson)))
.andReturn();
MatcherAssert.assertThat(
result.then().statusCode(200).extract().jsonPath().getList("solved"),
CoreMatchers.everyItem(CoreMatchers.is(true)));
}
public void checkResults() {
@ -238,7 +269,7 @@ public abstract class IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("file-server-location"))
.get(new WebWolfUrlBuilder().path("file-server-location").build())
.then()
.extract()
.response()
@ -266,7 +297,7 @@ public abstract class IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.delete(webWolfUrl("mail"))
.delete(new WebWolfUrlBuilder().path("mail").build())
.then()
.statusCode(HttpStatus.ACCEPTED.value());
}

View File

@ -13,7 +13,6 @@ import io.jsonwebtoken.impl.TextCodec;
import io.restassured.RestAssured;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
@ -34,7 +33,7 @@ import org.owasp.webgoat.lessons.jwt.JWTSecretKeyEndpoint;
public class JWTLessonIntegrationTest extends IntegrationTest {
@Test
public void solveAssignment() throws IOException, InvalidKeyException, NoSuchAlgorithmException {
public void solveAssignment() throws IOException, NoSuchAlgorithmException {
startLesson("JWT");
decodingToken();
@ -51,11 +50,10 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
quiz();
checkResults("/JWT/");
checkResults("JWT");
}
private String generateToken(String key) {
return Jwts.builder()
.setIssuer("WebGoat Token Builder")
.setAudience("webgoat.org")
@ -96,7 +94,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
CoreMatchers.is(true));
}
private void findPassword() throws IOException, NoSuchAlgorithmException, InvalidKeyException {
private void findPassword() {
String accessToken =
RestAssured.given()
@ -256,7 +254,7 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.multiPart("file", "jwks.json", jwks.toJson().getBytes())
.post(webWolfUrl("fileupload"))
.post(new WebWolfUrlBuilder().path("fileupload").build())
.then()
.extract()
.response()
@ -265,7 +263,10 @@ public class JWTLessonIntegrationTest extends IntegrationTest {
Map<String, Object> header = new HashMap();
header.put(Header.TYPE, Header.JWT_TYPE);
header.put(JwsHeader.JWK_SET_URL, webWolfFileUrl("jwks.json"));
header.put(
JwsHeader.JWK_SET_URL,
new WebWolfUrlBuilder().attackMode().path("files/%s/jwks.json", getUser()).build());
String token =
Jwts.builder()
.setHeader(header)

View File

@ -151,7 +151,6 @@ public class LabelAndHintIntegrationTest extends IntegrationTest {
checkLang(propsDefault, "nl");
checkLang(propsDefault, "de");
checkLang(propsDefault, "fr");
checkLang(propsDefault, "ru");
}
private Properties getProperties(String lang) {

View File

@ -85,7 +85,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("mail"))
.get(new WebWolfUrlBuilder().path("mail").build())
.then()
.extract()
.response()
@ -99,7 +99,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
public void shutdown() {
// this will run only once after the list of dynamic tests has run, this is to test if the
// lesson is marked complete
checkResults("/PasswordReset");
checkResults("PasswordReset");
}
private void changePassword(String link) {
@ -119,7 +119,7 @@ public class PasswordResetLessonIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("requests"))
.get(new WebWolfUrlBuilder().path("requests").build())
.then()
.extract()
.response()

View File

@ -147,6 +147,6 @@ class PathTraversalIT extends IntegrationTest {
void shutdown() {
// this will run only once after the list of dynamic tests has run, this is to test if the
// lesson is marked complete
checkResults("/PathTraversal");
checkResults("PathTraversal");
}
}

View File

@ -29,7 +29,7 @@ public class ProgressRaceConditionIntegrationTest extends IntegrationTest {
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.formParams(Map.of("flag", "test"))
.post(url("challenge/flag"));
.post(url("challenge/flag/1"));
};
ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_PARALLEL_THREADS);
List<? extends Callable<Response>> flagCalls =

View File

@ -1,6 +1,5 @@
package org.owasp.webgoat;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.junit.jupiter.api.Test;
@ -8,7 +7,7 @@ import org.junit.jupiter.api.Test;
public class SSRFIntegrationTest extends IntegrationTest {
@Test
public void runTests() throws IOException {
public void runTests() {
startLesson("SSRF");
Map<String, Object> params = new HashMap<>();
@ -21,6 +20,6 @@ public class SSRFIntegrationTest extends IntegrationTest {
checkAssignment(url("SSRF/task2"), params, true);
checkResults("/SSRF/");
checkResults("SSRF");
}
}

View File

@ -56,6 +56,6 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
checkAssignment(url("SqlInjectionAdvanced/quiz"), params, true);
checkResults("/SqlInjectionAdvanced/");
checkResults("SqlInjectionAdvanced");
}
}

View File

@ -73,6 +73,6 @@ public class SqlInjectionLessonIntegrationTest extends IntegrationTest {
params.put("action_string", sql_13);
checkAssignment(url("SqlInjection/attack10"), params, true);
checkResults("/SqlInjection/");
checkResults("SqlInjection");
}
}

View File

@ -80,6 +80,6 @@ public class SqlInjectionMitigationIntegrationTest extends IntegrationTest {
params.put("ip", "104.130.219.202");
checkAssignment(url("SqlInjectionMitigations/attack12a"), params, true);
checkResults();
checkResults("SqlInjectionMitigations");
}
}

View File

@ -23,7 +23,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("mail"))
.get(new WebWolfUrlBuilder().path("mail").build())
.then()
.extract()
.response()
@ -53,7 +53,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.queryParams(params)
.get(webWolfUrl("landing"))
.get(new WebWolfUrlBuilder().path("landing").build())
.then()
.statusCode(200);
responseBody =
@ -61,7 +61,7 @@ public class WebWolfIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("requests"))
.get(new WebWolfUrlBuilder().path("requests").build())
.then()
.extract()
.response()
@ -72,6 +72,6 @@ public class WebWolfIntegrationTest extends IntegrationTest {
params.put("uniqueCode", uniqueCode);
checkAssignment(url("WebWolf/landing"), params, true);
checkResults("/WebWolf");
checkResults("WebWolfIntroduction");
}
}

View File

@ -111,6 +111,6 @@ public class XSSIntegrationTest extends IntegrationTest {
+ "MyCommentDAO.addComment(threadID, userID).getCleanHTML());");
checkAssignment(url("CrossSiteScripting/attack4"), params, true);
checkResults("/CrossSiteScripting");
checkResults("CrossSiteScripting");
}
}

View File

@ -3,9 +3,6 @@ package org.owasp.webgoat;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.jupiter.api.Test;
public class XXEIntegrationTest extends IntegrationTest {
@ -28,47 +25,40 @@ public class XXEIntegrationTest extends IntegrationTest {
""";
private String webGoatHomeDirectory;
private String webWolfFileServerLocation;
/*
* This test is to verify that all is secure when XXE security patch is applied.
*/
@Test
public void xxeSecure() throws IOException {
startLesson("XXE");
webGoatHomeDirectory = webGoatServerDirectory();
webWolfFileServerLocation = getWebWolfFileServerLocation();
RestAssured.given()
.when()
.relaxedHTTPSValidation()
.cookie("JSESSIONID", getWebGoatCookie())
.get(url("service/enable-security.mvc"))
.then()
.statusCode(200);
checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, false);
checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, false);
checkAssignment(
url("xxe/blind"),
ContentType.XML,
"<comment><text>" + getSecret() + "</text></comment>",
false);
}
// TODO fix me
// /*
// * This test is to verify that all is secure when XXE security patch is applied.
// */
// @Test
// public void xxeSecure() throws IOException {
// startLesson("XXE");
// webGoatHomeDirectory = webGoatServerDirectory();
// RestAssured.given()
// .when()
// .relaxedHTTPSValidation()
// .cookie("JSESSIONID", getWebGoatCookie())
// .get(url("service/enable-security.mvc"))
// .then()
// .statusCode(200);
// checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, false);
// checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, false);
// checkAssignment(
// url("xxe/blind"),
// ContentType.XML,
// "<comment><text>" + getSecret() + "</text></comment>",
// false);
// }
/**
* This performs the steps of the exercise before the secret can be committed in the final step.
*
* @return
* @throws IOException
*/
private String getSecret() throws IOException {
// remove any left over DTD
Path webWolfFilePath = Paths.get(webWolfFileServerLocation);
if (webWolfFilePath.resolve(Paths.get(this.getUser(), "blind.dtd")).toFile().exists()) {
Files.delete(webWolfFilePath.resolve(Paths.get(this.getUser(), "blind.dtd")));
}
private String getSecret() {
String secretFile = webGoatHomeDirectory.concat("/XXE/" + getUser() + "/secret.txt");
String dtd7String =
dtd7.replace("WEBWOLFURL", webWolfUrl("landing")).replace("SECRET", secretFile);
String webWolfCallback = new WebWolfUrlBuilder().path("landing").attackMode().build();
String dtd7String = dtd7.replace("WEBWOLFURL", webWolfCallback).replace("SECRET", secretFile);
// upload DTD
RestAssured.given()
@ -76,15 +66,17 @@ public class XXEIntegrationTest extends IntegrationTest {
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.multiPart("file", "blind.dtd", dtd7String.getBytes())
.post(webWolfUrl("fileupload"))
.post(new WebWolfUrlBuilder().path("fileupload").build())
.then()
.extract()
.response()
.getBody()
.asString();
// upload attack
String xxe7String =
xxe7.replace("WEBWOLFURL", webWolfUrl("files")).replace("USERNAME", this.getUser());
xxe7.replace("WEBWOLFURL", new WebWolfUrlBuilder().attackMode().path("files").build())
.replace("USERNAME", this.getUser());
checkAssignment(url("xxe/blind"), ContentType.XML, xxe7String, false);
// read results from WebWolf
@ -93,7 +85,7 @@ public class XXEIntegrationTest extends IntegrationTest {
.when()
.relaxedHTTPSValidation()
.cookie("WEBWOLFSESSION", getWebWolfCookie())
.get(webWolfUrl("requests"))
.get(new WebWolfUrlBuilder().path("requests").build())
.then()
.extract()
.response()
@ -113,7 +105,6 @@ public class XXEIntegrationTest extends IntegrationTest {
public void runTests() throws IOException {
startLesson("XXE", true);
webGoatHomeDirectory = webGoatServerDirectory();
webWolfFileServerLocation = getWebWolfFileServerLocation();
checkAssignment(url("xxe/simple"), ContentType.XML, xxe3, true);
checkAssignment(url("xxe/content-type"), ContentType.XML, xxe4, true);
checkAssignment(
@ -121,6 +112,6 @@ public class XXEIntegrationTest extends IntegrationTest {
ContentType.XML,
"<comment><text>" + getSecret() + "</text></comment>",
true);
checkResults("xxe/");
checkResults("XXE");
}
}