Compare commits

...

3 Commits

Author SHA1 Message Date
Nanne Baars
6a83ddcdef
refactor: remove unused code 2024-12-15 12:49:42 +01:00
Nanne Baars
67c1f622ef
refactor: make AssignmentEndpoint an interface 2024-12-02 20:32:06 +01:00
Nanne Baars
a3e0fcc9b3
refactor: move plugin messages
It is now done afterward through an interceptor. No more need to burden assignments with plugin messages etc. Only return the key and the optional args.
2024-12-02 10:51:19 +01:00
140 changed files with 760 additions and 854 deletions

View File

@ -55,8 +55,8 @@ import org.thymeleaf.templateresource.StringTemplateResource;
public class LessonTemplateResolver extends FileTemplateResolver {
private static final String PREFIX = "lesson:";
private ResourceLoader resourceLoader;
private Map<String, byte[]> resources = new HashMap<>();
private final ResourceLoader resourceLoader;
private final Map<String, byte[]> resources = new HashMap<>();
public LessonTemplateResolver(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;

View File

@ -40,7 +40,6 @@ import lombok.extern.slf4j.Slf4j;
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.lessons.LessonScanner;
import org.owasp.webgoat.container.session.LabelDebugger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@ -74,8 +73,6 @@ public class MvcConfiguration implements WebMvcConfigurer {
private static final String UTF8 = "UTF-8";
private final LessonScanner lessonScanner;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
@ -187,28 +184,6 @@ public class MvcConfiguration implements WebMvcConfigurer {
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));
}
@Bean

View File

@ -33,7 +33,6 @@ package org.owasp.webgoat.container;
import java.io.File;
import org.owasp.webgoat.container.session.LessonSession;
import org.owasp.webgoat.container.users.UserRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.domain.EntityScan;
@ -54,12 +53,6 @@ import org.springframework.web.client.RestTemplate;
@EntityScan(basePackages = "org.owasp.webgoat.container")
public class WebGoat {
private final UserRepository userRepository;
public WebGoat(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Bean(name = "pluginTargetDirectory")
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
return new File(webgoatHome);

View File

@ -25,51 +25,4 @@
package org.owasp.webgoat.container.assignments;
import org.owasp.webgoat.container.i18n.PluginMessages;
import org.springframework.beans.factory.annotation.Autowired;
public abstract class AssignmentEndpoint {
// TODO: move this to different bean.
@Autowired private PluginMessages messages;
/**
* Convenience method for create a successful result:
*
* <p>- Assignment is set to solved - Feedback message is set to 'assignment.solved'
*
* <p>Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
* @param assignment
*/
protected AttackResult.AttackResultBuilder success(AssignmentEndpoint assignment) {
return AttackResult.builder(messages)
.lessonCompleted(true)
.attemptWasMade()
.feedback("assignment.solved")
.assignment(assignment);
}
/**
* Convenience method for create a failed result:
*
* <p>- Assignment is set to not solved - Feedback message is set to 'assignment.not.solved'
*
* <p>Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
* @param assignment
*/
protected AttackResult.AttackResultBuilder failed(AssignmentEndpoint assignment) {
return AttackResult.builder(messages)
.lessonCompleted(false)
.attemptWasMade()
.feedback("assignment.not.solved")
.assignment(assignment);
}
protected AttackResult.AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
return AttackResult.builder(messages).lessonCompleted(false).assignment(assignment);
}
}
public interface AssignmentEndpoint {}

View File

@ -1,19 +0,0 @@
package org.owasp.webgoat.container.assignments;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.web.bind.annotation.RequestMethod;
/** Created by nbaars on 1/14/17. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AssignmentPath {
String[] path() default {};
RequestMethod[] method() default {};
String value() default "";
}

View File

@ -30,82 +30,18 @@ import static org.apache.commons.text.StringEscapeUtils.escapeJson;
import lombok.Getter;
import org.owasp.webgoat.container.i18n.PluginMessages;
@Getter
public class AttackResult {
public static class AttackResultBuilder {
private boolean lessonCompleted;
private String feedback;
private Object[] feedbackArgs;
private String output;
private Object[] outputArgs;
private final String assignment;
private boolean attemptWasMade;
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 String output;
@Getter private final String assignment;
@Getter private boolean attemptWasMade;
public AttackResult(
private AttackResult(
boolean lessonCompleted,
String feedback,
String output,
@ -118,11 +54,33 @@ public class AttackResult {
this.attemptWasMade = attemptWasMade;
}
public static AttackResultBuilder builder(PluginMessages messages) {
return new AttackResultBuilder(messages);
public AttackResult(
boolean lessonCompleted,
String feedback,
Object[] feedbackArgs,
String output,
Object[] outputArgs,
String assignment,
boolean attemptWasMade) {
this.lessonCompleted = lessonCompleted;
this.feedback = feedback;
this.feedbackArgs = feedbackArgs;
this.output = output;
this.outputArgs = outputArgs;
this.assignment = assignment;
this.attemptWasMade = attemptWasMade;
}
public boolean assignmentSolved() {
return lessonCompleted;
}
public AttackResult apply(PluginMessages pluginMessages) {
return new AttackResult(
lessonCompleted,
pluginMessages.getMessage(feedback, feedback, feedbackArgs),
pluginMessages.getMessage(output, output, outputArgs),
assignment,
attemptWasMade);
}
}

View File

@ -0,0 +1,130 @@
package org.owasp.webgoat.container.assignments;
import org.owasp.webgoat.container.i18n.PluginMessages;
public class AttackResultBuilder {
private PluginMessages messages;
private boolean lessonCompleted;
private Object[] feedbackArgs;
private String feedbackResourceBundleKey;
private String output;
private Object[] outputArgs;
private AssignmentEndpoint assignment;
private boolean attemptWasMade = false;
private boolean assignmentCompleted;
public AttackResultBuilder(PluginMessages messages) {
this.messages = messages;
}
public AttackResultBuilder() {}
public AttackResultBuilder lessonCompleted(boolean lessonCompleted) {
this.lessonCompleted = lessonCompleted;
this.feedbackResourceBundleKey = "lesson.completed";
return this;
}
public AttackResultBuilder lessonCompleted(boolean lessonCompleted, String resourceBundleKey) {
this.lessonCompleted = lessonCompleted;
this.feedbackResourceBundleKey = resourceBundleKey;
return this;
}
public AttackResultBuilder assignmentCompleted(boolean assignmentCompleted) {
this.assignmentCompleted = assignmentCompleted;
this.feedbackResourceBundleKey = "assignment.completed";
return this;
}
public AttackResultBuilder assignmentCompleted(
boolean assignmentCompleted, String resourceBundleKey) {
this.assignmentCompleted = assignmentCompleted;
this.feedbackResourceBundleKey = resourceBundleKey;
return this;
}
public AttackResultBuilder feedbackArgs(Object... args) {
this.feedbackArgs = args;
return this;
}
public AttackResultBuilder feedback(String resourceBundleKey) {
this.feedbackResourceBundleKey = resourceBundleKey;
return this;
}
public AttackResultBuilder output(String output) {
this.output = output;
return this;
}
public AttackResultBuilder outputArgs(Object... args) {
this.outputArgs = args;
return this;
}
public AttackResultBuilder attemptWasMade() {
this.attemptWasMade = true;
return this;
}
public AttackResult build() {
return new AttackResult(
lessonCompleted,
feedbackResourceBundleKey,
feedbackArgs,
output,
outputArgs,
assignment.getClass().getSimpleName(),
attemptWasMade);
}
public AttackResultBuilder assignment(AssignmentEndpoint assignment) {
this.assignment = assignment;
return this;
}
/**
* Convenience method for create a successful result:
*
* <p>- Assignment is set to solved - Feedback message is set to 'assignment.solved'
*
* <p>Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
* @param assignment
*/
public static AttackResultBuilder success(AssignmentEndpoint assignment) {
return new AttackResultBuilder()
.lessonCompleted(true)
.assignmentCompleted(true)
.attemptWasMade()
.feedback("assignment.solved")
.assignment(assignment);
}
/**
* Convenience method for create a failed result:
*
* <p>- Assignment is set to not solved - Feedback message is set to 'assignment.not.solved'
*
* <p>Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
* @param assignment
*/
public static AttackResultBuilder failed(AssignmentEndpoint assignment) {
return new AttackResultBuilder()
.lessonCompleted(false)
.assignmentCompleted(true)
.attemptWasMade()
.feedback("assignment.not.solved")
.assignment(assignment);
}
public static AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
return new AttackResultBuilder().lessonCompleted(false).assignment(assignment);
}
}

