Hints per lesson (#314)
Squashing and merging ... * Each assigment should have the options to have its own set of hints #278 * Updating lessons due to changes from #278 * Enable i18n client side #312 * IDOR move hints to assignment and enable i18n #312
This commit is contained in:
@ -30,6 +30,7 @@
|
||||
*/
|
||||
package org.owasp.webgoat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.Context;
|
||||
@ -49,8 +50,10 @@ import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletCon
|
||||
import org.springframework.boot.web.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.context.annotation.ScopedProxyMode;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
@ -68,6 +71,15 @@ public class WebGoat extends SpringBootServletInitializer {
|
||||
SpringApplication.run(WebGoat.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public Jackson2ObjectMapperBuilder jacksonBuilder() {
|
||||
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
|
||||
builder.indentOutput(true);
|
||||
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Bean(name = "pluginTargetDirectory")
|
||||
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
|
||||
return new File(webgoatHome);
|
||||
|
@ -25,6 +25,9 @@
|
||||
*/
|
||||
package org.owasp.webgoat.endpoints;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.i18n.LabelManager;
|
||||
import org.owasp.webgoat.i18n.LabelProvider;
|
||||
import org.owasp.webgoat.lessons.AttackResult;
|
||||
import org.owasp.webgoat.session.UserSessionData;
|
||||
import org.owasp.webgoat.session.UserTracker;
|
||||
@ -50,6 +53,9 @@ public abstract class AssignmentEndpoint extends Endpoint {
|
||||
private WebSession webSession;
|
||||
@Autowired
|
||||
private UserSessionData userSessionData;
|
||||
@Autowired
|
||||
@Getter
|
||||
private LabelManager labelProvider;
|
||||
|
||||
|
||||
//// TODO: 11/13/2016 events better fit?
|
||||
@ -72,6 +78,6 @@ public abstract class AssignmentEndpoint extends Endpoint {
|
||||
|
||||
@Override
|
||||
public final String getPath() {
|
||||
return this.getClass().getAnnotationsByType(Path.class)[0].value();
|
||||
return this.getClass().getAnnotationsByType(AssignmentPath.class)[0].value();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,16 @@
|
||||
package org.owasp.webgoat.endpoints;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by nbaars on 1/14/17.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AssignmentHints {
|
||||
|
||||
String[] value() default {};
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.owasp.webgoat.endpoints;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created by nbaars on 1/14/17.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AssignmentPath {
|
||||
|
||||
String value();
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
|
||||
package org.owasp.webgoat.i18n;
|
||||
|
||||
import org.owasp.webgoat.session.LabelDebugger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
@ -33,22 +37,42 @@ import java.util.Locale;
|
||||
* @version $Id: $Id
|
||||
* @author dm
|
||||
*/
|
||||
public interface LabelManager
|
||||
@Component
|
||||
public class LabelManager
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LabelProvider labelProvider;
|
||||
private LabelDebugger labelDebugger;
|
||||
private Locale locale = new Locale(LabelProvider.DEFAULT_LANGUAGE);
|
||||
|
||||
/**
|
||||
* <p>setLocale.</p>
|
||||
* <p>Constructor for LabelManagerImpl.</p>
|
||||
*
|
||||
* @param locale a {@link java.util.Locale} object.
|
||||
* @param labelProvider a {@link LabelProvider} object.
|
||||
*/
|
||||
public void setLocale(Locale locale);
|
||||
protected LabelManager(LabelProvider labelProvider, LabelDebugger labelDebugger) {
|
||||
this.labelDebugger = labelDebugger;
|
||||
this.labelProvider = labelProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>get.</p>
|
||||
*
|
||||
* @param labelKey a {@link java.lang.String} object.
|
||||
* @return a {@link java.lang.String} object.
|
||||
*/
|
||||
public String get(String labelKey);
|
||||
/** {@inheritDoc} */
|
||||
public void setLocale(Locale locale)
|
||||
{
|
||||
if (locale != null)
|
||||
{
|
||||
this.locale = locale;
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String get(String labelKey, Object... params)
|
||||
{
|
||||
String label = labelProvider.get(locale, labelKey, params);
|
||||
if (labelDebugger.isEnabled()) {
|
||||
label = "<font color=\"#00CD00\">" + label + "</font>";
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
|
||||
package org.owasp.webgoat.i18n;
|
||||
|
||||
import org.owasp.webgoat.session.LabelDebugger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
/**
|
||||
*************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for
|
||||
* free software projects.
|
||||
*
|
||||
* @version $Id: $Id
|
||||
* @author dm
|
||||
*/
|
||||
@Component
|
||||
public class LabelManagerImpl implements LabelManager, Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LabelProvider labelProvider;
|
||||
private LabelDebugger labelDebugger;
|
||||
private Locale locale = new Locale(LabelProvider.DEFAULT_LANGUAGE);
|
||||
|
||||
/**
|
||||
* <p>Constructor for LabelManagerImpl.</p>
|
||||
*
|
||||
* @param labelProvider a {@link LabelProvider} object.
|
||||
*/
|
||||
protected LabelManagerImpl(LabelProvider labelProvider, LabelDebugger labelDebugger) {
|
||||
this.labelDebugger = labelDebugger;
|
||||
this.labelProvider = labelProvider;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void setLocale(Locale locale)
|
||||
{
|
||||
if (locale != null)
|
||||
{
|
||||
this.locale = locale;
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String get(String labelKey)
|
||||
{
|
||||
String label = labelProvider.get(locale, labelKey);
|
||||
if (labelDebugger.isEnabled()) {
|
||||
label = "<font color=\"#00CD00\">" + label + "</font>";
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
}
|
@ -97,8 +97,8 @@ public class LabelProvider {
|
||||
* @param strName a {@link java.lang.String} object.
|
||||
* @return a {@link java.lang.String} object.
|
||||
*/
|
||||
public String get(Locale locale, String strName) {
|
||||
return pluginLabels.getMessage(strName, null, useLocaleOrFallbackToEnglish(locale));
|
||||
public String get(Locale locale, String strName, Object... params) {
|
||||
return pluginLabels.getMessage(strName, params, useLocaleOrFallbackToEnglish(locale));
|
||||
}
|
||||
|
||||
private Locale useLocaleOrFallbackToEnglish(Locale locale) {
|
||||
|
@ -124,13 +124,6 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
|
||||
*/
|
||||
protected abstract boolean getDefaultHidden();
|
||||
|
||||
/**
|
||||
* <p>getSubmitMethod</p>
|
||||
*
|
||||
* @return a {@link java.lang.String} object.
|
||||
*/
|
||||
public abstract String getSubmitMethod();
|
||||
|
||||
/**
|
||||
* Gets the hintCount attribute of the Lesson object
|
||||
*
|
||||
@ -219,4 +212,5 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
|
||||
}
|
||||
|
||||
public abstract String getId();
|
||||
|
||||
}
|
||||
|
@ -2,8 +2,11 @@ package org.owasp.webgoat.lessons;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
@ -35,10 +38,14 @@ import java.io.Serializable;
|
||||
* @since November 25, 2016
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public class Assignment implements Serializable {
|
||||
|
||||
@NonNull
|
||||
private final String name;
|
||||
@NonNull
|
||||
private final String path;
|
||||
private List<String> hints;
|
||||
|
||||
}
|
||||
|
@ -26,70 +26,21 @@
|
||||
*/
|
||||
package org.owasp.webgoat.lessons;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>Hint class.</p>
|
||||
*
|
||||
* @author rlawson
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class Hint {
|
||||
|
||||
private String hint;
|
||||
private String lesson;
|
||||
private String assignmentPath;
|
||||
private int number;
|
||||
|
||||
/**
|
||||
* <p>Getter for the field <code>hint</code>.</p>
|
||||
*
|
||||
* @return the hint
|
||||
*/
|
||||
public String getHint() {
|
||||
return hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Setter for the field <code>hint</code>.</p>
|
||||
*
|
||||
* @param hint the hint to set
|
||||
*/
|
||||
public void setHint(String hint) {
|
||||
this.hint = hint;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Getter for the field <code>lesson</code>.</p>
|
||||
*
|
||||
* @return the lesson
|
||||
*/
|
||||
public String getLesson() {
|
||||
return lesson;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Setter for the field <code>lesson</code>.</p>
|
||||
*
|
||||
* @param lesson the lesson to set
|
||||
*/
|
||||
public void setLesson(String lesson) {
|
||||
this.lesson = lesson;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Getter for the field <code>number</code>.</p>
|
||||
*
|
||||
* @return the number
|
||||
*/
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Setter for the field <code>number</code>.</p>
|
||||
*
|
||||
* @param number the number to set
|
||||
*/
|
||||
public void setNumber(int number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.owasp.webgoat.lessons;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
|
||||
@ -9,30 +10,13 @@ import org.owasp.webgoat.session.WebSession;
|
||||
* @author dm
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
//// TODO: 11/5/2016 this can be removed???
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class LessonInfoModel {
|
||||
|
||||
private String lessonTitle;
|
||||
private int numberHints;
|
||||
private boolean hasSource;
|
||||
private boolean hasSolution;
|
||||
private boolean hasPlan;
|
||||
private String submitMethod;
|
||||
|
||||
/**
|
||||
* <p>Constructor for LessonInfoModel.</p>
|
||||
*
|
||||
* @param webSession a {@link org.owasp.webgoat.session.WebSession} object.
|
||||
*/
|
||||
public LessonInfoModel(WebSession webSession) {
|
||||
AbstractLesson lesson = webSession.getCurrentLesson();
|
||||
//TODO make these first class citizens of the lesson itself; and stop passing the session all over ... and generally tighten the checks up
|
||||
this.hasSource = false;
|
||||
this.hasPlan = false;
|
||||
this.hasSolution = false;
|
||||
this.lessonTitle = lesson.getTitle();
|
||||
this.numberHints = lesson.getHintCount();
|
||||
this.submitMethod = lesson.getSubmitMethod();
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ import java.util.List;
|
||||
public abstract class NewLesson extends LessonAdapter {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public abstract Category getDefaultCategory();
|
||||
|
||||
|
@ -4,6 +4,8 @@ import com.google.common.base.Optional;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.endpoints.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.endpoints.AssignmentHints;
|
||||
import org.owasp.webgoat.endpoints.AssignmentPath;
|
||||
import org.owasp.webgoat.endpoints.Endpoint;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
@ -114,12 +116,17 @@ public class Plugin {
|
||||
|
||||
|
||||
private List<Assignment> createAssignment(List<Class<AssignmentEndpoint>> endpoints) {
|
||||
return endpoints.stream().map(e -> new Assignment(e.getSimpleName(), getPath(e))).collect(toList());
|
||||
return endpoints.stream().map(e -> new Assignment(e.getSimpleName(), getPath(e), getHints(e))).collect(toList());
|
||||
}
|
||||
|
||||
private String getPath(Class<AssignmentEndpoint> e) {
|
||||
return e.getAnnotationsByType(javax.ws.rs.Path.class)[0].value();
|
||||
return e.getAnnotationsByType(AssignmentPath.class)[0].value();
|
||||
}
|
||||
|
||||
|
||||
private List<String> getHints(Class<AssignmentEndpoint> e) {
|
||||
if (e.isAnnotationPresent(AssignmentHints.class)) {
|
||||
return Lists.newArrayList(e.getAnnotationsByType(AssignmentHints.class)[0].value());
|
||||
}
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,16 @@
|
||||
*/
|
||||
package org.owasp.webgoat.service;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.owasp.webgoat.i18n.LabelManager;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
import org.owasp.webgoat.lessons.Hint;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
@ -23,9 +25,10 @@ import static java.util.stream.Collectors.toList;
|
||||
* @author rlawson
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@Controller
|
||||
@RestController
|
||||
public class HintService {
|
||||
|
||||
public static final String URL_HINTS_MVC = "/service/hint.mvc";
|
||||
private final WebSession webSession;
|
||||
|
||||
public HintService(WebSession webSession) {
|
||||
@ -37,30 +40,44 @@ public class HintService {
|
||||
*
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
@RequestMapping(path = "/service/hint.mvc", produces = "application/json")
|
||||
public
|
||||
@GetMapping(path = URL_HINTS_MVC, produces = "application/json")
|
||||
@ResponseBody
|
||||
List<Hint> showHint() {
|
||||
List<Hint> listHints = new ArrayList<Hint>();
|
||||
public List<Hint> showHint() {
|
||||
AbstractLesson l = webSession.getCurrentLesson();
|
||||
if (l == null) {
|
||||
return listHints;
|
||||
}
|
||||
List<String> hints = l.getHints();
|
||||
List<Hint> hints = createLessonHints(l);
|
||||
hints.addAll(createAssignmentHints(l));
|
||||
return hints;
|
||||
|
||||
if (hints == null) {
|
||||
return listHints;
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
return hints.stream().map(h -> createHint(h, l.getName(), idx)).collect(toList());
|
||||
}
|
||||
|
||||
private Hint createHint(String hintText, String lesson, int idx) {
|
||||
private List<Hint> createLessonHints(AbstractLesson l) {
|
||||
if ( l != null ) {
|
||||
return l.getHints().stream().map(h -> createHint(h, l.getName(), null)).collect(toList());
|
||||
}
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
private List<Hint> createAssignmentHints(AbstractLesson l) {
|
||||
List<Hint> hints = Lists.newArrayList();
|
||||
if ( l != null) {
|
||||
List<Assignment> assignments = l.getAssignments();
|
||||
assignments.stream().forEach(a -> { a.getHints(); createHints(a, hints);});
|
||||
}
|
||||
return hints;
|
||||
}
|
||||
|
||||
private void createHints(Assignment a, List<Hint> hints) {
|
||||
hints.addAll(a.getHints().stream().map(h -> createHint(h, null, a.getPath())).collect(toList()));
|
||||
}
|
||||
|
||||
private Hint createHint(String hintText, String lesson, String assignmentName) {
|
||||
Hint hint = new Hint();
|
||||
hint.setHint(hintText);
|
||||
hint.setLesson(lesson);
|
||||
hint.setNumber(idx);
|
||||
if (lesson != null) {
|
||||
hint.setLesson(lesson);
|
||||
} else {
|
||||
hint.setAssignmentPath(assignmentName);
|
||||
}
|
||||
return hint;
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,30 @@
|
||||
package org.owasp.webgoat.service;
|
||||
|
||||
import org.owasp.webgoat.i18n.LabelManager;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.LessonInfoModel;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
@Controller
|
||||
/**
|
||||
* <p>LessonInfoService class.</p>
|
||||
*
|
||||
* @author dm
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@RestController
|
||||
public class LessonInfoService {
|
||||
|
||||
private final WebSession webSession;
|
||||
private final LabelManager labelManager;
|
||||
|
||||
public LessonInfoService(WebSession webSession) {
|
||||
public LessonInfoService(WebSession webSession, LabelManager labelManager) {
|
||||
this.webSession = webSession;
|
||||
this.labelManager = labelManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,7 +35,8 @@ public class LessonInfoService {
|
||||
@RequestMapping(path = "/service/lessoninfo.mvc", produces = "application/json")
|
||||
public @ResponseBody
|
||||
LessonInfoModel getLessonInfo() {
|
||||
return new LessonInfoModel(webSession);
|
||||
AbstractLesson lesson = webSession.getCurrentLesson();
|
||||
return new LessonInfoModel(labelManager.get(lesson.getTitle()), false, false, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ public class LessonMenuService {
|
||||
|
||||
private final Course course;
|
||||
private UserTracker userTracker;
|
||||
private final WebSession webSession;
|
||||
|
||||
/**
|
||||
* Returns the lesson menu which is used to build the left nav
|
||||
|
Reference in New Issue
Block a user