Merge branch 'challenge' into develop
Conflicts: webgoat-container/src/main/resources/static/css/main.css
This commit is contained in:
@ -0,0 +1,36 @@
|
||||
package org.owasp.webgoat;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/15/17.
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@ConditionalOnExpression("'${webgoat.clean}' == 'true'")
|
||||
public class CleanupLocalProgressFiles {
|
||||
|
||||
@Value("${webgoat.server.directory}")
|
||||
private String webgoatHome;
|
||||
|
||||
@PostConstruct
|
||||
public void clean() {
|
||||
File dir = new File(webgoatHome);
|
||||
if (dir.exists()) {
|
||||
File[] progressFiles = dir.listFiles(f -> f.getName().endsWith(".progress"));
|
||||
if (progressFiles != null) {
|
||||
log.info("Removing stored user preferences...");
|
||||
for (File f : progressFiles) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -71,6 +71,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
registry.addViewController("/lesson_content").setViewName("lesson_content");
|
||||
registry.addViewController("/start.mvc").setViewName("main_new");
|
||||
registry.addViewController("/scoreboard").setViewName("scoreboard");
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,12 +31,14 @@
|
||||
package org.owasp.webgoat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.Context;
|
||||
import org.owasp.webgoat.plugins.PluginEndpointPublisher;
|
||||
import org.owasp.webgoat.plugins.PluginsLoader;
|
||||
import org.owasp.webgoat.session.*;
|
||||
import org.owasp.webgoat.session.Course;
|
||||
import org.owasp.webgoat.session.UserSessionData;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.owasp.webgoat.session.WebgoatContext;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@ -104,15 +106,6 @@ public class WebGoat extends SpringBootServletInitializer {
|
||||
return new PluginsLoader(pluginEndpointPublisher).loadPlugins();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EmbeddedServletContainerFactory servletContainer() {
|
||||
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
|
||||
@ -127,4 +120,5 @@ public class WebGoat extends SpringBootServletInitializer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ package org.owasp.webgoat.assignments;
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.session.UserSessionData;
|
||||
import org.owasp.webgoat.session.UserTracker;
|
||||
import org.owasp.webgoat.users.UserTracker;
|
||||
import org.owasp.webgoat.users.UserTrackerRepository;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@ -43,7 +44,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
public abstract class AssignmentEndpoint extends Endpoint {
|
||||
|
||||
@Autowired
|
||||
private UserTracker userTracker;
|
||||
private UserTrackerRepository userTrackerRepository;
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
@Autowired
|
||||
@ -54,11 +55,16 @@ public abstract class AssignmentEndpoint extends Endpoint {
|
||||
|
||||
//// TODO: 11/13/2016 events better fit?
|
||||
protected AttackResult trackProgress(AttackResult attackResult) {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
if (userTracker == null) {
|
||||
userTracker = new UserTracker(webSession.getUserName());
|
||||
}
|
||||
if (attackResult.assignmentSolved()) {
|
||||
userTracker.assignmentSolved(webSession.getCurrentLesson(), this.getClass().getSimpleName());
|
||||
} else {
|
||||
userTracker.assignmentFailed(webSession.getCurrentLesson());
|
||||
}
|
||||
userTrackerRepository.save(userTracker);
|
||||
return attackResult;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,12 @@ public class AttackResult {
|
||||
return this;
|
||||
}
|
||||
|
||||
public AttackResultBuilder lessonCompleted(boolean lessonCompleted, String resourceBundleKey) {
|
||||
this.lessonCompleted = lessonCompleted;
|
||||
this.feedbackResourceBundleKey = resourceBundleKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AttackResultBuilder feedbackArgs(Object... args) {
|
||||
this.feedbackArgs = args;
|
||||
return this;
|
||||
|
@ -1,11 +1,7 @@
|
||||
package org.owasp.webgoat.lessons;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -39,14 +35,14 @@ import java.util.List;
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@RequiredArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
public class Assignment implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 5410058267505412928L;
|
||||
@EqualsAndHashCode
|
||||
public class Assignment {
|
||||
@NonNull
|
||||
private final String name;
|
||||
private String name;
|
||||
@NonNull
|
||||
private final String path;
|
||||
private String path;
|
||||
private List<String> hints;
|
||||
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public enum Category {
|
||||
WEB_SERVICES("Web Services", new Integer(1900)),
|
||||
VULNERABLE_COMPONENTS("Vulnerable Components - A9", new Integer(1950)),
|
||||
ADMIN_FUNCTIONS("Admin Functions", new Integer(2000)),
|
||||
CHALLENGE("Challenge", new Integer(3000));
|
||||
CHALLENGE("Challenges", new Integer(3000));
|
||||
|
||||
@Getter
|
||||
private String name;
|
||||
|
@ -8,7 +8,6 @@ import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -24,21 +23,22 @@ public class PluginResource {
|
||||
private final URL location;
|
||||
private final List<Class> classes;
|
||||
|
||||
public Optional<Class> getLesson() {
|
||||
return classes.stream().filter(c -> c.getSuperclass() == NewLesson.class).findFirst();
|
||||
public List<Class> getLessons() {
|
||||
return classes.stream().filter(c -> c.getSuperclass() == NewLesson.class).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Class<Endpoint>> getEndpoints() {
|
||||
return classes.stream().
|
||||
filter(c -> c.getSuperclass() == AssignmentEndpoint.class || c.getSuperclass() == Endpoint.class).
|
||||
map(c -> (Class<Endpoint>)c).
|
||||
map(c -> (Class<Endpoint>) c).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Class<AssignmentEndpoint>> getAssignments() {
|
||||
public List<Class<AssignmentEndpoint>> getAssignments(Class lesson) {
|
||||
return classes.stream().
|
||||
filter(c -> c.getSuperclass() == AssignmentEndpoint.class).
|
||||
map(c -> (Class<AssignmentEndpoint>)c).
|
||||
filter(c -> c.getPackage().equals(lesson.getPackage())).
|
||||
map(c -> (Class<AssignmentEndpoint>) c).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
@ -67,13 +67,18 @@ public class PluginsLoader {
|
||||
List<AbstractLesson> lessons = Lists.newArrayList();
|
||||
for (PluginResource plugin : findPluginResources()) {
|
||||
try {
|
||||
Class lessonClazz = plugin.getLesson()
|
||||
.orElseThrow(() -> new PluginLoadingFailure("Plugin resource does not contain lesson"));
|
||||
NewLesson lesson = (NewLesson) lessonClazz.newInstance();
|
||||
List<Class<AssignmentEndpoint>> assignments = plugin.getAssignments();
|
||||
lesson.setAssignments(createAssignment(assignments));
|
||||
lessons.add(lesson);
|
||||
pluginEndpointPublisher.publish(plugin.getEndpoints());
|
||||
plugin.getLessons().forEach(c -> {
|
||||
NewLesson lesson = null;
|
||||
try {
|
||||
lesson = (NewLesson) c.newInstance();
|
||||
} catch (Exception e) {
|
||||
log.error("Error while loading:" + c, e);
|
||||
}
|
||||
List<Class<AssignmentEndpoint>> assignments = plugin.getAssignments(c);
|
||||
lesson.setAssignments(createAssignment(assignments));
|
||||
lessons.add(lesson);
|
||||
pluginEndpointPublisher.publish(plugin.getEndpoints());
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("Error in loadLessons: ", e);
|
||||
}
|
||||
|
@ -34,15 +34,18 @@ import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.LessonMenuItem;
|
||||
import org.owasp.webgoat.lessons.LessonMenuItemType;
|
||||
import org.owasp.webgoat.session.Course;
|
||||
import org.owasp.webgoat.session.LessonTracker;
|
||||
import org.owasp.webgoat.session.UserTracker;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.owasp.webgoat.users.LessonTracker;
|
||||
import org.owasp.webgoat.users.UserTracker;
|
||||
import org.owasp.webgoat.users.UserTrackerRepository;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>LessonMenuService class.</p>
|
||||
@ -54,20 +57,23 @@ import java.util.List;
|
||||
@AllArgsConstructor
|
||||
public class LessonMenuService {
|
||||
|
||||
public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc";
|
||||
private final Course course;
|
||||
private UserTracker userTracker;
|
||||
private final WebSession webSession;
|
||||
private UserTrackerRepository userTrackerRepository;
|
||||
|
||||
/**
|
||||
* Returns the lesson menu which is used to build the left nav
|
||||
*
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
@RequestMapping(path = "/service/lessonmenu.mvc", produces = "application/json")
|
||||
@RequestMapping(path = URL_LESSONMENU_MVC, produces = "application/json")
|
||||
public
|
||||
@ResponseBody
|
||||
List<LessonMenuItem> showLeftNav() {
|
||||
List<LessonMenuItem> menu = new ArrayList<LessonMenuItem>();
|
||||
List<LessonMenuItem> menu = new ArrayList<>();
|
||||
List<Category> categories = course.getCategories();
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
|
||||
for (Category category : categories) {
|
||||
LessonMenuItem categoryItem = new LessonMenuItem();
|
||||
@ -75,6 +81,7 @@ public class LessonMenuService {
|
||||
categoryItem.setType(LessonMenuItemType.CATEGORY);
|
||||
// check for any lessons for this category
|
||||
List<AbstractLesson> lessons = course.getLessons(category);
|
||||
lessons = lessons.stream().sorted(Comparator.comparing(l -> l.getTitle())).collect(Collectors.toList());
|
||||
for (AbstractLesson lesson : lessons) {
|
||||
LessonMenuItem lessonItem = new LessonMenuItem();
|
||||
lessonItem.setName(lesson.getTitle());
|
||||
|
@ -7,9 +7,10 @@ import lombok.Getter;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
import org.owasp.webgoat.lessons.LessonInfoModel;
|
||||
import org.owasp.webgoat.session.LessonTracker;
|
||||
import org.owasp.webgoat.session.UserTracker;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.owasp.webgoat.users.LessonTracker;
|
||||
import org.owasp.webgoat.users.UserTracker;
|
||||
import org.owasp.webgoat.users.UserTrackerRepository;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -28,7 +29,7 @@ import java.util.Map;
|
||||
@AllArgsConstructor
|
||||
public class LessonProgressService {
|
||||
|
||||
private UserTracker userTracker;
|
||||
private UserTrackerRepository userTrackerRepository;
|
||||
private WebSession webSession;
|
||||
|
||||
/**
|
||||
@ -39,6 +40,7 @@ public class LessonProgressService {
|
||||
@RequestMapping(value = "/service/lessonprogress.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public Map getLessonInfo() {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
LessonTracker lessonTracker = userTracker.getLessonTracker(webSession.getCurrentLesson());
|
||||
Map json = Maps.newHashMap();
|
||||
String successMessage = "";
|
||||
@ -61,6 +63,7 @@ public class LessonProgressService {
|
||||
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public List<LessonOverview> lessonOverview() {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
AbstractLesson currentLesson = webSession.getCurrentLesson();
|
||||
List<LessonOverview> result = Lists.newArrayList();
|
||||
if ( currentLesson != null ) {
|
||||
|
@ -29,25 +29,20 @@
|
||||
package org.owasp.webgoat.service;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.Singular;
|
||||
import org.apache.catalina.User;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.session.Course;
|
||||
import org.owasp.webgoat.session.LessonTracker;
|
||||
import org.owasp.webgoat.session.UserTracker;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.owasp.webgoat.users.LessonTracker;
|
||||
import org.owasp.webgoat.users.UserTracker;
|
||||
import org.owasp.webgoat.users.UserTrackerRepository;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* <p>ReportCardService</p>
|
||||
@ -56,22 +51,20 @@ import java.util.Map;
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@Controller
|
||||
@AllArgsConstructor
|
||||
public class ReportCardService {
|
||||
|
||||
private final UserTracker userTracker;
|
||||
private final WebSession webSession;
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
private final Course course;
|
||||
|
||||
public ReportCardService(UserTracker userTracker, Course course) {
|
||||
this.userTracker = userTracker;
|
||||
this.course = course;
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint which generates the report card for the current use to show the stats on the solved lessons
|
||||
*/
|
||||
@GetMapping(path = "/service/reportcard.mvc", produces = "application/json")
|
||||
@ResponseBody
|
||||
public ReportCard reportCard() {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
List<AbstractLesson> lessons = course.getLessons();
|
||||
ReportCard reportCard = new ReportCard();
|
||||
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
|
||||
|
@ -26,8 +26,9 @@ package org.owasp.webgoat.service;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.session.UserTracker;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.owasp.webgoat.users.UserTracker;
|
||||
import org.owasp.webgoat.users.UserTrackerRepository;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -45,7 +46,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
public class RestartLessonService {
|
||||
|
||||
private final WebSession webSession;
|
||||
private final UserTracker userTracker;
|
||||
private UserTrackerRepository userTrackerRepository;
|
||||
|
||||
/**
|
||||
* Returns current lesson
|
||||
@ -58,6 +59,8 @@ public class RestartLessonService {
|
||||
AbstractLesson al = webSession.getCurrentLesson();
|
||||
log.debug("Restarting lesson: " + al);
|
||||
|
||||
UserTracker userTracker = userTrackerRepository.findOne(webSession.getUserName());
|
||||
userTracker.reset(al);
|
||||
userTrackerRepository.save(userTracker);
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,6 @@ import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
|
||||
/**
|
||||
*************************************************************************************************
|
||||
@ -39,6 +37,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
* @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
//TODO: class we need to refactor to new structure, we can put the connection in the current session of the user
|
||||
// start using jdbc template
|
||||
public class DatabaseUtilities
|
||||
{
|
||||
|
||||
@ -122,7 +122,7 @@ public class DatabaseUtilities
|
||||
private static Connection getHsqldbConnection(String user, WebgoatContext context) throws ClassNotFoundException,
|
||||
SQLException
|
||||
{
|
||||
String url = context.getDatabaseConnectionString().replaceAll("\\$\\{USER\\}", user);
|
||||
String url = context.getDatabaseConnectionString().replace("{USER}", user);
|
||||
return DriverManager.getConnection(url, "sa", "");
|
||||
}
|
||||
|
||||
|
@ -1,181 +0,0 @@
|
||||
package org.owasp.webgoat.session;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
class UserDatabase {
|
||||
private Connection userDB;
|
||||
private final String USER_DB_URI = "jdbc:h2:" + System.getProperty("user.dir") + File.separator + "UserDatabase";
|
||||
|
||||
private final String CREATE_USERS_TABLE = "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTO_INCREMENT, username VARCHAR(255) NOT NULL UNIQUE);";
|
||||
private final String CREATE_ROLES_TABLE = "CREATE TABLE IF NOT EXISTS roles (id INTEGER PRIMARY KEY AUTO_INCREMENT, rolename VARCHAR(255) NOT NULL UNIQUE);";
|
||||
private final String CREATE_USER_ROLES_TABLE = "CREATE TABLE IF NOT EXISTS user_roles (id INTEGER PRIMARY KEY AUTO_INCREMENT, user_id INTEGER NOT NULL, role_id INTEGER NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id), FOREIGN KEY (role_id) REFERENCES roles(id));";
|
||||
private final String ADD_DEFAULT_USERS = "INSERT INTO users (username) VALUES ('webgoat'),('basic'),('guest');";
|
||||
private final String ADD_DEFAULT_ROLES = "INSERT INTO roles (rolename) VALUES ('webgoat_basic'),('webgoat_admin'),('webgoat_user');";
|
||||
private final String ADD_ROLE_TO_USER = "INSERT INTO user_roles (user_id, role_id) SELECT users.id, roles.id FROM users, roles WHERE users.username = ? AND roles.rolename = ?;";
|
||||
|
||||
private final String QUERY_ALL_USERS = "SELECT username FROM users;";
|
||||
private final String QUERY_ALL_ROLES_FOR_USERNAME = "SELECT rolename FROM roles, user_roles, users WHERE roles.id = user_roles.role_id AND user_roles.user_id = users.id AND users.username = ?;";
|
||||
private final String QUERY_TABLE_COUNT = "SELECT count(id) AS count FROM table;";
|
||||
|
||||
/**
|
||||
* <p>Constructor for UserDatabase.</p>
|
||||
*/
|
||||
public UserDatabase() {
|
||||
createDefaultTables();
|
||||
if (getTableCount("users") <= 0) {
|
||||
createDefaultUsers();
|
||||
}
|
||||
if (getTableCount("roles") <= 0) {
|
||||
createDefaultRoles();
|
||||
}
|
||||
if (getTableCount("user_roles") <= 0) {
|
||||
addDefaultRolesToDefaultUsers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>open.</p>
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
public boolean open() {
|
||||
try {
|
||||
if (userDB == null || userDB.isClosed()) {
|
||||
Class.forName("org.h2.Driver");
|
||||
userDB = DriverManager.getConnection(USER_DB_URI, "webgoat_admin", "");
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>close.</p>
|
||||
*
|
||||
* @return a boolean.
|
||||
*/
|
||||
public boolean close() {
|
||||
try {
|
||||
if (userDB != null && !userDB.isClosed())
|
||||
userDB.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>getTableCount.</p>
|
||||
*
|
||||
* @param tableName a {@link java.lang.String} object.
|
||||
* @return a int.
|
||||
*/
|
||||
public int getTableCount(String tableName) {
|
||||
int count = 0;
|
||||
try {
|
||||
open();
|
||||
Statement statement = userDB.createStatement();
|
||||
ResultSet countResult = statement.executeQuery(QUERY_TABLE_COUNT.replace("table", tableName));
|
||||
if (countResult.next()) {
|
||||
count = countResult.getInt("count");
|
||||
}
|
||||
countResult.close();
|
||||
statement.close();
|
||||
close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
count = -1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>addRoleToUser.</p>
|
||||
*
|
||||
* @param username a {@link java.lang.String} object.
|
||||
* @param rolename a {@link java.lang.String} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public boolean addRoleToUser(String username, String rolename) {
|
||||
try {
|
||||
open();
|
||||
PreparedStatement statement = userDB.prepareStatement(ADD_ROLE_TO_USER);
|
||||
statement.setString(1, username);
|
||||
statement.setString(2, rolename);
|
||||
statement.execute();
|
||||
statement.close();
|
||||
close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Methods to initialise the default state of the database.
|
||||
*/
|
||||
|
||||
private boolean createDefaultTables() {
|
||||
try {
|
||||
open();
|
||||
Statement statement = userDB.createStatement();
|
||||
statement.execute(CREATE_USERS_TABLE);
|
||||
statement.execute(CREATE_ROLES_TABLE);
|
||||
statement.execute(CREATE_USER_ROLES_TABLE);
|
||||
statement.close();
|
||||
close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean createDefaultUsers() {
|
||||
try {
|
||||
open();
|
||||
Statement statement = userDB.createStatement();
|
||||
statement.execute(ADD_DEFAULT_USERS);
|
||||
statement.close();
|
||||
close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean createDefaultRoles() {
|
||||
try {
|
||||
open();
|
||||
Statement statement = userDB.createStatement();
|
||||
statement.execute(ADD_DEFAULT_ROLES);
|
||||
statement.close();
|
||||
close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addDefaultRolesToDefaultUsers() {
|
||||
addRoleToUser("webgoat", "webgoat_admin");
|
||||
addRoleToUser("basic", "webgoat_user");
|
||||
addRoleToUser("basic", "webgoat_basic");
|
||||
addRoleToUser("guest", "webgoat_user");
|
||||
}
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
|
||||
package org.owasp.webgoat.session;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
import org.springframework.core.serializer.DefaultDeserializer;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* <p>
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @version $Id: $Id
|
||||
* @since October 29, 2003
|
||||
*/
|
||||
@Slf4j
|
||||
public class UserTracker {
|
||||
|
||||
private final String webgoatHome;
|
||||
private final String user;
|
||||
|
||||
public UserTracker(final String webgoatHome, final String user) {
|
||||
this.webgoatHome = webgoatHome;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lesson tracker for a specific lesson if available.
|
||||
*
|
||||
* @param lesson the lesson
|
||||
* @return the optional lesson tracker
|
||||
*/
|
||||
public LessonTracker getLessonTracker(AbstractLesson lesson) {
|
||||
return getLessonTracker(load(), lesson);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lesson tracker for a specific lesson if available.
|
||||
*
|
||||
* @param lesson the lesson
|
||||
* @return the optional lesson tracker
|
||||
*/
|
||||
public LessonTracker getLessonTracker(Map<String, LessonTracker> storage, AbstractLesson lesson) {
|
||||
LessonTracker lessonTracker = storage.get(lesson.getTitle());
|
||||
if (lessonTracker == null) {
|
||||
lessonTracker = new LessonTracker(lesson);
|
||||
storage.put(lesson.getTitle(), lessonTracker);
|
||||
save(storage);
|
||||
}
|
||||
return lessonTracker;
|
||||
}
|
||||
|
||||
public void assignmentSolved(AbstractLesson lesson, String assignmentName) {
|
||||
Map<String, LessonTracker> storage = load();
|
||||
LessonTracker lessonTracker = storage.get(lesson.getTitle());
|
||||
lessonTracker.incrementAttempts();
|
||||
lessonTracker.assignmentSolved(assignmentName);
|
||||
save(storage);
|
||||
}
|
||||
|
||||
public void assignmentFailed(AbstractLesson lesson) {
|
||||
Map<String, LessonTracker> storage = load();
|
||||
LessonTracker lessonTracker = storage.get(lesson.getTitle());
|
||||
lessonTracker.incrementAttempts();
|
||||
save(storage);
|
||||
}
|
||||
|
||||
public Map<String, LessonTracker> load() {
|
||||
File file = new File(webgoatHome, user + ".progress");
|
||||
Map<String, LessonTracker> storage = Maps.newHashMap();
|
||||
if (file.exists() && file.isFile()) {
|
||||
try {
|
||||
DefaultDeserializer deserializer = new DefaultDeserializer(Thread.currentThread().getContextClassLoader());
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
byte[] b = ByteStreams.toByteArray(fis);
|
||||
storage = (Map<String, LessonTracker>) deserializer.deserialize(new ByteArrayInputStream(b));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to read the progress file, creating a new one...");
|
||||
}
|
||||
}
|
||||
return storage;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void save(Map<String, LessonTracker> storage) {
|
||||
File file = new File(webgoatHome, user + ".progress");
|
||||
|
||||
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file))) {
|
||||
objectOutputStream.writeObject(storage);
|
||||
objectOutputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void reset(AbstractLesson al) {
|
||||
Map<String, LessonTracker> storage = load();
|
||||
LessonTracker lessonTracker = getLessonTracker(storage, al);
|
||||
lessonTracker.reset();
|
||||
save(storage);
|
||||
}
|
||||
|
||||
public int numberOfLessonsSolved() {
|
||||
int numberOfLessonsSolved = 0;
|
||||
Map<String, LessonTracker> storage = load();
|
||||
for (LessonTracker lessonTracker : storage.values()) {
|
||||
if (lessonTracker.isLessonSolved()) {
|
||||
numberOfLessonsSolved = numberOfLessonsSolved + 1;
|
||||
}
|
||||
}
|
||||
return numberOfLessonsSolved;
|
||||
}
|
||||
|
||||
public int numberOfAssignmentsSolved() {
|
||||
int numberOfAssignmentsSolved = 0;
|
||||
Map<String, LessonTracker> storage = load();
|
||||
for (LessonTracker lessonTracker : storage.values()) {
|
||||
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
|
||||
numberOfAssignmentsSolved = lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue();
|
||||
}
|
||||
return numberOfAssignmentsSolved;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package org.owasp.webgoat.session;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.users.WebGoatUser;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
package org.owasp.webgoat.session;
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
@ -7,7 +7,6 @@ import lombok.Getter;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -45,14 +44,20 @@ import java.util.stream.Collectors;
|
||||
* @version $Id: $Id
|
||||
* @since October 29, 2003
|
||||
*/
|
||||
public class LessonTracker implements Serializable {
|
||||
private static final long serialVersionUID = 5410058267505412928L;
|
||||
public class LessonTracker {
|
||||
@Getter
|
||||
private String lessonName;
|
||||
private final Set<Assignment> solvedAssignments = Sets.newHashSet();
|
||||
private final List<Assignment> allAssignments = Lists.newArrayList();
|
||||
@Getter
|
||||
private int numberOfAttempts = 0;
|
||||
|
||||
protected LessonTracker() {
|
||||
//Mongo
|
||||
}
|
||||
|
||||
public LessonTracker(AbstractLesson lesson) {
|
||||
lessonName = lesson.getId();
|
||||
allAssignments.addAll(lesson.getAssignments());
|
||||
}
|
||||
|
||||
@ -61,7 +66,7 @@ public class LessonTracker implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark an assingment as solved
|
||||
* Mark an assignment as solved
|
||||
*
|
||||
* @param solvedAssignment the assignment which the user solved
|
||||
*/
|
@ -2,7 +2,6 @@ package org.owasp.webgoat.users;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.session.WebGoatUser;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
@ -0,0 +1,61 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.session.Course;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Temp endpoint just for the CTF.
|
||||
*
|
||||
* @author nbaars
|
||||
* @since 3/23/17.
|
||||
*/
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
public class Scoreboard {
|
||||
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
private final UserRepository userRepository;
|
||||
private final Course course;
|
||||
private final PluginMessages pluginMessages;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
private class Ranking {
|
||||
private String username;
|
||||
private List<String> flagsCaptured;
|
||||
}
|
||||
|
||||
@GetMapping("/scoreboard-data")
|
||||
public List<Ranking> getRankings() {
|
||||
List<WebGoatUser> allUsers = userRepository.findAll();
|
||||
List<Ranking> rankings = Lists.newArrayList();
|
||||
for (WebGoatUser user : allUsers) {
|
||||
UserTracker userTracker = userTrackerRepository.findOne(user.getUsername());
|
||||
rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker)));
|
||||
}
|
||||
return rankings;
|
||||
}
|
||||
|
||||
private List<String> challengesSolved(UserTracker userTracker) {
|
||||
List<String> challenges = Lists.newArrayList("Challenge1", "Challenge2", "Challenge3", "Challenge4", "Challenge5");
|
||||
return challenges.stream()
|
||||
.map(c -> userTracker.getLessonTracker(c))
|
||||
.filter(l -> l.isPresent()).map(l -> l.get())
|
||||
.map(l -> l.getLessonName())
|
||||
.map(l -> toLessonTitle(l))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String toLessonTitle(String id) {
|
||||
String titleKey = course.getLessons().stream().filter(l -> l.getId().equals(id)).findFirst().get().getTitle();
|
||||
return pluginMessages.getMessage(titleKey, titleKey);
|
||||
}
|
||||
}
|
@ -1,13 +1,12 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import org.owasp.webgoat.session.WebGoatUser;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
public interface UserRepository extends CrudRepository<WebGoatUser, Long> {
|
||||
public interface UserRepository extends MongoRepository<WebGoatUser, String> {
|
||||
|
||||
WebGoatUser findByUsername(String username);
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webgoat.session.WebGoatUser;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -15,6 +14,7 @@ import org.springframework.stereotype.Service;
|
||||
public class UserService implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
private final UserTrackerRepository userTrackerRepository;
|
||||
|
||||
@Override
|
||||
public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
@ -29,5 +29,6 @@ public class UserService implements UserDetailsService {
|
||||
|
||||
public void addUser(String username, String password) {
|
||||
userRepository.save(new WebGoatUser(username, password));
|
||||
userTrackerRepository.save(new UserTracker(username));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,119 @@
|
||||
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* <p>
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @version $Id: $Id
|
||||
* @since October 29, 2003
|
||||
*/
|
||||
@Slf4j
|
||||
public class UserTracker {
|
||||
|
||||
@Id
|
||||
private final String user;
|
||||
private List<LessonTracker> lessonTrackers = Lists.newArrayList();
|
||||
|
||||
public UserTracker(final String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an existing lesson tracker or create a new one based on the lesson
|
||||
*
|
||||
* @param lesson the lesson
|
||||
* @return a lesson tracker created if not already present
|
||||
*/
|
||||
public LessonTracker getLessonTracker(AbstractLesson lesson) {
|
||||
Optional<LessonTracker> lessonTracker = lessonTrackers
|
||||
.stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst();
|
||||
if (!lessonTracker.isPresent()) {
|
||||
LessonTracker newLessonTracker = new LessonTracker(lesson);
|
||||
lessonTrackers.add(newLessonTracker);
|
||||
return newLessonTracker;
|
||||
} else {
|
||||
return lessonTracker.get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query method for finding a specific lesson tracker based on id
|
||||
*
|
||||
* @param id the id of the lesson
|
||||
* @return optional due to the fact we can only create a lesson tracker based on a lesson
|
||||
*/
|
||||
public Optional<LessonTracker> getLessonTracker(String id) {
|
||||
return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst();
|
||||
}
|
||||
|
||||
public void assignmentSolved(AbstractLesson lesson, String assignmentName) {
|
||||
LessonTracker lessonTracker = getLessonTracker(lesson);
|
||||
lessonTracker.incrementAttempts();
|
||||
lessonTracker.assignmentSolved(assignmentName);
|
||||
}
|
||||
|
||||
public void assignmentFailed(AbstractLesson lesson) {
|
||||
LessonTracker lessonTracker = getLessonTracker(lesson);
|
||||
lessonTracker.incrementAttempts();
|
||||
}
|
||||
|
||||
public void reset(AbstractLesson al) {
|
||||
LessonTracker lessonTracker = getLessonTracker(al);
|
||||
lessonTracker.reset();
|
||||
}
|
||||
|
||||
public int numberOfLessonsSolved() {
|
||||
int numberOfLessonsSolved = 0;
|
||||
for (LessonTracker lessonTracker : lessonTrackers) {
|
||||
if (lessonTracker.isLessonSolved()) {
|
||||
numberOfLessonsSolved = numberOfLessonsSolved + 1;
|
||||
}
|
||||
}
|
||||
return numberOfLessonsSolved;
|
||||
}
|
||||
|
||||
public int numberOfAssignmentsSolved() {
|
||||
int numberOfAssignmentsSolved = 0;
|
||||
for (LessonTracker lessonTracker : lessonTrackers) {
|
||||
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
|
||||
numberOfAssignmentsSolved = lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue();
|
||||
}
|
||||
return numberOfAssignmentsSolved;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/30/17.
|
||||
*/
|
||||
public interface UserTrackerRepository extends MongoRepository<UserTracker, String> {
|
||||
|
||||
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
package org.owasp.webgoat.session;
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Transient;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
@ -17,7 +16,6 @@ import java.util.Collections;
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Getter
|
||||
@Entity
|
||||
public class WebGoatUser implements UserDetails {
|
||||
|
||||
public static final String ROLE_USER = "WEBGOAT_USER";
|
@ -16,6 +16,7 @@ security.enable-csrf=false
|
||||
spring.resources.cache-period=0
|
||||
spring.thymeleaf.cache=false
|
||||
|
||||
webgoat.clean=true
|
||||
webgoat.server.directory=${user.home}/.webgoat/
|
||||
webgoat.user.directory=${user.home}/.webgoat/
|
||||
webgoat.build.version=@project.version@
|
||||
@ -25,18 +26,11 @@ webgoat.emaillist=owasp-webgoat@lists.owasp.org
|
||||
webgoat.feedback.address=webgoat@owasp.org
|
||||
webgoat.feedback.address.html=<A HREF=mailto:webgoat@owasp.org>webgoat@owasp.org</A>
|
||||
webgoat.database.driver=org.hsqldb.jdbcDriver
|
||||
webgoat.database.connection.string=jdbc:hsqldb:mem:test
|
||||
# TODO_NB
|
||||
#webgoat.database.connection.string=jdbc:hsqldb:mem:${USER}
|
||||
webgoat.database.connection.string=jdbc:hsqldb:mem:{USER}
|
||||
webgoat.default.language=en
|
||||
|
||||
spring.data.mongodb.database=webgoat
|
||||
spring.mongodb.embedded.storage.databaseDir=${webgoat.user.directory}/mongodb/
|
||||
|
||||
liquibase.change-log=classpath:db/changelog/db.changelog-master.xml
|
||||
spring.datasource.url=jdbc:hsqldb:file:${user.home}/.webgoat/WebGoatDatabase;hsqldb.write_delay=false
|
||||
spring.datasource.driverClassName=org.hsqldb.jdbcDriver
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=
|
||||
spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect
|
||||
spring.jpa.show-sql=true
|
||||
spring.jpa.hibernate.ddl-auto=none
|
||||
|
||||
#For static file refresh ... and faster dev :D
|
||||
spring.devtools.restart.additional-paths=webgoat-container/src/main/resources/static/js,webgoat-container/src/main/resources/static/css
|
||||
|
@ -6,9 +6,7 @@
|
||||
|
||||
<changeSet author="WebGoat" id="init_schema">
|
||||
<createTable tableName="web_goat_user">
|
||||
<column name="username" type="varchar(32)">
|
||||
<constraints unique="true"/>
|
||||
</column>
|
||||
<column name="username" type="varchar(32)"/>
|
||||
<column name="password" type="varchar(32)"/>
|
||||
<column name="role" type="varchar(32)"/>
|
||||
</createTable>
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 260 KiB |
@ -152,7 +152,7 @@ img {
|
||||
margin-left: 1.5em;*/
|
||||
margin-right: 5px;
|
||||
margin-top: -38px; /* << don't like doing this, but otherwise it does not line up correctly */
|
||||
color:#0F0
|
||||
color:#88FB88 /* #0F0 */
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
@ -958,8 +958,52 @@ cookie-container {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.page-nav-wrapper {
|
||||
display:inline-block;
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.attack-link, .page-link {
|
||||
display: inline-block;
|
||||
background-color: #555;
|
||||
border-radius: 8px;
|
||||
min-width: 20px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
padding-top:2px;
|
||||
}
|
||||
|
||||
.attack-link.solved-true {
|
||||
color:#88FB88;
|
||||
}
|
||||
|
||||
.attack-link.solved-false {
|
||||
color:#f2baba;
|
||||
}
|
||||
|
||||
.attack-link.cur-page, .page-link.cur-page {
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.page-link {
|
||||
color:#eee;
|
||||
}
|
||||
|
||||
.page-link-wrapper {
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.page-link-wrapper span {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.cur-page {
|
||||
border-bottom: 2px solid #000;
|
||||
color:#aaa;
|
||||
}
|
||||
|
||||
span.show-next-page, span.show-prev-page {
|
||||
font-size: 1.3em;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.show-prev-page {
|
||||
@ -970,6 +1014,8 @@ font-size: 1.3em;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
/* attack ... */
|
||||
|
||||
.attack-feedback {
|
||||
font-weight:800;
|
||||
}
|
||||
@ -984,10 +1030,11 @@ font-size: 1.3em;
|
||||
}
|
||||
|
||||
#lesson-hint {
|
||||
background-color: #ccc;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 4px;
|
||||
border-color: #999;
|
||||
margin-top:4px;
|
||||
border-color: #4fa44c;
|
||||
margin-top: 4px;
|
||||
border: 2px solid #24b054;
|
||||
}
|
||||
|
||||
#hintsViewTop{
|
||||
@ -1043,6 +1090,60 @@ font-size: 1.3em;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* temp override
|
||||
//TODO: come up with longer term solution for full-window viewing
|
||||
*/
|
||||
.col-md-8 {
|
||||
width: 95% !important;
|
||||
width: 95% !important
|
||||
}
|
||||
|
||||
/* scoreboard */
|
||||
div.scoreboard-title {
|
||||
font-size:xx-large;
|
||||
}
|
||||
|
||||
.scoreboard-table tr {
|
||||
}
|
||||
|
||||
div.scoreboard-username {
|
||||
background-color: #222;
|
||||
color: aliceblue;
|
||||
padding: 4px;
|
||||
padding-left:8px;
|
||||
font-size: x-large;
|
||||
border-radius:6px;
|
||||
}
|
||||
|
||||
th.username {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
td.user-flags {
|
||||
padding-left: 8px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
div.captured-flag {
|
||||
border-radius: 6px;
|
||||
background-color: #444;
|
||||
color: white;
|
||||
padding: 4px;
|
||||
font-size: x-large;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.scoreboard-page {
|
||||
background-color: #e0dfdc;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.fa-flag {
|
||||
color:red
|
||||
}
|
||||
|
||||
.appseceu-banner {
|
||||
background: url('img/appseceu-17.png') no-repeat 0px 0px;
|
||||
height: 117px;
|
||||
width: 1268px;
|
||||
margin-bottom: 20px;
|
||||
}
|
@ -3,12 +3,11 @@ define(['jquery',
|
||||
'libs/backbone',
|
||||
'goatApp/model/LessonContentModel',
|
||||
'goatApp/view/LessonContentView',
|
||||
'goatApp/view/PlanView',
|
||||
'goatApp/view/SourceView',
|
||||
'goatApp/view/SolutionView',
|
||||
// 'goatApp/view/PlanView',
|
||||
// 'goatApp/view/SourceView',
|
||||
// 'goatApp/view/SolutionView',
|
||||
'goatApp/view/HintView',
|
||||
'goatApp/view/HelpControlsView',
|
||||
'goatApp/view/CookieView',
|
||||
'goatApp/view/ParamView',
|
||||
'goatApp/model/ParamModel',
|
||||
'goatApp/view/DeveloperControlsView',
|
||||
@ -27,12 +26,11 @@ define(['jquery',
|
||||
Backbone,
|
||||
LessonContentModel,
|
||||
LessonContentView,
|
||||
PlanView,
|
||||
SourceView,
|
||||
SolutionView,
|
||||
// PlanView,
|
||||
// SourceView,
|
||||
// SolutionView,
|
||||
HintView,
|
||||
HelpControlsView,
|
||||
CookieView,
|
||||
ParamView,
|
||||
ParamModel,
|
||||
DeveloperControlsView,
|
||||
@ -66,13 +64,29 @@ define(['jquery',
|
||||
this.menuButtonView = new MenuButtonView();
|
||||
this.listenTo(this.lessonContentView, 'assignment:complete', this.updateMenu);
|
||||
this.listenTo(this.lessonContentView, 'assignment:complete', this.updateLessonOverview);
|
||||
this.listenTo(this.lessonContentView, 'endpoints:filtered', this.filterPageHints);
|
||||
};
|
||||
|
||||
this.loadLesson = function(name,pageNum) {
|
||||
this.filterPageHints = function(endpoints) {
|
||||
//filter hints for page by
|
||||
this.lessonHintView.filterHints(endpoints);
|
||||
}
|
||||
|
||||
this.onHideHintsButton = function() {
|
||||
this.helpControlsView.hideHintsButton();
|
||||
}
|
||||
|
||||
this.onShowHintsButton = function() {
|
||||
this.helpControlsView.showHintsButton();
|
||||
}
|
||||
|
||||
this.loadLesson = function(name,pageNum) {
|
||||
if (this.name === name) {
|
||||
this.listenTo(this.lessonHintView, 'hints:showButton', this.onShowHintsButton);
|
||||
this.listenTo(this.lessonHintView, 'hints:hideButton', this.onHideHintsButton);
|
||||
this.lessonContentView.navToPage(pageNum);
|
||||
this.lessonHintView.hideHints();
|
||||
//this.lessonHintView.selectHints();
|
||||
this.titleView.render(this.lessonInfoModel.get('lessonTitle'));
|
||||
return;
|
||||
}
|
||||
@ -82,10 +96,10 @@ define(['jquery',
|
||||
//TODO: implement lesson not found or return to welcome page?
|
||||
}
|
||||
this.lessonContent.loadData({'name':name});
|
||||
this.planView = {};
|
||||
this.solutionView = {};
|
||||
this.sourceView = {};
|
||||
this.lessonHintView = {};
|
||||
// this.planView = {};
|
||||
// this.solutionView = {};
|
||||
// this.sourceView = {};
|
||||
// this.lessonHintView = {};
|
||||
this.name = name;
|
||||
};
|
||||
|
||||
@ -98,15 +112,13 @@ define(['jquery',
|
||||
|
||||
this.listenTo(this.helpControlsView,'hints:show',this.showHints);
|
||||
this.listenTo(this.helpControlsView,'lessonOverview:show',this.showLessonOverview)
|
||||
this.listenTo(this.helpControlsView,'solution:show',this.hideShowHelps);
|
||||
this.listenTo(this.helpControlsView,'source:show',this.hideShowHelps);
|
||||
|
||||
this.listenTo(this.helpControlsView,'lesson:restart',this.restartLesson);
|
||||
this.listenTo(this.developerControlsView, 'dev:labels', this.restartLesson);
|
||||
|
||||
this.helpControlsView.render();
|
||||
this.lessonOverview.hideLessonOverview();
|
||||
this.titleView.render(this.lessonInfoModel.get('lessonTitle'));
|
||||
this.helpControlsView.showHideHintsButton({});
|
||||
};
|
||||
|
||||
this.updateMenu = function() {
|
||||
@ -126,11 +138,14 @@ define(['jquery',
|
||||
this.lessonContentView.model = this.lessonContent;
|
||||
this.lessonContentView.render();
|
||||
|
||||
this.planView = new PlanView();
|
||||
this.solutionView = new SolutionView();
|
||||
this.sourceView = new SourceView();
|
||||
//this.planView = new PlanView();
|
||||
//this.solutionView = new SolutionView();
|
||||
//this.sourceView = new SourceView();
|
||||
if (this.lessonHintView) {
|
||||
this.lessonHintView.stopListening();
|
||||
this.lessonHintView = null;
|
||||
}
|
||||
this.lessonHintView = new HintView();
|
||||
this.cookieView = new CookieView();
|
||||
|
||||
//TODO: instantiate model with values (not sure why was not working before)
|
||||
var paramModel = new ParamModel({});
|
||||
@ -150,34 +165,34 @@ define(['jquery',
|
||||
this.helpsLoaded[curHelp.helpElement] = curHelp.value;
|
||||
};
|
||||
|
||||
this.hideShowHelps = function(showHelp) {
|
||||
var showId = '#lesson-' + showHelp + '-row';
|
||||
var contentId = '#lesson-' + showHelp + '-content';
|
||||
$('.lesson-help').not(showId).hide();
|
||||
if (!showId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($(showId).is(':visible')) {
|
||||
$(showId).hide();
|
||||
return;
|
||||
} else {
|
||||
//TODO: move individual .html operations into individual help views
|
||||
switch(showHelp) {
|
||||
case 'plan':
|
||||
$(contentId).html(this.planView.model.get('content'));
|
||||
break;
|
||||
case 'solution':
|
||||
$(showId).html(this.solutionView.model.get('content'));
|
||||
break;
|
||||
case 'source':
|
||||
$(contentId).html('<pre>' + this.sourceView.model.get('content') + '</pre>');
|
||||
break;
|
||||
}
|
||||
$(showId).show();
|
||||
GoatUtils.scrollToHelp()
|
||||
}
|
||||
};
|
||||
// this.hideShowHelps = function(showHelp) {
|
||||
// var showId = '#lesson-' + showHelp + '-row';
|
||||
// var contentId = '#lesson-' + showHelp + '-content';
|
||||
// $('.lesson-help').not(showId).hide();
|
||||
// if (!showId) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if ($(showId).is(':visible')) {
|
||||
// $(showId).hide();
|
||||
// return;
|
||||
// } else {
|
||||
// //TODO: move individual .html operations into individual help views
|
||||
// switch(showHelp) {
|
||||
// case 'plan':
|
||||
// $(contentId).html(this.planView.model.get('content'));
|
||||
// break;
|
||||
// case 'solution':
|
||||
// $(showId).html(this.solutionView.model.get('content'));
|
||||
// break;
|
||||
// case 'source':
|
||||
// $(contentId).html('<pre>' + this.sourceView.model.get('content') + '</pre>');
|
||||
// break;
|
||||
// }
|
||||
// $(showId).show();
|
||||
// GoatUtils.scrollToHelp()
|
||||
// }
|
||||
// };
|
||||
|
||||
this.showHints = function() {
|
||||
this.lessonHintView.render();
|
||||
@ -194,6 +209,7 @@ define(['jquery',
|
||||
method:'GET'
|
||||
}).done(function(lessonLink) {
|
||||
self.loadLesson(self.name);
|
||||
self.updateMenu();
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
define(['jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'goatApp/model/CookieModel'],
|
||||
'goatApp/model/FlagModel'],
|
||||
function($,
|
||||
_,
|
||||
Backbone,
|
||||
CookieModel) {
|
||||
FlagModel) {
|
||||
return Backbone.Collection.extend({
|
||||
url:'service/cookie.mvc',
|
||||
model:CookieModel
|
||||
url:'/WebGoat/scoreboard-data',
|
||||
model:FlagModel
|
||||
});
|
||||
});
|
@ -20,7 +20,6 @@ define(['jquery',
|
||||
|
||||
loadData: function(options) {
|
||||
this.urlRoot = _.escape(encodeURIComponent(options.name)) + '.lesson'
|
||||
|
||||
var self = this;
|
||||
this.fetch().done(function(data) {
|
||||
self.setContent(data);
|
||||
@ -32,7 +31,8 @@ define(['jquery',
|
||||
loadHelps = true;
|
||||
}
|
||||
this.set('content',content);
|
||||
this.set('lessonUrl',document.URL);
|
||||
this.set('lessonUrl',document.URL.replace(/\.lesson.*/,'.lesson'));
|
||||
this.set('pageNum',document.URL.replace(/.*\.lesson\/(\d{1,4})$/,'$1'));
|
||||
this.trigger('content:loaded',this,loadHelps);
|
||||
},
|
||||
|
||||
|
@ -3,7 +3,7 @@ define([
|
||||
function(
|
||||
Backbone) {
|
||||
return Backbone.Collection.extend({
|
||||
tagName: 'ul',
|
||||
//tagName: 'ul',
|
||||
url: 'service/lessonoverview.mvc'
|
||||
});
|
||||
});
|
||||
|
@ -0,0 +1,17 @@
|
||||
define(['jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'goatApp/support/goatAsyncErrorHandler',
|
||||
'goatApp/view/ScoreboardView'],
|
||||
function ($,
|
||||
_,
|
||||
Backbone,
|
||||
asyncErrorHandler,
|
||||
ScoreboardView) {
|
||||
'use strict'
|
||||
return {
|
||||
initApp: function () {
|
||||
scoreboard = new ScoreboardView();
|
||||
}
|
||||
};
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
<div>
|
||||
<div class="page-nav-wrapper"><span class="glyphicon-class glyphicon glyphicon-circle-arrow-left show-prev-page"></span></div>
|
||||
<div class="page-link-wrapper">
|
||||
<% var baseUrl = overview.baseUrl; %>
|
||||
<% _.each(overview.pages, function(page,index) { %>
|
||||
<a href="<%=overview.baseUrl%>/<%=index%>" alt="Page <%=index++ %>">
|
||||
<% if (page.content === 'assignment') { %>
|
||||
<div class="<%=page.pageClass%> <%=page.solvedClass%> <%=page.curPageClass%>"><%=index++%></div>
|
||||
<% } else { %>
|
||||
<div class="<%=page.pageClass%> <%=page.curPageClass%>"><%=index++%></div>
|
||||
<% } %>
|
||||
</a>
|
||||
<% }); %>
|
||||
</div>
|
||||
<div class="page-nav-wrapper"><span class="glyphicon-class glyphicon glyphicon-circle-arrow-right show-next-page"></span></div>
|
||||
</div>
|
@ -0,0 +1,16 @@
|
||||
<div class="scoreboard-title">WebGoat Challenge - AppSec EU 2017</div>
|
||||
<div class="appseceu-banner">banner here</div>
|
||||
<table class="scoreboard-table">
|
||||
<% _.each(rankings, function(userRanking, index) { %>
|
||||
<tr>
|
||||
<th class="username"> <div class="scoreboard-username"><%= index%> <%=userRanking.username %> </div></th>
|
||||
<td class="user-flags"> <% _.each(userRanking.flagsCaptured, function(flag) { %>
|
||||
|
||||
<div class="captured-flag">
|
||||
<i class="fa fa-flag" aria-hidden="true"></i>
|
||||
<%=flag%> </div>
|
||||
<% }); %>
|
||||
</td>
|
||||
</tr>
|
||||
<% }); %>
|
||||
</table>
|
@ -1,34 +0,0 @@
|
||||
define(['jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'goatApp/model/CookieCollection'],
|
||||
function($,
|
||||
_,
|
||||
Backbone,
|
||||
CookieCollection) {
|
||||
return Backbone.View.extend({
|
||||
el:'#cookies-view',
|
||||
|
||||
initialize: function() {
|
||||
this.collection = new CookieCollection();
|
||||
this.listenTo(this.collection,'reset',this.render)
|
||||
this.collection.fetch({reset:true});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html('')
|
||||
var cookieTable;
|
||||
this.collection.each(function(model) {
|
||||
cookieTable = $('<table>',{'class':'cookie-table table-striped table-nonfluid'});
|
||||
_.each(model.keys(), function(attribute) {
|
||||
var newRow = $('<tr>');
|
||||
newRow.append($('<th>',{text:_.escape(attribute)}))
|
||||
newRow.append($('<td>',{text:_.escape(model.get(attribute))}));
|
||||
cookieTable.append(newRow);
|
||||
});
|
||||
});
|
||||
this.$el.append($('<h4>',{text:'Cookie/s'}));
|
||||
this.$el.append(cookieTable);
|
||||
}
|
||||
});
|
||||
});
|
@ -12,18 +12,14 @@ function($,_,Backbone) {
|
||||
this.hasPlan = options.hasPlan;
|
||||
this.hasSolution = options.hasSolution;
|
||||
this.hasSource = options.hasSource;
|
||||
var self = this;
|
||||
Backbone.on('navigatedToPage', function(nav) {
|
||||
self.showHideHintsButton(nav)
|
||||
});
|
||||
},
|
||||
|
||||
showHideHintsButton: function(nav) {
|
||||
if (typeof nav['assignmentPath'] !== 'undefined') {
|
||||
this.$el.find('#show-hints-button').unbind().on('click',this.showHints.bind(this)).show();
|
||||
} else {
|
||||
$('#show-hints-button').hide();
|
||||
}
|
||||
showHintsButton: function(nav) {
|
||||
this.$el.find('#show-hints-button').unbind().on('click',this.showHints.bind(this)).show();
|
||||
},
|
||||
|
||||
hideHintsButton: function(){
|
||||
$('#show-hints-button').hide();
|
||||
},
|
||||
|
||||
render:function(title) {
|
||||
@ -38,7 +34,7 @@ function($,_,Backbone) {
|
||||
this.$el.find('#show-solution-button').unbind().on('click',_.bind(this.showSolution,this)).show();
|
||||
}
|
||||
|
||||
this.$el.find('#show-lesson-overview-button').unbind().on('click', _.bind(this.showLessonOverview, this)).show();
|
||||
//this.$el.find('#show-lesson-overview-button').unbind().on('click', _.bind(this.showLessonOverview, this)).show();
|
||||
this.$el.find('#restart-lesson-button').unbind().on('click',_.bind(this.restartLesson,this)).show();
|
||||
},
|
||||
|
||||
|
@ -19,8 +19,10 @@ function($,
|
||||
this.listenTo(this.collection,'loaded',this.onModelLoaded);
|
||||
this.hideHints();
|
||||
var self = this;
|
||||
// different way to do this?
|
||||
Backbone.on('navigatedToPage', function(nav){
|
||||
self.selectHints(nav)
|
||||
self.selectHints(nav);
|
||||
// end event delegation??
|
||||
});
|
||||
},
|
||||
|
||||
@ -61,14 +63,25 @@ function($,
|
||||
*
|
||||
* @param nav the json structure for navigating
|
||||
*/
|
||||
selectHints: function(nav) {
|
||||
this.curHint = 0;
|
||||
var assignmentPath = nav['assignmentPath'];
|
||||
if (assignmentPath != null) {
|
||||
this.hintsToShow = this.collection.getHintsForAssignment(assignmentPath);
|
||||
filterHints: function(endpoints) {
|
||||
this.hintsToShow = [];
|
||||
_.each(endpoints, this.filterHint, this);
|
||||
|
||||
if (this.hintsToShow.length > 0) {
|
||||
this.trigger('hints:showButton');
|
||||
} else {
|
||||
this.hintsToShow = new Array();
|
||||
}
|
||||
this.trigger('hints:hideButton');
|
||||
}
|
||||
},
|
||||
|
||||
filterHint: function(endpoint) {
|
||||
var self = this;
|
||||
_.each(this.collection.models, function(hintModel) {
|
||||
if (endpoint.indexOf(hintModel.get('assignmentPath')) > -1) {
|
||||
self.hintsToShow.push(hintModel.get('hint'));
|
||||
}
|
||||
});
|
||||
console.log(this.hintsToShow);
|
||||
},
|
||||
|
||||
onModelLoaded: function() {
|
||||
@ -97,7 +110,7 @@ function($,
|
||||
if(this.hintsToShow.length == 0) {
|
||||
// this.hideHints();
|
||||
} else {
|
||||
this.$el.find('#lesson-hint-content').html(polyglot.t(this.hintsToShow[curHint].get('hint')));
|
||||
this.$el.find('#lesson-hint-content').html(polyglot.t(this.hintsToShow[curHint]));
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -3,13 +3,15 @@ define(['jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'libs/jquery.form',
|
||||
'goatApp/view/ErrorNotificationView'],
|
||||
'goatApp/view/ErrorNotificationView',
|
||||
'goatApp/view/PaginationControlView'],
|
||||
function(
|
||||
$,
|
||||
_,
|
||||
Backbone,
|
||||
JQueryForm,
|
||||
ErrorNotificationView) {
|
||||
ErrorNotificationView,
|
||||
PaginationControlView) {
|
||||
return Backbone.View.extend({
|
||||
el:'#lesson-content-wrapper', //TODO << get this fixed up in DOM
|
||||
|
||||
@ -37,7 +39,7 @@ define(['jquery',
|
||||
return -1;
|
||||
},
|
||||
|
||||
/* initial renering */
|
||||
/* initial rendering */
|
||||
render: function() {
|
||||
this.$el.find('.lesson-content').html(this.model.get('content'));
|
||||
this.$el.find('.attack-feedback').hide();
|
||||
@ -45,31 +47,17 @@ define(['jquery',
|
||||
this.makeFormsAjax();
|
||||
//this.ajaxifyAttackHref();
|
||||
$(window).scrollTop(0); //work-around til we get the scroll down sorted out
|
||||
this.initPagination();
|
||||
var startPageNum = this.model.get('pageNum');
|
||||
this.initPagination(startPageNum);
|
||||
},
|
||||
|
||||
initPagination: function() {
|
||||
initPagination: function(startPageNum) {
|
||||
//get basic pagination info
|
||||
this.currentPage = 0;
|
||||
this.$contentPages = this.$el.find('.lesson-page-wrapper');
|
||||
this.numPages = this.$contentPages.length;
|
||||
|
||||
//
|
||||
this.addPaginationControls();
|
||||
if (this.numPages > 1) {
|
||||
//no animation on init
|
||||
this.$contentPages.hide();
|
||||
this.$el.find(this.$contentPages[this.currentPage]).show();
|
||||
this.showNextPageButton();
|
||||
this.hidePrevPageButton();
|
||||
} else if (this.numPages === 1) {
|
||||
this.hideNextPageButton();
|
||||
this.hidePrevPageButton();
|
||||
}
|
||||
},
|
||||
|
||||
setCurrentPage: function (pageNum) {
|
||||
this.currentPage = (_.isNumber(pageNum) && pageNum < this.numPages) ? pageNum : 0;
|
||||
var currentPage = (!isNaN(startPageNum) && startPageNum && startPageNum < this.$contentPages) ? startPageNum : 0;
|
||||
//init views & pagination
|
||||
this.showCurContentPage(currentPage);
|
||||
this.paginationControlView = new PaginationControlView(this.$contentPages,this.model.get('lessonUrl'));
|
||||
},
|
||||
|
||||
getCurrentPage: function () {
|
||||
@ -160,128 +148,29 @@ define(['jquery',
|
||||
this.$curOutput.show(400)
|
||||
},
|
||||
|
||||
/* create, show & hide pagination controls */
|
||||
|
||||
addPaginationControls: function() {
|
||||
var pagingControlsDiv;
|
||||
//this.$el.html();
|
||||
//prev
|
||||
var prevPageButton = $('<span>',{class:'glyphicon-class glyphicon glyphicon-circle-arrow-left show-prev-page'});
|
||||
prevPageButton.unbind().on('click',this.decrementPageView.bind(this));
|
||||
//next
|
||||
var nextPageButton = $('<span>',{class:'glyphicon-class glyphicon glyphicon-circle-arrow-right show-next-page'});
|
||||
nextPageButton.unbind().on('click',this.incrementPageView.bind(this));
|
||||
//add to DOM
|
||||
if (this.$el.find('#lesson-page-controls').length < 1) {
|
||||
pagingControlsDiv = $('<div>',{class:'panel-body', id:'lesson-page-controls'});
|
||||
pagingControlsDiv.append(prevPageButton);
|
||||
pagingControlsDiv.append(nextPageButton);
|
||||
this.$el.find('.lesson-page-controls').append(pagingControlsDiv);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
showPrevPageButton: function() {
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-left.show-prev-page').show();
|
||||
},
|
||||
|
||||
hidePrevPageButton: function() {
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-left.show-prev-page').hide();
|
||||
},
|
||||
|
||||
showNextPageButton: function() {
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').show();
|
||||
},
|
||||
|
||||
hideNextPageButton: function() {
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').hide();
|
||||
},
|
||||
|
||||
/* increment, decrement & display handlers */
|
||||
incrementPageView: function() {
|
||||
if (this.currentPage < this.numPages -1) {
|
||||
this.currentPage++;
|
||||
window.location.href = this.model.get('lessonUrl') + '/' + this.currentPage;
|
||||
//this.showCurContentPage(true);Con
|
||||
}
|
||||
|
||||
if (this.currentPage > 0) {
|
||||
this.showPrevPageButton();
|
||||
}
|
||||
|
||||
if (this.currentPage >= this.numPages -1) {
|
||||
this.hideNextPageButton();
|
||||
this.showPrevPageButton;
|
||||
}
|
||||
},
|
||||
|
||||
decrementPageView: function() {
|
||||
if (this.currentPage > 0) {
|
||||
this.currentPage--;
|
||||
window.location.href = this.model.get('lessonUrl') + '/' + this.currentPage;
|
||||
//this.showCurContentPage(false);
|
||||
}
|
||||
|
||||
if (this.currentPage < this.numPages -1) {
|
||||
this.showNextPageButton();
|
||||
}
|
||||
|
||||
if (this.currentPage == 0) {
|
||||
this.hidePrevPageButton();
|
||||
this.showNextPageButton()
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
showCurContentPage: function(isIncrement) {
|
||||
showCurContentPage: function(pageNum) {
|
||||
this.$contentPages.hide();
|
||||
this.$el.find(this.$contentPages[this.currentPage]).show();
|
||||
this.$el.find(this.$contentPages[pageNum]).show();
|
||||
},
|
||||
|
||||
findAssigmentEndpointOnPage: function(pageNumber) {
|
||||
var contentPage = this.$contentPages[this.currentPage];
|
||||
var form = $('form.attack-form', contentPage);
|
||||
var action = form.attr('action')
|
||||
if (action !== undefined) {
|
||||
return action;
|
||||
findAssigmentEndpointsOnPage: function(pageNumber) {
|
||||
var contentPage = this.$contentPages[pageNumber];
|
||||
var endpoints = []; //going to assume uniqueness since these are assignments
|
||||
var pageForms = $(contentPage).find('form.attack-form');
|
||||
for (var i=0; i<pageForms.length; i++) {
|
||||
endpoints.push(pageForms[i].action);
|
||||
}
|
||||
console.log(endpoints);
|
||||
return endpoints;
|
||||
},
|
||||
|
||||
navToPage: function (pageNum) {
|
||||
this.setCurrentPage(pageNum);//provides validation
|
||||
this.showCurContentPage(this.currentPage);
|
||||
this.hideShowNavButtons();
|
||||
var assignmentPath = this.findAssigmentEndpointOnPage(pageNum);
|
||||
Backbone.trigger('navigatedToPage',{'pageNumber':pageNum, 'assignmentPath' : assignmentPath});
|
||||
},
|
||||
|
||||
hideShowNavButtons: function () {
|
||||
//one page only
|
||||
if (this.numPages === 1) {
|
||||
this.hidePrevPageButton();
|
||||
this.hideNextPageButton();
|
||||
}
|
||||
//first page
|
||||
if (this.currentPage === 0) {
|
||||
this.hidePrevPageButton();
|
||||
if (this.numPages > 1) {
|
||||
this.showNextPageButton();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// > first page, but not last
|
||||
if (this.currentPage > 0 && this.currentPage < this.numPages -1) {
|
||||
this.showNextPageButton();
|
||||
this.showPrevPageButton();
|
||||
return;
|
||||
}
|
||||
// last page and more than one page
|
||||
if (this.currentPage === this.numPages -1 && this.numPages > 1) {
|
||||
this.hideNextPageButton();
|
||||
this.showPrevPageButton();
|
||||
return;
|
||||
}
|
||||
|
||||
this.paginationControlView.setCurrentPage(pageNum);//provides validation
|
||||
this.showCurContentPage(this.paginationControlView.currentPage);
|
||||
this.paginationControlView.render();
|
||||
this.paginationControlView.hideShowNavButtons();
|
||||
var assignmentPaths = this.findAssigmentEndpointsOnPage(pageNum);
|
||||
this.trigger('endpoints:filtered',assignmentPaths);
|
||||
},
|
||||
|
||||
/* for testing */
|
||||
|
@ -39,7 +39,7 @@ function($,
|
||||
} else {
|
||||
this.$el.show();
|
||||
}
|
||||
this.showAssignments();
|
||||
//this.showAssignments();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
@ -0,0 +1,186 @@
|
||||
define(['jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'goatApp/model/LessonOverviewModel',
|
||||
'text!templates/paging_controls.html'],
|
||||
function ($,
|
||||
_,
|
||||
Backbone,
|
||||
LessonOverviewModel,
|
||||
PaginationTemplate) {
|
||||
return Backbone.View.extend({
|
||||
template: PaginationTemplate,
|
||||
el: '#lesson-page-controls',
|
||||
|
||||
initialize: function ($contentPages,baseLessonUrl) {
|
||||
this.$contentPages = $contentPages;
|
||||
this.model = new LessonOverviewModel();
|
||||
this.listenTo(this.model, 'change add remove update reset', this.render);
|
||||
this.numPages = this.$contentPages.length;
|
||||
this.baseUrl = baseLessonUrl;
|
||||
|
||||
this.model.fetch();
|
||||
this.initPagination();
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.parseLinks();
|
||||
var t = _.template(this.template);
|
||||
this.$el.html(t({'overview':this.lessonOverview}));
|
||||
this.bindNavButtons();
|
||||
this.hideShowNavButtons();
|
||||
},
|
||||
|
||||
bindNavButtons: function() {
|
||||
this.$el.find('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').unbind().on('click',this.incrementPageView.bind(this));
|
||||
this.$el.find('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-left.show-prev-page').unbind().on('click', this.decrementPageView.bind(this));
|
||||
this.navButtonsBound = true;
|
||||
},
|
||||
|
||||
parseLinks: function() {
|
||||
var assignmentCount = this.$contentPages.find('.attack-container');
|
||||
var solvedMap = {};
|
||||
var pages = [];
|
||||
// one pass on solved assignmets
|
||||
_.each(this.model.toJSON(), function(assignment) {
|
||||
if (assignment.solved) {
|
||||
var key = assignment.assignment.path; //.replace(/\//g,'');
|
||||
solvedMap[key] = assignment.assignment.name;
|
||||
}
|
||||
});
|
||||
|
||||
isAttackSolved = function (path) {
|
||||
//strip
|
||||
var newPath = path.replace(/^\/WebGoat/,'');
|
||||
if (typeof solvedMap[newPath] !== 'undefined') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var self = this;
|
||||
var pages, pageClass, solved;
|
||||
_.each(this.$contentPages,function(page,index) {
|
||||
var curPageClass = (self.currentPage == index) ? ' cur-page' : '';
|
||||
|
||||
if ($(page).find('.attack-container').length < 1) { // no assignments [attacks]
|
||||
pageClass = 'page-link';
|
||||
pages.push({content:'content',pageClass:pageClass,curPageClass:curPageClass});
|
||||
} else {
|
||||
var $assignmentForms = $(page).find('.attack-container form');
|
||||
// use for loop to avoid anonymous function scope hell
|
||||
//var pageAssignments = {content:'attack',attacks:[]}
|
||||
pageClass = 'attack-link'
|
||||
var solvedClass = 'solved-true'
|
||||
for (var i=0; i< $assignmentForms.length; i++) {
|
||||
//normalize path
|
||||
var action = $assignmentForms.attr('action');//.replace(/\//g,'');
|
||||
if (action && isAttackSolved(action)) {
|
||||
//pageClass = 'fa fa-check-square-o assignment-solved';
|
||||
//pageAssignments.attacks.push({solved:true});
|
||||
} else {
|
||||
solvedClass = 'solved-false';
|
||||
|
||||
}
|
||||
}
|
||||
pages.push({solvedClass:solvedClass,content:'assignment',curPageClass:curPageClass,pageClass:pageClass});
|
||||
}
|
||||
});
|
||||
//assign to the view
|
||||
this.lessonOverview = {
|
||||
baseUrl: this.baseUrl,
|
||||
pages: pages
|
||||
}
|
||||
},
|
||||
|
||||
showPrevPageButton: function() {
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-left.show-prev-page').show();
|
||||
},
|
||||
|
||||
hidePrevPageButton: function() {
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-left.show-prev-page').hide();
|
||||
},
|
||||
|
||||
showNextPageButton: function() {
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').show();
|
||||
},
|
||||
|
||||
hideNextPageButton: function() {
|
||||
$('span.glyphicon-class.glyphicon.glyphicon-circle-arrow-right.show-next-page').hide();
|
||||
},
|
||||
|
||||
initPagination: function() {
|
||||
//track pagination state in this view ... start at 0
|
||||
this.currentPage = 0;
|
||||
},
|
||||
|
||||
setCurrentPage: function (pageNum) {
|
||||
this.currentPage = (_.isNumber(pageNum) && pageNum < this.numPages) ? pageNum : 0;
|
||||
},
|
||||
|
||||
/* increment, decrement & display handlers */
|
||||
incrementPageView: function() {
|
||||
if (this.currentPage < this.numPages -1) {
|
||||
this.currentPage++;
|
||||
window.location.href = this.baseUrl + '/' + this.currentPage;
|
||||
}
|
||||
|
||||
if (this.currentPage > 0) {
|
||||
this.showPrevPageButton();
|
||||
}
|
||||
|
||||
if (this.currentPage >= this.numPages -1) {
|
||||
this.hideNextPageButton();
|
||||
this.showPrevPageButton;
|
||||
}
|
||||
this.render();
|
||||
},
|
||||
|
||||
decrementPageView: function() {
|
||||
if (this.currentPage > 0) {
|
||||
this.currentPage--;
|
||||
window.location.href = this.baseUrl + '/' + this.currentPage;
|
||||
}
|
||||
|
||||
if (this.currentPage < this.numPages -1) {
|
||||
this.showNextPageButton();
|
||||
}
|
||||
|
||||
if (this.currentPage == 0) {
|
||||
this.hidePrevPageButton();
|
||||
this.showNextPageButton()
|
||||
}
|
||||
this.render();
|
||||
},
|
||||
|
||||
hideShowNavButtons: function () {
|
||||
//one page only
|
||||
if (this.numPages === 1) {
|
||||
this.hidePrevPageButton();
|
||||
this.hideNextPageButton();
|
||||
}
|
||||
//first page
|
||||
if (this.currentPage === 0) {
|
||||
this.hidePrevPageButton();
|
||||
if (this.numPages > 1) {
|
||||
this.showNextPageButton();
|
||||
}
|
||||
return;
|
||||
}
|
||||
// > first page, but not last
|
||||
if (this.currentPage > 0 && this.currentPage < this.numPages -1) {
|
||||
this.showNextPageButton();
|
||||
this.showPrevPageButton();
|
||||
return;
|
||||
}
|
||||
// last page and more than one page
|
||||
if (this.currentPage === this.numPages -1 && this.numPages > 1) {
|
||||
this.hideNextPageButton();
|
||||
this.showPrevPageButton();
|
||||
return;
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
});
|
@ -0,0 +1,32 @@
|
||||
define(['jquery',
|
||||
'underscore',
|
||||
'backbone',
|
||||
'goatApp/model/FlagsCollection',
|
||||
'text!templates/scoreboard.html'],
|
||||
function($,
|
||||
_,
|
||||
Backbone,
|
||||
FlagsCollection,
|
||||
ScoreboardTemplate) {
|
||||
return Backbone.View.extend({
|
||||
el:'#scoreboard',
|
||||
|
||||
initialize: function() {
|
||||
this.template = ScoreboardTemplate,
|
||||
this.collection = new FlagsCollection();
|
||||
this.listenTo(this.collection,'reset',this.render)
|
||||
this.collection.fetch({reset:true});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
//this.$el.html('test');
|
||||
var t = _.template(this.template);
|
||||
this.$el.html(t({'rankings':this.collection.toJSON()}));
|
||||
setTimeout(this.pollData.bind(this), 5000);
|
||||
},
|
||||
|
||||
pollData: function() {
|
||||
this.collection.fetch({reset:true});
|
||||
}
|
||||
});
|
||||
});
|
47
webgoat-container/src/main/resources/static/js/scoreboard.js
Normal file
47
webgoat-container/src/main/resources/static/js/scoreboard.js
Normal file
@ -0,0 +1,47 @@
|
||||
//main.js
|
||||
/*
|
||||
/js
|
||||
js/main.js << main file for require.js
|
||||
--/libs/(jquery,backbone,etc.) << base libs
|
||||
--/goatApp/ << base dir for goat application, js-wise
|
||||
--/goatApp/model
|
||||
--/goatApp/view
|
||||
--/goatApp/support
|
||||
--/goatApp/controller
|
||||
*/
|
||||
|
||||
require.config({
|
||||
baseUrl: "js/",
|
||||
paths: {
|
||||
jquery: 'libs/jquery-2.2.4.min',
|
||||
jqueryui: 'libs/jquery-ui-1.10.4',
|
||||
underscore: 'libs/underscore-min',
|
||||
backbone: 'libs/backbone-min',
|
||||
text: 'libs/text',
|
||||
templates: 'goatApp/templates',
|
||||
polyglot: 'libs/polyglot.min'
|
||||
},
|
||||
|
||||
map: {
|
||||
'libs/jquery-base' : {'jquery':'libs/jquery-2.2.4.min'},
|
||||
'libs/jquery-vuln' : {'jquery':'libs/jquery-2.1.4.min'}
|
||||
},
|
||||
|
||||
shim: {
|
||||
"jqueryui": {
|
||||
exports:"$",
|
||||
deps: ['jquery']
|
||||
},
|
||||
underscore: {
|
||||
exports: "_"
|
||||
},
|
||||
backbone: {
|
||||
deps: ['underscore', 'jquery'],
|
||||
exports: 'Backbone'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
require(['jquery','libs/jquery-base','libs/jquery-vuln','jqueryui', 'underscore','backbone','goatApp/scoreboardApp'], function($,jqueryBase,jqueryVuln,jqueryui,_,Backbone,ScoreboardApp){
|
||||
ScoreboardApp.initApp();
|
||||
});
|
@ -2,7 +2,7 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<meta http-equiv="Expires" CONTENT="0"/>
|
||||
<meta http-equiv="Expires" CONTENT="-1"/>
|
||||
<meta http-equiv="Pragma" CONTENT="no-cache"/>
|
||||
<meta http-equiv="Cache-Control" CONTENT="no-cache"/>
|
||||
<meta http-equiv="Cache-Control" CONTENT="no-store"/>
|
||||
@ -143,10 +143,7 @@
|
||||
<button class="btn btn-primary btn-xs btn-danger help-button"
|
||||
id="show-hints-button" th:text="#{show.hints}">Show hints
|
||||
</button>
|
||||
<button class="btn btn-primary btn-xs btn-danger help-button"
|
||||
id="show-lesson-overview-button" th:text="#{lesson.overview}">Lesson
|
||||
overview
|
||||
</button>
|
||||
|
||||
<button class="btn btn-xs help-button" id="restart-lesson-button"
|
||||
th:text="#{reset.lesson}">Reset Lesson
|
||||
</button>
|
||||
@ -172,7 +169,7 @@
|
||||
<div class="panel-body" id="lesson-overview"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lesson-page-controls">
|
||||
<div id="lesson-page-controls">
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -0,0 +1,41 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
|
||||
<head>
|
||||
<meta http-equiv="Expires" CONTENT="-1"/>
|
||||
<meta http-equiv="Pragma" CONTENT="no-cache"/>
|
||||
<meta http-equiv="Cache-Control" CONTENT="no-cache"/>
|
||||
<meta http-equiv="Cache-Control" CONTENT="no-store"/>
|
||||
|
||||
<!--[if lt IE 7]>
|
||||
<id class="no-js lt-ie9 lt-ie8 lt-ie7"/> <![endif]-->
|
||||
<!--[if IE 7]>
|
||||
<id class="no-js lt-ie9 lt-ie8"/> <![endif]-->
|
||||
<!--[if IE 8]>
|
||||
<id class="no-js lt-ie9"/> <![endif]-->
|
||||
<!--[if gt IE 8]><!-->
|
||||
|
||||
<!-- CSS -->
|
||||
<link rel="shortcut icon" th:href="@{/images/favicon.ico}" type="image/x-icon"/>
|
||||
|
||||
<!-- Require.js used to load js asynchronously -->
|
||||
<script src="js/libs/require.min.js" data-main="js/scoreboard.js"/>
|
||||
<!-- main css -->
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/main.css}"/>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/plugins/bootstrap/css/bootstrap.min.css}"/>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/font-awesome.min.css}"/>
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/id; charset=ISO-8859-1"/>
|
||||
<title>WebGoat</title>
|
||||
</head>
|
||||
<body class="scoreboard-page">
|
||||
|
||||
<div id="scoreboard-wrapper">
|
||||
<div id="scoreboard">
|
||||
<!-- will use _ template here -->
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
Reference in New Issue
Block a user