View File

@ -0,0 +1,41 @@
package org.owasp.webgoat.container.assignments;
import org.owasp.webgoat.container.i18n.PluginMessages;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/** This class intercepts the response body and applies the plugin messages to the attack result. */
@RestControllerAdvice
public class AttackResultMessageResponseBodyAdvice implements ResponseBodyAdvice<Object> {
private final PluginMessages pluginMessages;
public AttackResultMessageResponseBodyAdvice(PluginMessages pluginMessages) {
this.pluginMessages = pluginMessages;
}
@Override
public boolean supports(
MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(
Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
if (body instanceof AttackResult a) {
return a.apply(pluginMessages);
}
return body;
}
}

View File

@ -35,6 +35,5 @@ package org.owasp.webgoat.container.lessons;
*/
public enum LessonMenuItemType {
CATEGORY,
LESSON,
STAGE
LESSON
}

View File

@ -1,42 +0,0 @@
package org.owasp.webgoat.container.lessons;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class LessonScanner {
private static final Pattern lessonPattern = Pattern.compile("^.*/lessons/([^/]*)/.*$");
@Getter private final Set<String> lessons = new HashSet<>();
public LessonScanner(ResourcePatternResolver resourcePatternResolver) {
try {
var resources = resourcePatternResolver.getResources("classpath:/lessons/*/*");
for (var resource : resources) {
// WG can run as a fat jar or as directly from file system we need to support both so use
// the URL
var url = resource.getURL();
var matcher = lessonPattern.matcher(url.toString());
if (matcher.matches()) {
lessons.add(matcher.group(1));
}
}
log.debug("Found {} lessons", lessons.size());
} catch (IOException e) {
log.warn("No lessons found...");
}
}
public List<String> applyPattern(String pattern) {
return lessons.stream().map(lesson -> String.format(pattern, lesson)).toList();
}
}

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.authbypass;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
@ -46,7 +49,7 @@ import org.springframework.web.bind.annotation.RestController;
"auth-bypass.hints.verify.3",
"auth-bypass.hints.verify.4"
})
public class VerifyAccount extends AssignmentEndpoint {
public class VerifyAccount implements AssignmentEndpoint {
private final LessonSession userSessionData;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.bypassrestrictions;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.PostMapping;
@ -30,7 +33,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BypassRestrictionsFieldRestrictions extends AssignmentEndpoint {
public class BypassRestrictionsFieldRestrictions implements AssignmentEndpoint {
@PostMapping("/BypassRestrictions/FieldRestrictions")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.bypassrestrictions;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.PostMapping;
@ -30,7 +33,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class BypassRestrictionsFrontendValidation extends AssignmentEndpoint {
public class BypassRestrictionsFrontendValidation implements AssignmentEndpoint {
@PostMapping("/BypassRestrictions/frontendValidation")
@ResponseBody

View File

@ -22,7 +22,9 @@
package org.owasp.webgoat.lessons.challenges;
import lombok.AllArgsConstructor;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.PathVariable;
@ -32,11 +34,14 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@AllArgsConstructor
public class FlagController extends AssignmentEndpoint {
public class FlagController implements AssignmentEndpoint {
private final Flags flags;
public FlagController(Flags flags) {
this.flags = flags;
}
@PostMapping(path = "/challenge/flag/{flagNumber}")
@ResponseBody
public AttackResult postFlag(@PathVariable int flagNumber, @RequestParam String flag) {

View File

@ -1,8 +1,9 @@
package org.owasp.webgoat.lessons.challenges.challenge1;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD;
import lombok.RequiredArgsConstructor;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.lessons.challenges.Flags;
@ -42,11 +43,14 @@ import org.springframework.web.bind.annotation.RestController;
* @since August 11, 2016
*/
@RestController
@RequiredArgsConstructor
public class Assignment1 extends AssignmentEndpoint {
public class Assignment1 implements AssignmentEndpoint {
private final Flags flags;
public Assignment1(Flags flags) {
this.flags = flags;
}
@PostMapping("/challenge/1")
@ResponseBody
public AttackResult completed(@RequestParam String username, @RequestParam String password) {

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.challenges.challenge5;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import lombok.RequiredArgsConstructor;
@ -39,7 +42,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
@RequiredArgsConstructor
public class Assignment5 extends AssignmentEndpoint {
public class Assignment5 implements AssignmentEndpoint {
private final LessonDataSource dataSource;
private final Flags flags;

View File

@ -1,5 +1,7 @@
package org.owasp.webgoat.lessons.challenges.challenge7;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URI;
import java.net.URISyntaxException;
@ -29,7 +31,7 @@ import org.springframework.web.client.RestTemplate;
*/
@RestController
@Slf4j
public class Assignment7 extends AssignmentEndpoint {
public class Assignment7 implements AssignmentEndpoint {
public static final String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2";

View File

@ -19,7 +19,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
@RequiredArgsConstructor
public class Assignment8 extends AssignmentEndpoint {
public class Assignment8 implements AssignmentEndpoint {
private static final Map<Integer, Integer> votes = new HashMap<>();

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.chromedevtools;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.session.LessonSession;
@ -37,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController;
* @since 30.11.18
*/
@RestController
public class NetworkDummy extends AssignmentEndpoint {
public class NetworkDummy implements AssignmentEndpoint {
private final LessonSession lessonSession;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.chromedevtools;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -40,7 +43,7 @@ import org.springframework.web.bind.annotation.RestController;
*/
@RestController
@AssignmentHints({"networkHint1", "networkHint2"})
public class NetworkLesson extends AssignmentEndpoint {
public class NetworkLesson implements AssignmentEndpoint {
@PostMapping(
value = "/ChromeDevTools/network",

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.lessons.cia;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.GetMapping;
@ -9,9 +12,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CIAQuiz extends AssignmentEndpoint {
public class CIAQuiz implements AssignmentEndpoint {
String[] solutions = {"Solution 3", "Solution 1", "Solution 4", "Solution 2"};
private final String[] solutions = {"Solution 3", "Solution 1", "Solution 4", "Solution 2"};
boolean[] guesses = new boolean[solutions.length];
@PostMapping("/cia/quiz")

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.clientsidefiltering;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -37,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController;
"ClientSideFilteringHint3",
"ClientSideFilteringHint4"
})
public class ClientSideFilteringAssignment extends AssignmentEndpoint {
public class ClientSideFilteringAssignment implements AssignmentEndpoint {
@PostMapping("/clientSideFiltering/attack1")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.clientsidefiltering;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -40,8 +43,7 @@ import org.springframework.web.bind.annotation.RestController;
"client.side.filtering.free.hint2",
"client.side.filtering.free.hint3"
})
public class ClientSideFilteringFreeAssignment extends AssignmentEndpoint {
public class ClientSideFilteringFreeAssignment implements AssignmentEndpoint {
public static final String SUPER_COUPON_CODE = "get_it_for_free";
@PostMapping("/clientSideFiltering/getItForFree")

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.cryptography;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Random;
@ -35,7 +38,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class EncodingAssignment extends AssignmentEndpoint {
public class EncodingAssignment implements AssignmentEndpoint {
public static String getBasicAuth(String username, String password) {
return Base64.getEncoder().encodeToString(username.concat(":").concat(password).getBytes());

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.cryptography;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.HttpServletRequest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@ -39,8 +42,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"crypto-hashing.hints.1", "crypto-hashing.hints.2"})
public class HashingAssignment extends AssignmentEndpoint {
public class HashingAssignment implements AssignmentEndpoint {
public static final String[] SECRETS = {"secret", "admin", "password", "123456", "passw0rd"};
@RequestMapping(path = "/crypto/hashing/md5", produces = MediaType.TEXT_HTML_VALUE)

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.cryptography;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.security.NoSuchAlgorithmException;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
@ -37,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController;
"crypto-secure-defaults.hints.2",
"crypto-secure-defaults.hints.3"
})
public class SecureDefaultsAssignment extends AssignmentEndpoint {
public class SecureDefaultsAssignment implements AssignmentEndpoint {
@PostMapping("/crypto/secure/defaults")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.cryptography;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.HttpServletRequest;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
@ -47,7 +50,7 @@ import org.springframework.web.bind.annotation.RestController;
"crypto-signing.hints.4"
})
@Slf4j
public class SigningAssignment extends AssignmentEndpoint {
public class SigningAssignment implements AssignmentEndpoint {
@RequestMapping(path = "/crypto/signing/getprivate", produces = MediaType.TEXT_HTML_VALUE)
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.cryptography;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -32,7 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"crypto-encoding-xor.hints.1"})
public class XOREncodingAssignment extends AssignmentEndpoint {
public class XOREncodingAssignment implements AssignmentEndpoint {
@PostMapping("/crypto/encoding/xor")
@ResponseBody

View File

@ -22,11 +22,13 @@
package org.owasp.webgoat.lessons.csrf;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@ -34,9 +36,13 @@ import org.springframework.web.bind.annotation.RestController;
/** 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 {
public class CSRFConfirmFlag1 implements AssignmentEndpoint {
@Autowired LessonSession userSessionData;
private final LessonSession userSessionData;
public CSRFConfirmFlag1(LessonSession userSessionData) {
this.userSessionData = userSessionData;
}
@PostMapping(
path = "/csrf/confirm-flag-1",

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.csrf;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.Cookie;
@ -34,7 +37,6 @@ import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -44,10 +46,15 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"csrf-feedback-hint1", "csrf-feedback-hint2", "csrf-feedback-hint3"})
public class CSRFFeedback extends AssignmentEndpoint {
public class CSRFFeedback implements AssignmentEndpoint {
@Autowired private LessonSession userSessionData;
@Autowired private ObjectMapper objectMapper;
private final LessonSession userSessionData;
private final ObjectMapper objectMapper;
public CSRFFeedback(LessonSession userSessionData, ObjectMapper objectMapper) {
this.userSessionData = userSessionData;
this.objectMapper = objectMapper;
}
@PostMapping(
value = "/csrf/feedback/message",

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.csrf;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.CurrentUsername;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
@ -32,7 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"csrf-login-hint1", "csrf-login-hint2", "csrf-login-hint3"})
public class CSRFLogin extends AssignmentEndpoint {
public class CSRFLogin implements AssignmentEndpoint {
@PostMapping(
path = "/csrf/login",

View File

@ -22,6 +22,8 @@
package org.owasp.webgoat.lessons.csrf;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import static org.springframework.http.MediaType.ALL_VALUE;
import com.google.common.collect.Lists;
@ -45,7 +47,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"csrf-review-hint1", "csrf-review-hint2", "csrf-review-hint3"})
public class ForgedReviews extends AssignmentEndpoint {
public class ForgedReviews implements AssignmentEndpoint {
private static DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd, HH:mm:ss");

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.deserialization;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InvalidClassException;
@ -42,7 +45,7 @@ import org.springframework.web.bind.annotation.RestController;
"insecure-deserialization.hints.2",
"insecure-deserialization.hints.3"
})
public class InsecureDeserializationTask extends AssignmentEndpoint {
public class InsecureDeserializationTask implements AssignmentEndpoint {
@PostMapping("/InsecureDeserialization/task")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.hijacksession;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
@ -30,7 +33,6 @@ import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.lessons.hijacksession.cas.Authentication;
import org.owasp.webgoat.lessons.hijacksession.cas.HijackSessionAuthenticationProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -51,11 +53,14 @@ import org.springframework.web.bind.annotation.RestController;
"hijacksession.hints.4",
"hijacksession.hints.5"
})
public class HijackSessionAssignment extends AssignmentEndpoint {
public class HijackSessionAssignment implements AssignmentEndpoint {
private static final String COOKIE_NAME = "hijack_cookie";
@Autowired HijackSessionAuthenticationProvider provider;
private final HijackSessionAuthenticationProvider provider;
public HijackSessionAssignment(HijackSessionAuthenticationProvider provider) {
this.provider = provider;
}
@PostMapping(path = "/HijackSession/login")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.htmltampering;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -32,7 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"hint1", "hint2", "hint3"})
public class HtmlTamperingTask extends AssignmentEndpoint {
public class HtmlTamperingTask implements AssignmentEndpoint {
@PostMapping("/HtmlTampering/task")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.httpbasics;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -32,7 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"http-basics.hints.http_basics_lesson.1"})
public class HttpBasicsLesson extends AssignmentEndpoint {
public class HttpBasicsLesson implements AssignmentEndpoint {
@PostMapping("/HttpBasics/attack1")
@ResponseBody

View File

@ -22,9 +22,11 @@
package org.owasp.webgoat.lessons.httpbasics;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AssignmentPath;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -33,8 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"http-basics.hints.http_basic_quiz.1", "http-basics.hints.http_basic_quiz.2"})
@AssignmentPath("HttpBasics/attack2")
public class HttpBasicsQuiz extends AssignmentEndpoint {
public class HttpBasicsQuiz implements AssignmentEndpoint {
@PostMapping("/HttpBasics/attack2")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.httpproxies;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.HttpServletRequest;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -34,7 +37,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HttpBasicsInterceptRequest extends AssignmentEndpoint {
public class HttpBasicsInterceptRequest implements AssignmentEndpoint {
@RequestMapping(
path = "/HttpProxies/intercept-request",

View File

@ -23,6 +23,9 @@
package org.owasp.webgoat.lessons.idor;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -37,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController;
"idor.hints.idorDiffAttributes2",
"idor.hints.idorDiffAttributes3"
})
public class IDORDiffAttributes extends AssignmentEndpoint {
public class IDORDiffAttributes implements AssignmentEndpoint {
@PostMapping("/IDOR/diff-attributes")
@ResponseBody

View File

@ -23,11 +23,13 @@
package org.owasp.webgoat.lessons.idor;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -46,9 +48,13 @@ import org.springframework.web.bind.annotation.RestController;
"idor.hints.otherProfile8",
"idor.hints.otherProfile9"
})
public class IDOREditOtherProfile extends AssignmentEndpoint {
public class IDOREditOtherProfile implements AssignmentEndpoint {
@Autowired private LessonSession userSessionData;
private final LessonSession userSessionData;
public IDOREditOtherProfile(LessonSession lessonSession) {
this.userSessionData = lessonSession;
}
@PutMapping(path = "/IDOR/profile/{userId}", consumes = "application/json")
@ResponseBody

View File

@ -23,6 +23,9 @@
package org.owasp.webgoat.lessons.idor;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.util.HashMap;
import java.util.Map;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -36,15 +39,14 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"idor.hints.idor_login"})
public class IDORLogin extends AssignmentEndpoint {
public class IDORLogin implements AssignmentEndpoint {
private final LessonSession lessonSession;
public IDORLogin(LessonSession lessonSession) {
this.lessonSession = lessonSession;
}
private Map<String, Map<String, String>> idorUserInfo = new HashMap<>();
private final Map<String, Map<String, String>> idorUserInfo = new HashMap<>();
public void initIDORInfo() {

View File

@ -23,12 +23,13 @@
package org.owasp.webgoat.lessons.idor;
import jakarta.servlet.http.HttpServletResponse;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
@ -46,15 +47,19 @@ import org.springframework.web.bind.annotation.RestController;
"idor.hints.otherProfile8",
"idor.hints.otherProfile9"
})
public class IDORViewOtherProfile extends AssignmentEndpoint {
public class IDORViewOtherProfile implements AssignmentEndpoint {
@Autowired LessonSession userSessionData;
private final LessonSession userSessionData;
public IDORViewOtherProfile(LessonSession userSessionData) {
this.userSessionData = userSessionData;
}
@GetMapping(
path = "/IDOR/profile/{userId}",
produces = {"application/json"})
@ResponseBody
public AttackResult completed(@PathVariable("userId") String userId, HttpServletResponse resp) {
public AttackResult completed(@PathVariable("userId") String userId) {
Object obj = userSessionData.getValue("idor-authenticated-as");
if (obj != null && obj.equals("tom")) {

View File

@ -27,7 +27,6 @@ import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@ -36,7 +35,11 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
public class IDORViewOwnProfile {
@Autowired LessonSession userSessionData;
private final LessonSession userSessionData;
public IDORViewOwnProfile(LessonSession userSessionData) {
this.userSessionData = userSessionData;
}
@GetMapping(
path = {"/IDOR/own", "/IDOR/profile"},
@ -60,7 +63,7 @@ public class IDORViewOwnProfile {
"You do not have privileges to view the profile. Authenticate as tom first please.");
}
} catch (Exception ex) {
log.error("something went wrong", ex.getMessage());
log.error("something went wrong: {}", ex.getMessage());
}
return details;
}

View File

@ -23,11 +23,13 @@
package org.owasp.webgoat.lessons.idor;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@ -39,9 +41,12 @@ import org.springframework.web.bind.annotation.RestController;
"idor.hints.ownProfileAltUrl2",
"idor.hints.ownProfileAltUrl3"
})
public class IDORViewOwnProfileAltUrl extends AssignmentEndpoint {
public class IDORViewOwnProfileAltUrl implements AssignmentEndpoint {
private final LessonSession userSessionData;
@Autowired LessonSession userSessionData;
public IDORViewOwnProfileAltUrl(LessonSession userSessionData) {
this.userSessionData = userSessionData;
}
@PostMapping("/IDOR/profile/alt-path")
@ResponseBody

View File

@ -22,13 +22,16 @@
package org.owasp.webgoat.lessons.insecurelogin;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@RestController
public class InsecureLoginTask extends AssignmentEndpoint {
public class InsecureLoginTask implements AssignmentEndpoint {
@PostMapping("/InsecureLogin/task")
@ResponseBody

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.lessons.jwt;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.PostMapping;
@ -8,7 +11,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class JWTDecodeEndpoint extends AssignmentEndpoint {
public class JWTDecodeEndpoint implements AssignmentEndpoint {
@PostMapping("/JWT/decode")
@ResponseBody

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.lessons.jwt;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.GetMapping;
@ -9,7 +12,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class JWTQuiz extends AssignmentEndpoint {
public class JWTQuiz implements AssignmentEndpoint {
private final String[] solutions = {"Solution 1", "Solution 2"};
private final boolean[] guesses = new boolean[solutions.length];

View File

@ -22,6 +22,8 @@
package org.owasp.webgoat.lessons.jwt;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import static org.springframework.http.ResponseEntity.ok;
import io.jsonwebtoken.Claims;
@ -56,7 +58,7 @@ import org.springframework.web.bind.annotation.RestController;
"jwt-refresh-hint3",
"jwt-refresh-hint4"
})
public class JWTRefreshEndpoint extends AssignmentEndpoint {
public class JWTRefreshEndpoint implements AssignmentEndpoint {
public static final String PASSWORD = "bm5nhSkxCXZkKRy4";
private static final String JWT_PASSWORD = "bm5n3SkxCX4kKRy4";

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.jwt;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
@ -44,7 +47,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"jwt-secret-hint1", "jwt-secret-hint2", "jwt-secret-hint3"})
public class JWTSecretKeyEndpoint extends AssignmentEndpoint {
public class JWTSecretKeyEndpoint implements AssignmentEndpoint {
public static final String[] SECRETS = {
"victory", "business", "available", "shipping", "washington"

View File

@ -25,6 +25,8 @@ 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 static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
@ -66,13 +68,13 @@ import org.springframework.web.bind.annotation.RestController;
"jwt-change-token-hint4",
"jwt-change-token-hint5"
})
public class JWTVotesEndpoint extends AssignmentEndpoint {
public class JWTVotesEndpoint implements AssignmentEndpoint {
public static final String JWT_PASSWORD = TextCodec.BASE64.encode("victory");
private static String validUsers = "TomJerrySylvester";
private static int totalVotes = 38929;
private Map<String, Vote> votes = new HashMap<>();
private final Map<String, Vote> votes = new HashMap<>();
@PostConstruct
public void initVotes() {

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.lessons.jwt.claimmisuse;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import com.auth0.jwk.JwkException;
import com.auth0.jwk.JwkProviderBuilder;
import com.auth0.jwt.JWT;
@ -28,7 +31,7 @@ import org.springframework.web.bind.annotation.RestController;
"jwt-jku-hint4",
"jwt-jku-hint5"
})
public class JWTHeaderJKUEndpoint extends AssignmentEndpoint {
public class JWTHeaderJKUEndpoint implements AssignmentEndpoint {
@PostMapping("jku/follow/{user}")
public @ResponseBody String follow(@PathVariable("user") String user) {

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.jwt.claimmisuse;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwt;
@ -53,8 +56,7 @@ import org.springframework.web.bind.annotation.RestController;
"jwt-kid-hint6"
})
@RequestMapping("/JWT/")
public class JWTHeaderKIDEndpoint extends AssignmentEndpoint {
public class JWTHeaderKIDEndpoint implements AssignmentEndpoint {
private final LessonDataSource dataSource;
private JWTHeaderKIDEndpoint(LessonDataSource dataSource) {

View File

@ -22,13 +22,15 @@
package org.owasp.webgoat.lessons.lessontemplate;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.util.List;
import lombok.AllArgsConstructor;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@ -39,12 +41,14 @@ import org.springframework.web.bind.annotation.RestController;
/** 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 {
public class SampleAttack implements AssignmentEndpoint {
private static final String secretValue = "secr37Value";
String secretValue = "secr37Value";
private final LessonSession userSessionData;
// UserSessionData is bound to session and can be used to persist data across multiple assignments
@Autowired LessonSession userSessionData;
public SampleAttack(LessonSession userSessionData) {
this.userSessionData = userSessionData;
}
@PostMapping("/lesson-template/sample-attack")
@ResponseBody

View File

@ -22,7 +22,9 @@
package org.owasp.webgoat.lessons.logging;
import jakarta.annotation.PostConstruct;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.UUID;
@ -37,14 +39,13 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LogBleedingTask extends AssignmentEndpoint {
public class LogBleedingTask implements AssignmentEndpoint {
Logger log = LoggerFactory.getLogger(this.getClass().getName());
private String password;
private static final Logger log = LoggerFactory.getLogger(LogBleedingTask.class);
private final String password;
@PostConstruct
public void generatePassword() {
password = UUID.randomUUID().toString();
public LogBleedingTask() {
this.password = UUID.randomUUID().toString();
log.info(
"Password for admin: {}",
Base64.getEncoder().encodeToString(password.getBytes(StandardCharsets.UTF_8)));

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.logging;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.apache.logging.log4j.util.Strings;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -31,7 +34,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LogSpoofingTask extends AssignmentEndpoint {
public class LogSpoofingTask implements AssignmentEndpoint {
@PostMapping("/LogSpoofing/log-spoofing")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.missingac;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -36,7 +39,7 @@ import org.springframework.web.bind.annotation.RestController;
"access-control.hidden-menus.hint2",
"access-control.hidden-menus.hint3"
})
public class MissingFunctionACHiddenMenus extends AssignmentEndpoint {
public class MissingFunctionACHiddenMenus implements AssignmentEndpoint {
@PostMapping(
path = "/access-control/hidden-menu",

View File

@ -22,9 +22,10 @@
package org.owasp.webgoat.lessons.missingac;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
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;
@ -40,11 +41,14 @@ import org.springframework.web.bind.annotation.RestController;
"access-control.hash.hint4",
"access-control.hash.hint5"
})
@RequiredArgsConstructor
public class MissingFunctionACYourHash extends AssignmentEndpoint {
public class MissingFunctionACYourHash implements AssignmentEndpoint {
private final MissingAccessControlUserRepository userRepository;
public MissingFunctionACYourHash(MissingAccessControlUserRepository userRepository) {
this.userRepository = userRepository;
}
@PostMapping(
path = "/access-control/user-hash",
produces = {"application/json"})

View File

@ -22,6 +22,8 @@
package org.owasp.webgoat.lessons.missingac;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import static org.owasp.webgoat.lessons.missingac.MissingFunctionAC.PASSWORD_SALT_ADMIN;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -42,7 +44,7 @@ import org.springframework.web.bind.annotation.RestController;
"access-control.hash.hint12",
"access-control.hash.hint13"
})
public class MissingFunctionACYourHashAdmin extends AssignmentEndpoint {
public class MissingFunctionACYourHashAdmin implements AssignmentEndpoint {
private final MissingAccessControlUserRepository userRepository;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.passwordreset;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.util.HashMap;
import java.util.Map;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -37,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController;
* @since 8/20/17.
*/
@RestController
public class QuestionsAssignment extends AssignmentEndpoint {
public class QuestionsAssignment implements AssignmentEndpoint {
private static final Map<String, String> COLORS = new HashMap<>();

View File

@ -22,6 +22,8 @@
package org.owasp.webgoat.lessons.passwordreset;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import static org.springframework.util.StringUtils.hasText;
import com.google.common.collect.Maps;
@ -58,7 +60,7 @@ import org.springframework.web.servlet.ModelAndView;
"password-reset-hint5",
"password-reset-hint6"
})
public class ResetLinkAssignment extends AssignmentEndpoint {
public class ResetLinkAssignment implements AssignmentEndpoint {
private static final String VIEW_FORMATTER = "lessons/passwordreset/templates/%s.html";
static final String PASSWORD_TOM_9 =

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.passwordreset;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.HttpServletRequest;
import java.util.UUID;
import org.owasp.webgoat.container.CurrentUsername;
@ -44,12 +47,12 @@ import org.springframework.web.client.RestTemplate;
* @since 8/20/17.
*/
@RestController
public class ResetLinkAssignmentForgotPassword extends AssignmentEndpoint {
public class ResetLinkAssignmentForgotPassword implements AssignmentEndpoint {
private final RestTemplate restTemplate;
private String webWolfHost;
private String webWolfPort;
private String webWolfURL;
private final String webWolfHost;
private final String webWolfPort;
private final String webWolfURL;
private final String webWolfMailURL;
public ResetLinkAssignmentForgotPassword(

View File

@ -23,12 +23,13 @@
package org.owasp.webgoat.lessons.passwordreset;
import static java.util.Optional.of;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.informationMessage;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
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;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@ -41,9 +42,9 @@ import org.springframework.web.bind.annotation.RestController;
* @since 11.12.18
*/
@RestController
public class SecurityQuestionAssignment extends AssignmentEndpoint {
public class SecurityQuestionAssignment implements AssignmentEndpoint {
@Autowired private TriedQuestions triedQuestions;
private final TriedQuestions triedQuestions;
private static Map<String, String> questions;
@ -90,6 +91,10 @@ public class SecurityQuestionAssignment extends AssignmentEndpoint {
questions.put("What is your favorite color?", "Can easily be guessed.");
}
public SecurityQuestionAssignment(TriedQuestions triedQuestions) {
this.triedQuestions = triedQuestions;
}
@PostMapping("/PasswordReset/SecurityQuestions")
@ResponseBody
public AttackResult completed(@RequestParam String question) {

View File

@ -23,6 +23,9 @@
package org.owasp.webgoat.lessons.passwordreset;
import static java.util.Optional.ofNullable;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.informationMessage;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.time.LocalDateTime;
import org.apache.commons.lang3.StringUtils;
@ -43,8 +46,7 @@ import org.springframework.web.client.RestTemplate;
* @since 8/20/17.
*/
@RestController
public class SimpleMailAssignment extends AssignmentEndpoint {
public class SimpleMailAssignment implements AssignmentEndpoint {
private final String webWolfURL;
private RestTemplate restTemplate;

View File

@ -1,5 +1,9 @@
package org.owasp.webgoat.lessons.pathtraversal;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.informationMessage;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@ -7,7 +11,6 @@ import java.nio.file.Files;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.SneakyThrows;
import org.apache.commons.io.FilenameUtils;
@ -21,11 +24,14 @@ import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
@AllArgsConstructor
@Getter
public class ProfileUploadBase extends AssignmentEndpoint {
public class ProfileUploadBase implements AssignmentEndpoint {
private String webGoatHomeDirectory;
private final String webGoatHomeDirectory;
public ProfileUploadBase(String webGoatHomeDirectory) {
this.webGoatHomeDirectory = webGoatHomeDirectory;
}
protected AttackResult execute(MultipartFile file, String fullName, String username) {
if (file.isEmpty()) {

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.lessons.pathtraversal;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import java.io.File;
@ -40,8 +43,7 @@ import org.springframework.web.bind.annotation.RestController;
"path-traversal-profile-retrieve.hint6"
})
@Slf4j
public class ProfileUploadRetrieval extends AssignmentEndpoint {
public class ProfileUploadRetrieval implements AssignmentEndpoint {
private final File catPicturesDirectory;
public ProfileUploadRetrieval(@Value("${webgoat.server.directory}") String webGoatHomeDirectory) {

View File

@ -1,5 +1,7 @@
package org.owasp.webgoat.lessons.pathtraversal;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import static org.springframework.http.MediaType.ALL_VALUE;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.securepasswords;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import com.nulabinc.zxcvbn.Strength;
import com.nulabinc.zxcvbn.Zxcvbn;
import java.text.DecimalFormat;
@ -35,7 +38,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SecurePasswordsAssignment extends AssignmentEndpoint {
public class SecurePasswordsAssignment implements AssignmentEndpoint {
@PostMapping("SecurePasswords/assignment")
@ResponseBody

View File

@ -23,6 +23,10 @@
package org.owasp.webgoat.lessons.spoofcookie;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.informationMessage;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Map;
@ -48,7 +52,7 @@ import org.springframework.web.bind.annotation.RestController;
@AssignmentHints({"spoofcookie.hint1", "spoofcookie.hint2", "spoofcookie.hint3"})
@RestController
public class SpoofCookieAssignment extends AssignmentEndpoint {
public class SpoofCookieAssignment implements AssignmentEndpoint {
private static final String COOKIE_NAME = "spoof_auth";
private static final String COOKIE_INFO =

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.advanced;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.*;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.LessonDataSource;
@ -42,7 +45,7 @@ import org.springframework.web.bind.annotation.RestController;
@AssignmentHints(
value = {"SqlInjectionChallenge1", "SqlInjectionChallenge2", "SqlInjectionChallenge3"})
@Slf4j
public class SqlInjectionChallenge extends AssignmentEndpoint {
public class SqlInjectionChallenge implements AssignmentEndpoint {
private final LessonDataSource dataSource;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.advanced;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.LessonDataSource;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
@ -39,8 +42,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlInjectionChallengeHint3",
"SqlInjectionChallengeHint4"
})
public class SqlInjectionChallengeLogin extends AssignmentEndpoint {
public class SqlInjectionChallengeLogin implements AssignmentEndpoint {
private final LessonDataSource dataSource;
public SqlInjectionChallengeLogin(LessonDataSource dataSource) {

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.advanced;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
@ -46,8 +49,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint-advanced-6a-4",
"SqlStringInjectionHint-advanced-6a-5"
})
public class SqlInjectionLesson6a extends AssignmentEndpoint {
public class SqlInjectionLesson6a implements AssignmentEndpoint {
private final LessonDataSource dataSource;
private static final String YOUR_QUERY_WAS = "<br> Your query was: ";

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.advanced;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
@ -36,8 +39,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SqlInjectionLesson6b extends AssignmentEndpoint {
public class SqlInjectionLesson6b implements AssignmentEndpoint {
private final LessonDataSource dataSource;
public SqlInjectionLesson6b(LessonDataSource dataSource) {

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.advanced;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.io.IOException;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -37,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController;
* implement the quiz go to the quiz.js file in webgoat-container -> js
*/
@RestController
public class SqlInjectionQuiz extends AssignmentEndpoint {
public class SqlInjectionQuiz implements AssignmentEndpoint {
String[] solutions = {"Solution 4", "Solution 3", "Solution 2", "Solution 3", "Solution 4"};
boolean[] guesses = new boolean[solutions.length];

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.introduction;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -45,7 +48,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint.10.5",
"SqlStringInjectionHint.10.6"
})
public class SqlInjectionLesson10 extends AssignmentEndpoint {
public class SqlInjectionLesson10 implements AssignmentEndpoint {
private final LessonDataSource dataSource;
@ -120,8 +123,7 @@ public class SqlInjectionLesson10 extends AssignmentEndpoint {
if (errorMsg.contains("object not found: ACCESS_LOG")) {
return false;
} else {
System.err.println(e.getMessage());
return false;
return true;
}
}
}

View File

@ -24,6 +24,8 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction;
import static java.sql.ResultSet.CONCUR_READ_ONLY;
import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.ResultSet;
import java.sql.SQLException;
@ -45,7 +47,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint2-3",
"SqlStringInjectionHint2-4"
})
public class SqlInjectionLesson2 extends AssignmentEndpoint {
public class SqlInjectionLesson2 implements AssignmentEndpoint {
private final LessonDataSource dataSource;

View File

@ -24,6 +24,8 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction;
import static java.sql.ResultSet.CONCUR_READ_ONLY;
import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.Connection;
import java.sql.ResultSet;
@ -40,7 +42,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints(value = {"SqlStringInjectionHint3-1", "SqlStringInjectionHint3-2"})
public class SqlInjectionLesson3 extends AssignmentEndpoint {
public class SqlInjectionLesson3 implements AssignmentEndpoint {
private final LessonDataSource dataSource;

View File

@ -24,6 +24,8 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction;
import static java.sql.ResultSet.CONCUR_READ_ONLY;
import static java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.Connection;
import java.sql.ResultSet;
@ -41,7 +43,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints(
value = {"SqlStringInjectionHint4-1", "SqlStringInjectionHint4-2", "SqlStringInjectionHint4-3"})
public class SqlInjectionLesson4 extends AssignmentEndpoint {
public class SqlInjectionLesson4 implements AssignmentEndpoint {
private final LessonDataSource dataSource;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.introduction;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.annotation.PostConstruct;
import java.sql.Connection;
import java.sql.ResultSet;
@ -43,7 +46,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint5-3",
"SqlStringInjectionHint5-4"
})
public class SqlInjectionLesson5 extends AssignmentEndpoint {
public class SqlInjectionLesson5 implements AssignmentEndpoint {
private final LessonDataSource dataSource;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.introduction;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.*;
import org.owasp.webgoat.container.LessonDataSource;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -34,7 +37,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints(value = {"SqlStringInjectionHint5a1"})
public class SqlInjectionLesson5a extends AssignmentEndpoint {
public class SqlInjectionLesson5a implements AssignmentEndpoint {
private static final String EXPLANATION =
"<br> Explanation: This injection works, because <span style=\"font-style: italic\">or '1' ="

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.introduction;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.io.IOException;
import java.sql.*;
import org.owasp.webgoat.container.LessonDataSource;
@ -41,7 +44,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint5b3",
"SqlStringInjectionHint5b4"
})
public class SqlInjectionLesson5b extends AssignmentEndpoint {
public class SqlInjectionLesson5b implements AssignmentEndpoint {
private final LessonDataSource dataSource;

View File

@ -24,6 +24,8 @@ package org.owasp.webgoat.lessons.sqlinjection.introduction;
import static java.sql.ResultSet.CONCUR_UPDATABLE;
import static java.sql.ResultSet.TYPE_SCROLL_SENSITIVE;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.*;
import java.text.SimpleDateFormat;
@ -46,7 +48,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint.8.4",
"SqlStringInjectionHint.8.5"
})
public class SqlInjectionLesson8 extends AssignmentEndpoint {
public class SqlInjectionLesson8 implements AssignmentEndpoint {
private final LessonDataSource dataSource;

View File

@ -24,6 +24,8 @@ 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 static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.Connection;
import java.sql.ResultSet;
@ -47,7 +49,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint.9.4",
"SqlStringInjectionHint.9.5"
})
public class SqlInjectionLesson9 extends AssignmentEndpoint {
public class SqlInjectionLesson9 implements AssignmentEndpoint {
private final LessonDataSource dataSource;
@ -99,7 +101,6 @@ public class SqlInjectionLesson9 extends AssignmentEndpoint {
SqlInjectionLesson8.generateTable(this.getEmployeesDataOrderBySalaryDesc(connection)))
.build();
} catch (SQLException e) {
System.err.println(e.getMessage());
return failed(this)
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
.build();

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.mitigation;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
@ -35,9 +38,9 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j
@AssignmentHints(
value = {"SqlStringInjectionHint-mitigation-10a-1", "SqlStringInjectionHint-mitigation-10a-2"})
public class SqlInjectionLesson10a extends AssignmentEndpoint {
public class SqlInjectionLesson10a implements AssignmentEndpoint {
private String[] results = {
private static final String[] results = {
"getConnection", "PreparedStatement", "prepareStatement", "?", "?", "setString", "setString"
};

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.mitigation;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
@ -52,7 +55,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint-mitigation-10b-4",
"SqlStringInjectionHint-mitigation-10b-5"
})
public class SqlInjectionLesson10b extends AssignmentEndpoint {
public class SqlInjectionLesson10b implements AssignmentEndpoint {
@PostMapping("/SqlInjectionMitigations/attack10b")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.sqlinjection.mitigation;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -45,7 +48,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlStringInjectionHint-mitigation-13-4"
})
@Slf4j
public class SqlInjectionLesson13 extends AssignmentEndpoint {
public class SqlInjectionLesson13 implements AssignmentEndpoint {
private final LessonDataSource dataSource;
@ -68,7 +71,7 @@ public class SqlInjectionLesson13 extends AssignmentEndpoint {
return failed(this).build();
} catch (SQLException e) {
log.error("Failed", e);
return (failed(this).build());
return failed(this).build();
}
}
}

View File

@ -22,6 +22,8 @@
package org.owasp.webgoat.lessons.sqlinjection.mitigation;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -34,7 +36,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints(
value = {"SqlOnlyInputValidation-1", "SqlOnlyInputValidation-2", "SqlOnlyInputValidation-3"})
public class SqlOnlyInputValidation extends AssignmentEndpoint {
public class SqlOnlyInputValidation implements AssignmentEndpoint {
private final SqlInjectionLesson6a lesson6a;
@ -52,7 +54,9 @@ public class SqlOnlyInputValidation extends AssignmentEndpoint {
return new AttackResult(
attackResult.isLessonCompleted(),
attackResult.getFeedback(),
attackResult.getFeedbackArgs(),
attackResult.getOutput(),
attackResult.getOutputArgs(),
getClass().getSimpleName(),
true);
}

View File

@ -22,6 +22,8 @@
package org.owasp.webgoat.lessons.sqlinjection.mitigation;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -38,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController;
"SqlOnlyInputValidationOnKeywords-2",
"SqlOnlyInputValidationOnKeywords-3"
})
public class SqlOnlyInputValidationOnKeywords extends AssignmentEndpoint {
public class SqlOnlyInputValidationOnKeywords implements AssignmentEndpoint {
private final SqlInjectionLesson6a lesson6a;
@ -58,7 +60,9 @@ public class SqlOnlyInputValidationOnKeywords extends AssignmentEndpoint {
return new AttackResult(
attackResult.isLessonCompleted(),
attackResult.getFeedback(),
attackResult.getFeedbackArgs(),
attackResult.getOutput(),
attackResult.getOutputArgs(),
getClass().getSimpleName(),
true);
}

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.ssrf;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -32,7 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"ssrf.hint1", "ssrf.hint2"})
public class SSRFTask1 extends AssignmentEndpoint {
public class SSRFTask1 implements AssignmentEndpoint {
@PostMapping("/SSRF/task1")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.ssrf;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
@ -37,7 +40,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"ssrf.hint3"})
public class SSRFTask2 extends AssignmentEndpoint {
public class SSRFTask2 implements AssignmentEndpoint {
@PostMapping("/SSRF/task2")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.vulnerablecomponents;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import com.thoughtworks.xstream.XStream;
import org.apache.commons.lang3.StringUtils;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -34,7 +37,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"vulnerable.hint"})
public class VulnerableComponentsLesson extends AssignmentEndpoint {
public class VulnerableComponentsLesson implements AssignmentEndpoint {
@PostMapping("/VulnerableComponents/attack1")
public @ResponseBody AttackResult completed(@RequestParam String payload) {

View File

@ -22,9 +22,9 @@
package org.owasp.webgoat.lessons.webwolfintroduction;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URI;
import java.net.URISyntaxException;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.apache.commons.lang3.StringUtils;
import org.owasp.webgoat.container.CurrentUsername;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -41,10 +41,12 @@ import org.springframework.web.servlet.ModelAndView;
* @since 8/20/17.
*/
@RestController
public class LandingAssignment extends AssignmentEndpoint {
public class LandingAssignment implements AssignmentEndpoint {
private final String landingPageUrl;
@Value("${webwolf.landingpage.url}")
private String landingPageUrl;
public LandingAssignment(@Value("${webwolf.landingpage.url}") String landingPageUrl) {
this.landingPageUrl = landingPageUrl;
}
@PostMapping("/WebWolf/landing")
@ResponseBody
@ -56,9 +58,7 @@ public class LandingAssignment extends AssignmentEndpoint {
}
@GetMapping("/WebWolf/landing/password-reset")
public ModelAndView openPasswordReset(
HttpServletRequest request, @CurrentUsername String username) throws URISyntaxException {
URI uri = new URI(request.getRequestURL().toString());
public ModelAndView openPasswordReset(@CurrentUsername String username) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject(
"webwolfLandingPageUrl", landingPageUrl.replace("//landing", "/landing"));

View File

@ -22,6 +22,10 @@
package org.owasp.webgoat.lessons.webwolfintroduction;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.informationMessage;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.apache.commons.lang3.StringUtils;
import org.owasp.webgoat.container.CurrentUsername;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -39,7 +43,7 @@ import org.springframework.web.client.RestTemplate;
* @since 8/20/17.
*/
@RestController
public class MailAssignment extends AssignmentEndpoint {
public class MailAssignment implements AssignmentEndpoint {
private final String webWolfURL;
private RestTemplate restTemplate;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.xss;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.web.bind.annotation.PostMapping;
@ -30,7 +33,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CrossSiteScriptingLesson1 extends AssignmentEndpoint {
public class CrossSiteScriptingLesson1 implements AssignmentEndpoint {
@PostMapping("/CrossSiteScripting/attack1")
@ResponseBody

View File

@ -22,13 +22,15 @@
package org.owasp.webgoat.lessons.xss;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
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;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@ -42,13 +44,18 @@ import org.springframework.web.bind.annotation.RestController;
"xss-reflected-5a-hint-3",
"xss-reflected-5a-hint-4"
})
public class CrossSiteScriptingLesson5a extends AssignmentEndpoint {
public class CrossSiteScriptingLesson5a implements AssignmentEndpoint {
public static final Predicate<String> XSS_PATTERN =
Pattern.compile(
".*<script>(console\\.log|alert)\\(.*\\);?</script>.*", Pattern.CASE_INSENSITIVE)
.asMatchPredicate();
@Autowired LessonSession userSessionData;
private final LessonSession userSessionData;
public CrossSiteScriptingLesson5a(LessonSession lessonSession) {
this.userSessionData = lessonSession;
}
@GetMapping("/CrossSiteScripting/attack5a")
@ResponseBody

View File

@ -22,11 +22,13 @@
package org.owasp.webgoat.lessons.xss;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.container.session.LessonSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@ -40,8 +42,12 @@ import org.springframework.web.bind.annotation.RestController;
"xss-reflected-6a-hint-3",
"xss-reflected-6a-hint-4"
})
public class CrossSiteScriptingLesson6a extends AssignmentEndpoint {
@Autowired LessonSession userSessionData;
public class CrossSiteScriptingLesson6a implements AssignmentEndpoint {
private final LessonSession userSessionData;
public CrossSiteScriptingLesson6a(LessonSession userSessionData) {
this.userSessionData = userSessionData;
}
@PostMapping("/CrossSiteScripting/attack6a")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.xss;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import java.io.IOException;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -32,9 +35,11 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CrossSiteScriptingQuiz extends AssignmentEndpoint {
public class CrossSiteScriptingQuiz implements AssignmentEndpoint {
String[] solutions = {"Solution 4", "Solution 3", "Solution 1", "Solution 2", "Solution 4"};
private static final String[] solutions = {
"Solution 4", "Solution 3", "Solution 1", "Solution 2", "Solution 4"
};
boolean[] guesses = new boolean[solutions.length];
@PostMapping("/CrossSiteScripting/quiz")

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.xss;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import jakarta.servlet.http.HttpServletRequest;
import java.security.SecureRandom;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -33,7 +36,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DOMCrossSiteScripting extends AssignmentEndpoint {
public class DOMCrossSiteScripting implements AssignmentEndpoint {
private final LessonSession lessonSession;

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.xss;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -42,7 +45,7 @@ import org.springframework.web.bind.annotation.RestController;
"xss-dom-message-hint-5",
"xss-dom-message-hint-6"
})
public class DOMCrossSiteScriptingVerifier extends AssignmentEndpoint {
public class DOMCrossSiteScriptingVerifier implements AssignmentEndpoint {
private final LessonSession lessonSession;

View File

@ -23,6 +23,9 @@
package org.owasp.webgoat.lessons.xss.mitigation;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -41,7 +44,7 @@ import org.springframework.web.bind.annotation.RestController;
"xss-mitigation-3-hint3",
"xss-mitigation-3-hint4"
})
public class CrossSiteScriptingLesson3 extends AssignmentEndpoint {
public class CrossSiteScriptingLesson3 implements AssignmentEndpoint {
@PostMapping("/CrossSiteScripting/attack3")
@ResponseBody

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.xss.mitigation;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -32,7 +35,7 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints(value = {"xss-mitigation-4-hint1"})
public class CrossSiteScriptingLesson4 extends AssignmentEndpoint {
public class CrossSiteScriptingLesson4 implements AssignmentEndpoint {
@PostMapping("/CrossSiteScripting/attack4")
@ResponseBody

Some files were not shown because too many files have changed in this diff Show More