Merge branch 'feature/spring-boot' of https://github.com/WebGoat/WebGoat into feature/spring-boot

This commit is contained in:
mayhew64 2016-11-15 07:11:43 -05:00
commit dad7bdba92
27 changed files with 321 additions and 579 deletions

View File

@ -161,11 +161,7 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId> <groupId>com.fasterxml.jackson.dataformat</groupId>
@ -264,6 +260,11 @@
<!-- ************* END spring MVC and related dependencies ************** --> <!-- ************* END spring MVC and related dependencies ************** -->
<!-- ************* START: Dependencies for Unit and Integration Testing ************** --> <!-- ************* START: Dependencies for Unit and Integration Testing ************** -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>

View File

@ -52,7 +52,6 @@ public class HammerHead {
/** /**
* Entry point for WebGoat, redirects to the first lesson found within the course. * Entry point for WebGoat, redirects to the first lesson found within the course.
*/ */
//// TODO: 11/6/2016 course necessary?
@RequestMapping(path = "/attack", method = {RequestMethod.GET, RequestMethod.POST}) @RequestMapping(path = "/attack", method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView attack() { public ModelAndView attack() {
return new ModelAndView("redirect:" + "start.mvc" + course.getFirstLesson().getLink()); return new ModelAndView("redirect:" + "start.mvc" + course.getFirstLesson().getLink());

View File

@ -30,14 +30,17 @@
*/ */
package org.owasp.webgoat; package org.owasp.webgoat;
import lombok.SneakyThrows;
import org.owasp.webgoat.plugins.Plugin; import org.owasp.webgoat.plugins.Plugin;
import org.owasp.webgoat.plugins.PluginClassLoader; import org.owasp.webgoat.plugins.PluginClassLoader;
import org.owasp.webgoat.plugins.PluginEndpointPublisher; import org.owasp.webgoat.plugins.PluginEndpointPublisher;
import org.owasp.webgoat.plugins.PluginsLoader; import org.owasp.webgoat.plugins.PluginsLoader;
import org.owasp.webgoat.session.Course; import org.owasp.webgoat.session.Course;
import org.owasp.webgoat.session.UserTracker;
import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.session.WebgoatContext; import org.owasp.webgoat.session.WebgoatContext;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
@ -62,15 +65,10 @@ public class WebGoat extends SpringBootServletInitializer {
} }
@Bean(name = "pluginTargetDirectory") @Bean(name = "pluginTargetDirectory")
public File pluginTargetDirectory() { public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
return com.google.common.io.Files.createTempDir(); return new File(webgoatHome);
} }
// @Bean
// public ApplicationListener<ContextClosedEvent> closeEvent(@Qualifier("pluginTargetDirectory") File pluginTargetDirectory) {
// return e -> pluginTargetDirectory.delete();
// }
@Bean @Bean
public PluginClassLoader pluginClassLoader() { public PluginClassLoader pluginClassLoader() {
return new PluginClassLoader(PluginClassLoader.class.getClassLoader()); return new PluginClassLoader(PluginClassLoader.class.getClassLoader());
@ -96,4 +94,14 @@ public class WebGoat extends SpringBootServletInitializer {
return course; return course;
} }
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
@SneakyThrows
public UserTracker userTracker(@Value("${webgoat.user.directory}") final String webgoatHome, WebSession webSession) {
UserTracker userTracker = new UserTracker(webgoatHome, webSession.getUserName());
userTracker.load();
return userTracker;
}
} }

View File

@ -1,5 +1,7 @@
package org.owasp.webgoat.lessons; package org.owasp.webgoat.lessons;
import lombok.Getter;
import lombok.Setter;
import org.owasp.webgoat.session.Screen; import org.owasp.webgoat.session.Screen;
import java.util.List; import java.util.List;
@ -42,6 +44,10 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
private Integer ranking; private Integer ranking;
@Setter
@Getter
private List<Class<Assignment>> assignments;
/** /**
* Constructor for the Lesson object * Constructor for the Lesson object
*/ */
@ -49,6 +55,7 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
id = new Integer(++count); id = new Integer(++count);
} }
/** /**
* <p>getName.</p> * <p>getName.</p>
* *
@ -135,6 +142,7 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
/** /**
* <p>getHints.</p> * <p>getHints.</p>
*
* @return a {@link java.util.List} object. * @return a {@link java.util.List} object.
*/ */
public abstract List<String> getHints(); public abstract List<String> getHints();
@ -198,8 +206,7 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
public String getLink() { public String getLink() {
StringBuffer link = new StringBuffer(getPath()); return String.format("%s%s.lesson", getPath(), getId());
return link.append(getId()).toString();
} }
/** /**
@ -211,7 +218,5 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
return getTitle(); return getTitle();
} }
public String getId() { public abstract String getId();
return "";
}
} }

View File

@ -0,0 +1,59 @@
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*/
package org.owasp.webgoat.lessons;
import org.owasp.webgoat.lessons.model.AttackResult;
import org.owasp.webgoat.session.UserTracker;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Each lesson can define an endpoint which can support the lesson. So for example if you create a lesson which uses JavaScript and
* needs to call out to the server to fetch data you can define an endpoint in that lesson. WebGoat will pick up this endpoint and
* Spring will publish it.
* </p>
* Extend this class and implement the met
* </p>
* Note: each subclass should declare this annotation otherwise the WebGoat framework cannot find your endpoint.
*/
public abstract class Assignment extends Endpoint {
@Autowired
private UserTracker userTracker;
@Autowired
private WebSession webSession;
//// TODO: 11/13/2016 events better fit?
protected AttackResult trackProgress(AttackResult attackResult) {
if (attackResult.assignmentSolved()) {
userTracker.assignmentSolved(webSession.getCurrentLesson(), this);
} else {
userTracker.assignmentFailed(webSession.getCurrentLesson());
}
return attackResult;
}
}

