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:
Nanne Baars
2017-01-24 15:34:06 +01:00
committed by misfir3
parent 6d727b98e3
commit 0779f7a3d0
56 changed files with 488 additions and 367 deletions

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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 {};
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -34,7 +34,6 @@ import java.util.List;
public abstract class NewLesson extends LessonAdapter {
@Override
public abstract Category getDefaultCategory();

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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