XSS lesson completion fixes (#669)

* XSS lesson completion fixes

* removed log all

* lesson progress capable of deprecated assignments in the database

* fixed unit test for lesson progress
This commit is contained in:
René Zubcevic
2019-09-29 14:46:18 +02:00
committed by GitHub
parent 45c7949118
commit 0319c477b1
22 changed files with 218 additions and 58 deletions

View File

@ -45,6 +45,7 @@ public class Assignment {
private Long id;
private String name;
private String path;
@Transient
private List<String> hints;
@ -64,4 +65,14 @@ public class Assignment {
this.path = path;
this.hints = hints;
}
/**
* Set path is here to overwrite stored paths.
* Since a stored path can no longer be used in a lesson while
* the lesson (name) itself is still part of the lesson.
* @param pathName
*/
public void setPath(String pathName) {
this.path = pathName;
}
}

View File

@ -30,6 +30,7 @@ package org.owasp.webgoat.service;
import lombok.AllArgsConstructor;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.lessons.Assignment;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.lessons.LessonMenuItem;
import org.owasp.webgoat.lessons.LessonMenuItemType;
@ -45,6 +46,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@ -88,7 +90,8 @@ public class LessonMenuService {
lessonItem.setLink(lesson.getLink());
lessonItem.setType(LessonMenuItemType.LESSON);
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
lessonItem.setComplete(lessonTracker.isLessonSolved());
boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson);
lessonItem.setComplete(lessonSolved);
categoryItem.addChild(lessonItem);
}
categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking());
@ -97,4 +100,27 @@ public class LessonMenuService {
return menu;
}
/**
* This determines if the lesson is complete based on data in the database
* and the list of assignments actually linked to the existing current lesson.
* This way older removed assignments will not prevent a lesson from being completed.
* @param map
* @param currentLesson
* @return
*/
private boolean lessonCompleted(Map<Assignment, Boolean> map, Lesson currentLesson) {
boolean result = true;
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment: currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result = result && entry.getValue();
break;
}
}
}
return result;
}
}

View File

@ -47,7 +47,7 @@ public class LessonProgressService {
String successMessage = "";
boolean lessonCompleted = false;
if (lessonTracker != null) {
lessonCompleted = lessonTracker.isLessonSolved();
lessonCompleted = lessonCompleted(lessonTracker.getLessonOverview(),webSession.getCurrentLesson());
successMessage = "LessonCompleted"; //@todo we still use this??
}
json.put("lessonCompleted", lessonCompleted);
@ -70,19 +70,56 @@ public class LessonProgressService {
List<LessonOverview> result = Lists.newArrayList();
if ( currentLesson != null ) {
LessonTracker lessonTracker = userTracker.getLessonTracker(currentLesson);
result = toJson(lessonTracker.getLessonOverview());
result = toJson(lessonTracker.getLessonOverview(), currentLesson);
}
return result;
}
private List<LessonOverview> toJson(Map<Assignment, Boolean> map) {
private List<LessonOverview> toJson(Map<Assignment, Boolean> map, Lesson currentLesson) {
List<LessonOverview> result = new ArrayList();
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
result.add(new LessonOverview(entry.getKey(), entry.getValue()));
Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment: currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())
&& !lessonAssignment.getPath().equals(storedAssignment.getPath())) {
//here a stored path in the assignments table will be corrected for the JSON output
//with the value of the actual expected path
storedAssignment.setPath(lessonAssignment.getPath());
result.add(new LessonOverview(storedAssignment, entry.getValue()));
break;
} else if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result.add(new LessonOverview(storedAssignment, entry.getValue()));
break;
}
}
//assignments not in the list will not be put in the lesson progress JSON output
}
return result;
}
/**
* Get the lesson completed based on Assignment data from the database
* while ignoring assignments no longer in the application.
* @param map
* @param currentLesson
* @return
*/
private boolean lessonCompleted(Map<Assignment, Boolean> map, Lesson currentLesson) {
boolean result = true;
for (Map.Entry<Assignment, Boolean> entry : map.entrySet()) {
Assignment storedAssignment = entry.getKey();
for (Assignment lessonAssignment: currentLesson.getAssignments()) {
if (lessonAssignment.getName().equals(storedAssignment.getName())) {
result = result && entry.getValue();
break;
}
}
}
return result;
}
@AllArgsConstructor
@Getter

View File

@ -1,10 +1,10 @@
package org.owasp.webgoat.session;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.lessons.Lesson;
import org.owasp.webgoat.users.WebGoatUser;
import org.springframework.security.core.context.SecurityContextHolder;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
@ -37,10 +37,10 @@ import java.sql.SQLException;
* @version $Id: $Id
* @since October 28, 2003
*/
@Slf4j
public class WebSession {
public class WebSession implements Serializable {
private final WebGoatUser currentUser;
private static final long serialVersionUID = -4270066103101711560L;
private final WebGoatUser currentUser;
private final WebgoatContext webgoatContext;
private Lesson currentLesson;