View File

@ -1,3 +1,11 @@
package org.owasp.webgoat.lessons;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import java.io.File;
/** /**
* ************************************************************************************************ * ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, * This file is part of WebGoat, an Open Web Application Security Project utility. For details,
@ -22,36 +30,16 @@
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects. * projects.
* <p> * <p>
*
* @author nbaars
* @version $Id: $Id
* @since November 13, 2016
*/ */
package org.owasp.webgoat.lessons; public abstract class Endpoint implements MvcEndpoint {
import org.owasp.webgoat.lessons.model.AttackResult;
import org.owasp.webgoat.session.LessonTracker;
import org.owasp.webgoat.session.UserTracker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import java.io.File;
/**
* Each lesson can define an endpoint which can support the lesson. So for example if you create a lesson which uses JavaScript and
* needs to call out to the server to fetch data you can define an endpoint in that lesson. WebGoat will pick up this endpoint and
* Spring will publish it.
* </p>
* Extend this class and implement the met
* </p>
* Note: each subclass should declare this annotation otherwise the WebGoat framework cannot find your endpoint.
*/
@LessonEndpointMapping
public abstract class AssignmentEndpoint implements MvcEndpoint {
@Autowired @Autowired
@Qualifier("pluginTargetDirectory") @Qualifier("pluginTargetDirectory")
private File pluginDirectory; private File pluginDirectory;
@Autowired
private UserTracker userTracker;
/** /**
* The directory of the plugin directory in which the lessons resides, so if you want to access the lesson 'ClientSideFiltering' you will * The directory of the plugin directory in which the lessons resides, so if you want to access the lesson 'ClientSideFiltering' you will
@ -69,23 +57,6 @@ public abstract class AssignmentEndpoint implements MvcEndpoint {
return new File(this.pluginDirectory, "plugin"); return new File(this.pluginDirectory, "plugin");
} }
/**
* Get the lesson tracker which is based on the current user and do the
* @return
*/
protected LessonTracker getLessonTracker() {
LessonTracker lessonTracker = userTracker.getCurrentLessonTracker();
return lessonTracker;
}
protected AttackResult trackProgress(AttackResult attackResult) {
//// TODO: 11/5/2016 improve
if (attackResult.isLessonCompleted()) {
getLessonTracker().incrementNumVisits();
}
getLessonTracker().setCompleted(attackResult.isLessonCompleted());
return attackResult;
}
@Override @Override
public final boolean isSensitive() { public final boolean isSensitive() {
@ -93,8 +64,7 @@ public abstract class AssignmentEndpoint implements MvcEndpoint {
} }
@Override @Override
public final Class<? extends Endpoint> getEndpointType() { public final Class<? extends org.springframework.boot.actuate.endpoint.Endpoint> getEndpointType() {
return null; return null;
} }
} }

View File

@ -30,6 +30,7 @@
*/ */
package org.owasp.webgoat.lessons; package org.owasp.webgoat.lessons;
//// TODO: 11/8/2016 remove
public abstract class LessonAdapter extends AbstractLesson { public abstract class LessonAdapter extends AbstractLesson {

View File

@ -1,49 +0,0 @@
/**
*************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author WebGoat
* @since December 12, 2015
* @version $Id: $Id
*/
package org.owasp.webgoat.lessons;
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation as a marker annotation. During the startup we scan the plugins for classes which use this annotation.
* @see AssignmentEndpoint for more information.
*/
@Component
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LessonEndpointMapping { }

View File

@ -1,9 +1,5 @@
package org.owasp.webgoat.lessons; package org.owasp.webgoat.lessons;
import lombok.Getter;
import lombok.Setter;
import org.owasp.webgoat.session.WebSession;
import java.util.List; import java.util.List;
/** /**
@ -37,9 +33,7 @@ import java.util.List;
*/ */
public abstract class NewLesson extends LessonAdapter { public abstract class NewLesson extends LessonAdapter {
@Setter
@Getter
private int totalNumberOfAssignments = 0;
@Override @Override
public abstract Category getDefaultCategory(); public abstract Category getDefaultCategory();
@ -55,10 +49,4 @@ public abstract class NewLesson extends LessonAdapter {
@Override @Override
public abstract String getId(); public abstract String getId();
public final List<String> getHints(WebSession w) {
throw new IllegalStateException("Do not use");
}
} }

View File

@ -1,5 +1,7 @@
package org.owasp.webgoat.lessons.model; package org.owasp.webgoat.lessons.model;
import lombok.Getter;
/** /**
* ************************************************************************************************ * ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, * This file is part of WebGoat, an Open Web Application Security Project utility. For details,
@ -29,6 +31,7 @@ package org.owasp.webgoat.lessons.model;
* @version $Id: $Id * @version $Id: $Id
* @since August 13, 2016 * @since August 13, 2016
*/ */
@Getter
public class AttackResult { public class AttackResult {
private boolean lessonCompleted; private boolean lessonCompleted;
@ -54,15 +57,7 @@ public class AttackResult {
return attackResult; return attackResult;
} }
public boolean isLessonCompleted() { public boolean assignmentSolved() {
return lessonCompleted; return lessonCompleted;
} }
public String getFeedback() {
return feedback;
}
public String getOutput() {
return output;
}
} }

View File

@ -1,5 +1,6 @@
package org.owasp.webgoat.lessons.model; package org.owasp.webgoat.lessons.model;
import lombok.Getter;
import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.session.WebSession;
@ -10,6 +11,7 @@ import org.owasp.webgoat.session.WebSession;
* @version $Id: $Id * @version $Id: $Id
*/ */
//// TODO: 11/5/2016 this can be removed??? //// TODO: 11/5/2016 this can be removed???
@Getter
public class LessonInfoModel { public class LessonInfoModel {
private String lessonTitle; private String lessonTitle;

View File

@ -3,18 +3,16 @@ package org.owasp.webgoat.plugins;
import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.AssignmentEndpoint; import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.Endpoint;
import org.owasp.webgoat.lessons.NewLesson; import org.owasp.webgoat.lessons.NewLesson;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import static org.owasp.webgoat.plugins.PluginFileUtils.fileEndsWith; import static org.owasp.webgoat.plugins.PluginFileUtils.fileEndsWith;
import static org.owasp.webgoat.plugins.PluginFileUtils.hasParentDirectoryWithName;
/** /**
* <p>Plugin class.</p> * <p>Plugin class.</p>
@ -24,23 +22,22 @@ import static org.owasp.webgoat.plugins.PluginFileUtils.hasParentDirectoryWithNa
*/ */
public class Plugin { public class Plugin {
private static final String NAME_LESSON_SOLUTION_DIRECTORY = "lessonSolutions";
private static final String NAME_LESSON_PLANS_DIRECTORY = "lessonPlans";
private PluginClassLoader classLoader; private PluginClassLoader classLoader;
private Class<NewLesson> newLesson; private Class<NewLesson> newLesson;
private List<Class<AssignmentEndpoint>> lessonEndpoints = Lists.newArrayList(); private List<Class<Assignment>> assignments = Lists.newArrayList();
private Map<String, File> solutionLanguageFiles = new HashMap<>(); private List<Class<Endpoint>> endpoints = Lists.newArrayList();
private Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
private List<File> pluginFiles = Lists.newArrayList(); private List<File> pluginFiles = Lists.newArrayList();
private File lessonSourceFile;
public Plugin(PluginClassLoader classLoader) { public Plugin(PluginClassLoader classLoader) {
this.classLoader = classLoader; this.classLoader = classLoader;
} }
public List<Class<AssignmentEndpoint>> getLessonEndpoints() { public List<Class<Assignment>> getAssignments() {
return this.lessonEndpoints; return this.assignments;
}
public List<Class<Endpoint>> getEndpoints() {
return this.endpoints;
} }
/** /**
@ -74,8 +71,10 @@ public class Plugin {
try { try {
Class clazz = classLoader.loadClass(realClassName); Class clazz = classLoader.loadClass(realClassName);
if (AssignmentEndpoint.class.isAssignableFrom(clazz)) { if (Assignment.class.isAssignableFrom(clazz)) {
this.lessonEndpoints.add(clazz); this.assignments.add(clazz);
} else if (Endpoint.class.isAssignableFrom(clazz)) {
this.endpoints.add(clazz);
} }
} catch (ClassNotFoundException ce) { } catch (ClassNotFoundException ce) {
throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce); throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce);
@ -89,16 +88,6 @@ public class Plugin {
* @param file a {@link java.nio.file.Path} object. * @param file a {@link java.nio.file.Path} object.
*/ */
public void loadFiles(Path file) { public void loadFiles(Path file) {
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_SOLUTION_DIRECTORY)) {
solutionLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_PLANS_DIRECTORY)) {
lessonPlansLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
if (fileEndsWith(file, ".java")) {
lessonSourceFile = file.toFile();
}
if (fileEndsWith(file, ".css", ".jsp", ".js")) { if (fileEndsWith(file, ".css", ".jsp", ".js")) {
pluginFiles.add(file.toFile()); pluginFiles.add(file.toFile());
} }
@ -106,13 +95,14 @@ public class Plugin {
/** /**
* Lesson is optional, it is also possible that the supplied jar contains only helper classes. * Lesson is optional, it is also possible that the supplied jar contains only helper classes.
* Lesson could be a new lesson (adoc based) or still ECS based.
* *
* @return a {@link com.google.common.base.Optional} object. * @return a {@link com.google.common.base.Optional} object.
*/ */
public Optional<AbstractLesson> getLesson() { public Optional<AbstractLesson> getLesson() {
try { try {
if (newLesson != null) { if (newLesson != null) {
AbstractLesson lesson = newLesson.newInstance();
lesson.setAssignments(this.assignments);
return Optional.of(newLesson.newInstance()); return Optional.of(newLesson.newInstance());
} }
} catch (IllegalAccessException | InstantiationException e) { } catch (IllegalAccessException | InstantiationException e) {
@ -121,42 +111,5 @@ public class Plugin {
return Optional.absent(); return Optional.absent();
} }
/**
* <p>getLessonSolution.</p>
*
* @param language a {@link java.lang.String} object.
* @return a {@link com.google.common.base.Optional} object.
*/
public Optional<File> getLessonSolution(String language) {
return Optional.fromNullable(this.solutionLanguageFiles.get(language));
}
/**
* <p>getLessonSolutions.</p>
*
* @return a {@link java.util.Map} object.
*/
public Map<String, File> getLessonSolutions() {
return this.solutionLanguageFiles;
}
/**
* <p>getLessonSource.</p>
*
* @return a {@link com.google.common.base.Optional} object.
*/
public Optional<File> getLessonSource() {
return Optional.fromNullable(lessonSourceFile);
}
/**
* <p>getLessonPlans.</p>
*
* @return a {@link java.util.Map} object.
*/
public Map<String, File> getLessonPlans() {
return this.lessonPlansLanguageFiles;
}
} }

View File

@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -49,7 +50,11 @@ public class PluginEndpointPublisher {
} }
public void publish(Plugin plugin) { public void publish(Plugin plugin) {
plugin.getLessonEndpoints().forEach(e -> { plugin.getAssignments().forEach(e -> publishEndpoint(e));
plugin.getEndpoints().forEach(e -> publishEndpoint(e));
}
private void publishEndpoint(Class<? extends MvcEndpoint> e) {
try { try {
BeanDefinition beanDefinition = new RootBeanDefinition(e, Autowire.BY_TYPE.value(), true); BeanDefinition beanDefinition = new RootBeanDefinition(e, Autowire.BY_TYPE.value(), true);
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory();
@ -57,6 +62,5 @@ public class PluginEndpointPublisher {
} catch (Exception ex) { } catch (Exception ex) {
log.error("Failed to register " + e.getSimpleName() + " as endpoint with Spring, skipping..."); log.error("Failed to register " + e.getSimpleName() + " as endpoint with Spring, skipping...");
} }
});
} }
} }

View File

@ -43,7 +43,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* <p>LessonMenuService class.</p> * <p>LessonMenuService class.</p>
@ -56,7 +55,7 @@ import java.util.Optional;
public class LessonMenuService { public class LessonMenuService {
private final Course course; private final Course course;
private final UserTracker userTracker; private UserTracker userTracker;
private final WebSession webSession; private final WebSession webSession;
/** /**
@ -82,8 +81,8 @@ public class LessonMenuService {
lessonItem.setName(lesson.getTitle()); lessonItem.setName(lesson.getTitle());
lessonItem.setLink(lesson.getLink()); lessonItem.setLink(lesson.getLink());
lessonItem.setType(LessonMenuItemType.LESSON); lessonItem.setType(LessonMenuItemType.LESSON);
Optional<LessonTracker> lessonTracker = userTracker.getLessonTracker(lesson); LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
lessonItem.setComplete(lessonTracker.isPresent() ? lessonTracker.get().getCompleted() : false); lessonItem.setComplete(lessonTracker.isLessonSolved());
categoryItem.addChild(lessonItem); categoryItem.addChild(lessonItem);
} }
menu.add(categoryItem); menu.add(categoryItem);

View File

@ -6,6 +6,7 @@ import org.owasp.webgoat.i18n.LabelManager;
import org.owasp.webgoat.lessons.model.LessonInfoModel; import org.owasp.webgoat.lessons.model.LessonInfoModel;
import org.owasp.webgoat.session.LessonTracker; import org.owasp.webgoat.session.LessonTracker;
import org.owasp.webgoat.session.UserTracker; import org.owasp.webgoat.session.UserTracker;
import org.owasp.webgoat.session.WebSession;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
@ -24,6 +25,7 @@ public class LessonProgressService {
private LabelManager labelManager; private LabelManager labelManager;
private UserTracker userTracker; private UserTracker userTracker;
private WebSession webSession;
/** /**
* <p>LessonProgressService.</p> * <p>LessonProgressService.</p>
@ -33,10 +35,14 @@ public class LessonProgressService {
@RequestMapping(value = "/service/lessonprogress.mvc", produces = "application/json") @RequestMapping(value = "/service/lessonprogress.mvc", produces = "application/json")
@ResponseBody @ResponseBody
public Map getLessonInfo() { public Map getLessonInfo() {
LessonTracker lessonTracker = userTracker.getCurrentLessonTracker(); LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
boolean lessonCompleted = lessonTracker.getCompleted();
String successMessage = labelManager.get("LessonCompleted");
Map json = Maps.newHashMap(); Map json = Maps.newHashMap();
String successMessage = "";
boolean lessonCompleted = false;
if (lessonTracker != null) {
lessonCompleted = lessonTracker.isLessonSolved();
successMessage = labelManager.get("LessonCompleted");
}
json.put("lessonCompleted", lessonCompleted); json.put("lessonCompleted", lessonCompleted);
json.put("successMessage", successMessage); json.put("successMessage", successMessage);
return json; return json;

View File

@ -24,12 +24,14 @@
package org.owasp.webgoat.service; package org.owasp.webgoat.service;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.session.UserTracker; import org.owasp.webgoat.session.UserTracker;
import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.session.WebSession;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus;
/** /**
* <p>RestartLessonService class.</p> * <p>RestartLessonService class.</p>
@ -39,6 +41,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
*/ */
@Controller @Controller
@AllArgsConstructor @AllArgsConstructor
@Slf4j
public class RestartLessonService { public class RestartLessonService {
private final WebSession webSession; private final WebSession webSession;
@ -50,13 +53,11 @@ public class RestartLessonService {
* @return a {@link java.lang.String} object. * @return a {@link java.lang.String} object.
*/ */
@RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text") @RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text")
public @ResponseStatus(value = HttpStatus.OK)
@ResponseBody public void restartLesson() {
String restartLesson() {
AbstractLesson al = webSession.getCurrentLesson(); AbstractLesson al = webSession.getCurrentLesson();
System.out.println("Restarting lesson: " + al); log.debug("Restarting lesson: " + al);
userTracker.getCurrentLessonTracker().setCompleted(false);
return webSession.getCurrentLesson().getLink(); userTracker.reset(al);
} }
} }

View File

@ -96,7 +96,7 @@ public class Course {
for (Plugin plugin : plugins) { for (Plugin plugin : plugins) {
try { try {
NewLesson lesson = (NewLesson) plugin.getLesson().get(); NewLesson lesson = (NewLesson) plugin.getLesson().get();
lesson.setTotalNumberOfAssignments(plugin.getLessonEndpoints().size()); lesson.setAssignments(plugin.getAssignments());
lessons.add(lesson); lessons.add(lesson);
} catch (Exception e) { } catch (Exception e) {
log.error("Error in loadLessons: ", e); log.error("Error in loadLessons: ", e);

View File

@ -1,13 +1,13 @@
package org.owasp.webgoat.session; package org.owasp.webgoat.session;
import lombok.extern.slf4j.Slf4j; import com.google.common.collect.Sets;
import org.owasp.webgoat.lessons.AbstractLesson;
import java.io.FileInputStream; import java.io.Serializable;
import java.io.FileNotFoundException; import java.util.List;
import java.io.FileOutputStream; import java.util.Set;
import java.io.IOException; import java.util.stream.Collectors;
import java.util.Properties;
/** /**
@ -40,290 +40,43 @@ import java.util.Properties;
* @version $Id: $Id * @version $Id: $Id
* @since October 29, 2003 * @since October 29, 2003
*/ */
@Slf4j public class LessonTracker implements Serializable {
public class LessonTracker { private static final long serialVersionUID = 5410058267505412928L;
private final List<String> assignments;
private final Set<String> solvedAssignments = Sets.newHashSet();
private int numberOfAttempts = 0;
private boolean completed = false; public LessonTracker(AbstractLesson lesson) {
this.assignments = lesson.getAssignments().stream().map(a -> a.getSimpleName()).collect(Collectors.toList());
private int maxHintLevel = 0;
private int numVisits = 0;
private boolean viewedCookies = false;
private boolean viewedHtml = false;
private boolean viewedLessonPlan = false;
private boolean viewedParameters = false;
private boolean viewedSource = false;
private boolean viewedSolution = false;
Properties lessonProperties = new Properties();
private int totalNumberOfAssignments = 0;
public void setTotalNumberOfAssignments(int totalNumberOfAssignments) {
this.totalNumberOfAssignments = totalNumberOfAssignments;
} }
/** /**
* Gets the completed attribute of the LessonTracker object * Mark an assingment as solved
* *
* @return The completed value * @param solvedAssignment the assignment which the user solved
*/ */
public boolean getCompleted() { public void assignmentSolved(String solvedAssignment) {
return completed; solvedAssignments.add(solvedAssignment);
} }
/** /**
* Gets the maxHintLevel attribute of the LessonTracker object * @return did they user solved all assignments for the lesson?
*
* @return The maxHintLevel value
*/ */
public int getMaxHintLevel() { public boolean isLessonSolved() {
return maxHintLevel; return solvedAssignments.size() == assignments.size();
} }
/** /**
* Gets the numVisits attribute of the LessonTracker object * Increase the number attempts to solve the lesson
*
* @return The numVisits value
*/ */
public int getNumVisits() { public void incrementAttempts() {
return numVisits; numberOfAttempts++;
} }
/** /**
* Gets the viewedCookies attribute of the LessonTracker object * Reset the tracker. We do not reset the number of attempts here!
*
* @return The viewedCookies value
*/ */
public boolean getViewedCookies() { void reset() {
return viewedCookies; solvedAssignments.clear();
}
/**
* Gets the viewedHtml attribute of the LessonTracker object
*
* @return The viewedHtml value
*/
public boolean getViewedHtml() {
return viewedHtml;
}
/**
* Gets the viewedLessonPlan attribute of the LessonTracker object
*
* @return The viewedLessonPlan value
*/
public boolean getViewedLessonPlan() {
return viewedLessonPlan;
}
/**
* Gets the viewedParameters attribute of the LessonTracker object
*
* @return The viewedParameters value
*/
public boolean getViewedParameters() {
return viewedParameters;
}
/**
* Gets the viewedSource attribute of the LessonTracker object
*
* @return The viewedSource value
*/
public boolean getViewedSource() {
return viewedSource;
}
/**
* <p>Getter for the field <code>viewedSolution</code>.</p>
*
* @return a boolean.
*/
public boolean getViewedSolution() {
return viewedSource;
}
/**
* Description of the Method
*/
public void incrementNumVisits() {
numVisits++;
}
/**
* Sets the properties attribute of the LessonTracker object
*
* @param props The new properties value
* @param screen a {@link org.owasp.webgoat.session.Screen} object.
*/
protected void setProperties(Properties props, Screen screen) {
completed = Boolean.valueOf(props.getProperty(screen.getTitle() + ".completed")).booleanValue();
maxHintLevel = Integer.parseInt(props.getProperty(screen.getTitle() + ".maxHintLevel", "0"));
numVisits = Integer.parseInt(props.getProperty(screen.getTitle() + ".numVisits", "0"));
viewedCookies = Boolean.valueOf(props.getProperty(screen.getTitle() + ".viewedCookies", "false")).booleanValue();
viewedHtml = Boolean.valueOf(props.getProperty(screen.getTitle() + ".viewedHtml", "false")).booleanValue();
viewedLessonPlan = Boolean.valueOf(props.getProperty(screen.getTitle() + ".viewedLessonPlan", "false")).booleanValue();
viewedParameters = Boolean.valueOf(props.getProperty(screen.getTitle() + ".viewedParameters", "false")).booleanValue();
viewedSource = Boolean.valueOf(props.getProperty(screen.getTitle() + ".viewedSource", "false")).booleanValue();
totalNumberOfAssignments = Integer.parseInt(props.getProperty(screen.getTitle() + ".totalNumberOfAssignments", "0"));
}
/**
* <p>getUserDir.</p>
*
* @param s a {@link org.owasp.webgoat.session.WebSession} object.
* @return a {@link java.lang.String} object.
*/
public static String getUserDir(WebSession s) {
return "";
}
private static String getTrackerFile(WebSession s, String user, Screen screen) {
return getUserDir(s) + user + "." + screen.getClass().getName() + ".props";
}
/**
* Description of the Method
*
* @param screen Description of the Parameter
* @param screen Description of the Parameter
* @param screen Description of the Parameter
* @param screen Description of the Parameter
* @param screen Description of the Parameter
* @param screen Description of the Parameter
* @param s Description of the Parameter
* @param user a {@link java.lang.String} object.
* @return Description of the Return Value
*/
public static LessonTracker load(WebSession s, String user, Screen screen) {
FileInputStream in = null;
try {
String fileName = getTrackerFile(s, user, screen);
if (fileName != null) {
Properties tempProps = new Properties();
// System.out.println("Loading lesson state from: " + fileName);
in = new FileInputStream(fileName);
tempProps.load(in);
// allow the screen to use any custom properties it may have set
LessonTracker tempLessonTracker = new LessonTracker();
tempLessonTracker.setProperties(tempProps, screen);
return tempLessonTracker;
}
} catch (FileNotFoundException e) {
// Normal if the lesson has not been accessed yet.
} catch (Exception e) {
System.out.println("Failed to load lesson state for " + screen);
e.printStackTrace();
} finally {
try {
in.close();
} catch (Exception e) {
}
}
return new LessonTracker();
}
/**
* Sets the completed attribute of the LessonTracker object
*
* @param completed The new completed value
*/
public void setCompleted(boolean completed) {
this.completed = completed;
}
/**
* Sets the maxHintLevel attribute of the LessonTracker object
*
* @param maxHintLevel The new maxHintLevel value
*/
public void setMaxHintLevel(int maxHintLevel) {
this.maxHintLevel = Math.max(this.maxHintLevel, maxHintLevel);
}
/**
* Allows the storing of properties for the logged in and a screen.
*
* @param s Description of the Parameter
* @param screen a {@link org.owasp.webgoat.session.Screen} object.
* @param screen a {@link org.owasp.webgoat.session.Screen} object.
*/
public void store(WebSession s, Screen screen) {
store(s, screen, s.getUserName());
}
/**
* Allows the storing of properties for a user and a screen.
*
* @param s Description of the Parameter
* @param screen a {@link org.owasp.webgoat.session.Screen} object.
* @param screen a {@link org.owasp.webgoat.session.Screen} object.
* @param user a {@link java.lang.String} object.
*/
public void store(WebSession s, Screen screen, String user) {
String fileName = getTrackerFile(s, user, screen);
// System.out.println( "Storing data to" + fileName );
lessonProperties.setProperty(screen.getTitle() + ".completed", Boolean.toString(completed));
lessonProperties.setProperty(screen.getTitle() + ".maxHintLevel", Integer.toString(maxHintLevel));
lessonProperties.setProperty(screen.getTitle() + ".numVisits", Integer.toString(numVisits));
lessonProperties.setProperty(screen.getTitle() + ".viewedCookies", Boolean.toString(viewedCookies));
lessonProperties.setProperty(screen.getTitle() + ".viewedHtml", Boolean.toString(viewedHtml));
lessonProperties.setProperty(screen.getTitle() + ".viewedLessonPlan", Boolean.toString(viewedLessonPlan));
lessonProperties.setProperty(screen.getTitle() + ".viewedParameters", Boolean.toString(viewedParameters));
lessonProperties.setProperty(screen.getTitle() + ".viewedSource", Boolean.toString(viewedSource));
lessonProperties.setProperty(screen.getTitle() + ".totalNumberOfAssignments", Integer.toString(totalNumberOfAssignments));
try (FileOutputStream out = new FileOutputStream(fileName)) {
lessonProperties.store(out, s.getUserName());
} catch (IOException e) {
log.warn("Warning User data for {} will not persist", s.getUserName());
}
}
/**
* Description of the Method
*
* @return Description of the Return Value
*/
public String toString() {
StringBuffer buff = new StringBuffer();
buff.append("LessonTracker:" + "\n");
buff.append(" - completed:................. " + completed + "\n");
buff.append(" - maxHintLevel:.............. " + maxHintLevel + "\n");
buff.append(" - numVisits:................. " + numVisits + "\n");
buff.append(" - viewedCookies:............. " + viewedCookies + "\n");
buff.append(" - viewedHtml:................ " + viewedHtml + "\n");
buff.append(" - viewedLessonPlan:.......... " + viewedLessonPlan + "\n");
buff.append(" - viewedParameters:.......... " + viewedParameters + "\n");
buff.append(" - viewedSource:.............. " + viewedSource + "\n" + "\n");
buff.append(" - totalNumberOfAssignments:.. " + viewedSource + "\n" + "\n");
return buff.toString();
}
/**
* <p>Getter for the field <code>lessonProperties</code>.</p>
*
* @return Returns the lessonProperties.
*/
public Properties getLessonProperties() {
return lessonProperties;
}
/**
* <p>Setter for the field <code>lessonProperties</code>.</p>
*
* @param lessonProperties The lessonProperties to set.
*/
public void setLessonProperties(Properties lessonProperties) {
this.lessonProperties = lessonProperties;
} }
} }

View File

@ -1,13 +1,16 @@
package org.owasp.webgoat.session; package org.owasp.webgoat.session;
import lombok.SneakyThrows;
import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Assignment;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.util.FileCopyUtils;
import org.springframework.util.SerializationUtils;
import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional;
/** /**
@ -40,34 +43,15 @@ import java.util.Optional;
* @version $Id: $Id * @version $Id: $Id
* @since October 29, 2003 * @since October 29, 2003
*/ */
@Component
public class UserTracker { public class UserTracker {
private static Map<String, HashMap<String, LessonTracker>> storage = new HashMap<>();
private final String webgoatHome; private final String webgoatHome;
private final WebSession webSession; private final String user;
private Map<String, LessonTracker> storage = new HashMap<>();
public UserTracker(@Value("${webgoat.user.directory}") final String webgoatHome, final WebSession webSession) { public UserTracker(@Value("${webgoat.user.directory}") final String webgoatHome, final String user) {
this.webgoatHome = webgoatHome; this.webgoatHome = webgoatHome;
this.webSession = webSession; this.user = user;
}
/**
* <p>getCurrentLessonTracker.</p>
*
* @return a {@link org.owasp.webgoat.session.LessonTracker} object.
*/
public LessonTracker getCurrentLessonTracker() {
String lessonTitle = webSession.getCurrentLesson().getTitle();
String username = webSession.getUserName();
HashMap<String, LessonTracker> usermap = getUserMap(username);
LessonTracker tracker = usermap.get(lessonTitle);
if (tracker == null) {
// Creates a new lesson tracker, if one does not exist on disk.
tracker = LessonTracker.load(webSession, username, webSession.getCurrentLesson());
usermap.put(lessonTitle, tracker);
}
return tracker;
} }
/** /**
@ -76,31 +60,45 @@ public class UserTracker {
* @param lesson the lesson * @param lesson the lesson
* @return the optional lesson tracker * @return the optional lesson tracker
*/ */
public Optional<LessonTracker> getLessonTracker(AbstractLesson lesson) { public LessonTracker getLessonTracker(AbstractLesson lesson) {
String username = webSession.getUserName(); LessonTracker lessonTracker = storage.get(lesson.getTitle());
return Optional.ofNullable(getUserMap(username).getOrDefault(lesson.getTitle(), null)); if (lessonTracker == null) {
lessonTracker = new LessonTracker(lesson);
storage.put(lesson.getTitle(), lessonTracker);
}
return lessonTracker;
}
public void assignmentSolved(AbstractLesson lesson, Assignment assignment) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
lessonTracker.assignmentSolved(assignment.getClass().getSimpleName());
save();
}
public void assignmentFailed(AbstractLesson lesson) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
save();
}
@SneakyThrows
public void load() {
File file = new File(webgoatHome, user);
if (file.exists() && file.isFile()) {
this.storage = (Map<String, LessonTracker>) SerializationUtils.deserialize(FileCopyUtils.copyToByteArray(file));
}
}
@SneakyThrows
private void save() {
File file = new File(webgoatHome, user);
FileCopyUtils.copy(SerializationUtils.serialize(this.storage), file);
} }
/** public void reset(AbstractLesson al) {
* Gets the userMap attribute of the UserTracker object getLessonTracker(al).reset();
* save();
* @param userName Description of the Parameter
* @return The userMap value
*/
private HashMap<String, LessonTracker> getUserMap(String userName) {
HashMap<String, LessonTracker> usermap = storage.get(userName);
if (usermap == null) {
usermap = new HashMap<>();
storage.put(userName, usermap);
} }
return (usermap);
}
} }

View File

@ -2,7 +2,6 @@ package org.owasp.webgoat.session;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.AbstractLesson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
@ -44,13 +43,13 @@ public class WebSession {
private final User currentUser; private final User currentUser;
private final WebgoatContext webgoatContext; private final WebgoatContext webgoatContext;
private AbstractLesson currentLesson; private AbstractLesson currentLesson;
private UserTracker userTracker;
/** /**
* Constructor for the WebSession object * Constructor for the WebSession object
* *
* @param webgoatContext a {@link org.owasp.webgoat.session.WebgoatContext} object. * @param webgoatContext a {@link org.owasp.webgoat.session.WebgoatContext} object.
*/ */
@Autowired
public WebSession(WebgoatContext webgoatContext) { public WebSession(WebgoatContext webgoatContext) {
this.webgoatContext = webgoatContext; this.webgoatContext = webgoatContext;
this.currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); this.currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
@ -76,7 +75,6 @@ public class WebSession {
DatabaseUtilities.returnConnection(s.getUserName()); DatabaseUtilities.returnConnection(s.getUserName());
} }
/** /**
* <p> Setter for the field <code>currentScreen</code>. </p> * <p> Setter for the field <code>currentScreen</code>. </p>
* *

View File

@ -187,22 +187,11 @@ define(['jquery',
this.restartLesson = function() { this.restartLesson = function() {
var self=this; var self=this;
var fragment = "attack/" + self.scr + "/" + self.menu;
console.log("Navigating to " + fragment);
// Avoiding the trigger event - handle - navigate loop by
// loading the lesson explicitly (after executing the restart
// servlet).
goatRouter.navigate(fragment);
// Resetting the user's lesson state (assuming a single browser
// and session per user).
$.ajax({ $.ajax({
url:'service/restartlesson.mvc', url:'service/restartlesson.mvc',
method:'GET' method:'GET'
}).done(function(text) { }).done(function(lessonLink) {
console.log("Received a response from the restart servlet: '" + text + "'"); self.loadLesson(self.name);
// Explicitly loading the lesson instead of triggering an
// event in goatRouter.navigate().
self.loadLesson(self.scr,self.menu);
}); });
}; };

View File

@ -77,7 +77,7 @@ define(['jquery',
this.renderFeedback(data.feedback); this.renderFeedback(data.feedback);
this.renderOutput(data.output || ""); this.renderOutput(data.output || "");
if (data.lessonComplete) { if (data.lessonCompleted) {
this.trigger('lesson:complete'); this.trigger('lesson:complete');
} }
return false; return false;

View File

@ -0,0 +1,71 @@
package org.owasp.webgoat.session;
import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Assignment;
import java.io.File;
import java.io.IOException;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
/**
* ************************************************************************************************
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
* <p>
* Copyright (c) 2002 - 20014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>
*
* @author nbaars
* @version $Id: $Id
* @since November 15, 2016
*/
public class UserTrackerTest {
private File home;
@Before
public void init() throws IOException {
home = File.createTempFile("test", "test");
home.deleteOnExit();
}
@Test
public void writeAndRead() {
UserTracker userTracker = new UserTracker(home.getParent(), "test");
AbstractLesson abstractLesson = Mockito.mock(AbstractLesson.class);
Assignment assignment = Mockito.mock(Assignment.class);
when(abstractLesson.getAssignments()).thenReturn((List)Lists.newArrayList(assignment.getClass()));
userTracker.getLessonTracker(abstractLesson);
userTracker.assignmentSolved(abstractLesson, assignment);
userTracker = new UserTracker(home.getParent(), "test");
userTracker.load();
assertThat(userTracker.getLessonTracker(abstractLesson).isLessonSolved()).isTrue();
}
}

View File

@ -1,7 +1,6 @@
package org.owasp.webgoat.plugin; package org.owasp.webgoat.plugin;
import org.owasp.webgoat.lessons.AssignmentEndpoint; import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.LessonEndpointMapping;
import org.owasp.webgoat.lessons.model.AttackResult; import org.owasp.webgoat.lessons.model.AttackResult;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
@ -39,8 +38,7 @@ import java.io.IOException;
* @version $Id: $Id * @version $Id: $Id
* @since August 11, 2016 * @since August 11, 2016
*/ */
@LessonEndpointMapping public class Attack extends Assignment {
public class Attack extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST) @RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String answer) throws IOException { public @ResponseBody AttackResult completed(@RequestParam String answer) throws IOException {

View File

@ -7,8 +7,7 @@ package org.owasp.webgoat.plugin;
import org.apache.ecs.html.TD; import org.apache.ecs.html.TD;
import org.apache.ecs.html.TR; import org.apache.ecs.html.TR;
import org.apache.ecs.html.Table; import org.apache.ecs.html.Table;
import org.owasp.webgoat.lessons.AssignmentEndpoint; import org.owasp.webgoat.lessons.Endpoint;
import org.owasp.webgoat.lessons.LessonEndpointMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.w3c.dom.Node; import org.w3c.dom.Node;
@ -26,8 +25,7 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
@LessonEndpointMapping public class Salaries extends Endpoint {
public class Salaries extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
public void invoke(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { public void invoke(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

View File

@ -1,7 +1,6 @@
package org.owasp.webgoat.plugin; package org.owasp.webgoat.plugin;
import org.owasp.webgoat.lessons.AssignmentEndpoint; import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.LessonEndpointMapping;
import org.owasp.webgoat.lessons.model.AttackResult; import org.owasp.webgoat.lessons.model.AttackResult;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
@ -45,8 +44,7 @@ import java.io.IOException;
* @created October 28, 2003 * @created October 28, 2003
*/ */
@LessonEndpointMapping public class HttpBasicsLesson extends Assignment {
public class HttpBasicsLesson extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST) @RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String person, HttpServletRequest request) throws IOException { public @ResponseBody AttackResult completed(@RequestParam String person, HttpServletRequest request) throws IOException {

View File

@ -1,17 +1,15 @@
package org.owasp.webgoat.plugin; package org.owasp.webgoat.plugin;
import java.io.IOException; import org.owasp.webgoat.lessons.Assignment;
import javax.servlet.http.HttpServletRequest;
import org.owasp.webgoat.lessons.AssignmentEndpoint;
import org.owasp.webgoat.lessons.LessonEndpointMapping;
import org.owasp.webgoat.lessons.model.AttackResult; import org.owasp.webgoat.lessons.model.AttackResult;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/** /**
* ************************************************************************************************* * *************************************************************************************************
* *
@ -46,8 +44,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
* @created October 28, 2003 * @created October 28, 2003
*/ */
@LessonEndpointMapping public class HttpBasicsQuiz extends Assignment {
public class HttpBasicsQuiz extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST) @RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String answer, @RequestParam String magic_answer, @RequestParam String magic_num, HttpServletRequest request) throws IOException { public @ResponseBody AttackResult completed(@RequestParam String answer, @RequestParam String magic_answer, @RequestParam String magic_num, HttpServletRequest request) throws IOException {