Apply formatting

This will make sure we have a consistent style across our project and the PRs are only concerned with actual changes and no longer about style.
This commit is contained in:
Nanne Baars
2023-01-04 08:07:23 +01:00
committed by GitHub
parent b03777d39b
commit d2a1546dff
336 changed files with 13921 additions and 12688 deletions

View File

@ -1,59 +1,59 @@
/**
* *************************************************************************************************
*
* <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 - 2014 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
*
* <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 - 2014 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.
*/
package org.owasp.webgoat.container;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
/**
* <p>AjaxAuthenticationEntryPoint class.</p>
* AjaxAuthenticationEntryPoint class.
*
* @author zupzup
*/
public class AjaxAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public AjaxAuthenticationEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
public AjaxAuthenticationEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
if (request.getHeader("x-requested-with") != null) {
response.sendError(401, authException.getMessage());
} else {
super.commence(request, response, authException);
}
@Override
public void commence(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException)
throws IOException, ServletException {
if (request.getHeader("x-requested-with") != null) {
response.sendError(401, authException.getMessage());
} else {
super.commence(request, response, authException);
}
}
}

View File

@ -1,37 +1,47 @@
/**
* ************************************************************************************************
* 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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* <p>
*
* @author WebGoat
* @version $Id: $Id
* @since December 12, 2015
*/
package org.owasp.webgoat.container;
import static org.asciidoctor.Asciidoctor.Factory.create;
import io.undertow.util.Headers;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.extension.JavaExtensionRegistry;
@ -46,113 +56,117 @@ import org.thymeleaf.templateresolver.FileTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import static org.asciidoctor.Asciidoctor.Factory.create;
/**
* Thymeleaf resolver for AsciiDoc used in the lesson, can be used as follows inside a lesson file:
* <p>
* <code>
*
* <p><code>
* <div th:replace="doc:AccessControlMatrix_plan.adoc"></div>
* </code>
*/
@Slf4j
public class AsciiDoctorTemplateResolver extends FileTemplateResolver {
private static final Asciidoctor asciidoctor = create();
private static final String PREFIX = "doc:";
private static final Asciidoctor asciidoctor = create();
private static final String PREFIX = "doc:";
private final Language language;
private final ResourceLoader resourceLoader;
private final Language language;
private final ResourceLoader resourceLoader;
public AsciiDoctorTemplateResolver(Language language, ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
this.language = language;
setResolvablePatterns(Set.of(PREFIX + "*"));
public AsciiDoctorTemplateResolver(Language language, ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
this.language = language;
setResolvablePatterns(Set.of(PREFIX + "*"));
}
@Override
protected ITemplateResource computeTemplateResource(
IEngineConfiguration configuration,
String ownerTemplate,
String template,
String resourceName,
String characterEncoding,
Map<String, Object> templateResolutionAttributes) {
var templateName = resourceName.substring(PREFIX.length());
log.debug("template used: {}", templateName);
try (InputStream is = getInputStream(templateName)) {
JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry();
extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class);
extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class);
extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class);
extensionRegistry.inlineMacro("webGoatTempDir", WebGoatTmpDirMacro.class);
extensionRegistry.inlineMacro("operatingSystem", OperatingSystemMacro.class);
extensionRegistry.inlineMacro("username", UsernameMacro.class);
StringWriter writer = new StringWriter();
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
return new StringTemplateResource(writer.getBuffer().toString());
} catch (IOException e) {
return new StringTemplateResource(
"<div>Unable to find documentation for: " + templateName + " </div>");
}
}
@Override
protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map<String, Object> templateResolutionAttributes) {
var templateName = resourceName.substring(PREFIX.length());
log.debug("template used: {}", templateName);
try (InputStream is = getInputStream(templateName)) {
JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry();
extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class);
extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class);
extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class);
extensionRegistry.inlineMacro("webGoatTempDir", WebGoatTmpDirMacro.class);
extensionRegistry.inlineMacro("operatingSystem", OperatingSystemMacro.class);
extensionRegistry.inlineMacro("username", UsernameMacro.class);
StringWriter writer = new StringWriter();
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
return new StringTemplateResource(writer.getBuffer().toString());
} catch (IOException e) {
return new StringTemplateResource("<div>Unable to find documentation for: " + templateName + " </div>");
}
private InputStream getInputStream(String templateName) throws IOException {
log.debug("locale: {}", language.getLocale().getLanguage());
String computedResourceName =
computeResourceName(templateName, language.getLocale().getLanguage());
if (resourceLoader
.getResource("classpath:/" + computedResourceName)
.isReadable() /*isFile()*/) {
log.debug("localized file exists");
return resourceLoader.getResource("classpath:/" + computedResourceName).getInputStream();
} else {
log.debug("using english template");
return resourceLoader.getResource("classpath:/" + templateName).getInputStream();
}
}
private InputStream getInputStream(String templateName) throws IOException {
log.debug("locale: {}",language.getLocale().getLanguage());
String computedResourceName = computeResourceName(templateName, language.getLocale().getLanguage());
if (resourceLoader.getResource("classpath:/" + computedResourceName).isReadable()/*isFile()*/) {
log.debug("localized file exists");
return resourceLoader.getResource("classpath:/" + computedResourceName).getInputStream();
} else {
log.debug("using english template");
return resourceLoader.getResource("classpath:/" + templateName).getInputStream();
}
private String computeResourceName(String resourceName, String language) {
String computedResourceName;
if (language.equals("en")) {
computedResourceName = resourceName;
} else {
computedResourceName = resourceName.replace(".adoc", "_".concat(language).concat(".adoc"));
}
private String computeResourceName(String resourceName, String language) {
String computedResourceName;
if (language.equals("en")) {
computedResourceName = resourceName;
} else {
computedResourceName = resourceName.replace(".adoc", "_".concat(language).concat(".adoc"));
}
log.debug("computed local file name: {}", computedResourceName);
log.debug("file exists: {}",resourceLoader.getResource("classpath:/"+computedResourceName).isReadable());
return computedResourceName;
}
private Map<String, Object> createAttributes() {
Map<String, Object> attributes = new HashMap<>();
attributes.put("source-highlighter", "coderay");
attributes.put("backend", "xhtml");
attributes.put("lang", determineLanguage());
attributes.put("icons", org.asciidoctor.Attributes.FONT_ICONS);
Map<String, Object> options = new HashMap<>();
options.put("attributes", attributes);
return options;
}
private String determineLanguage() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Locale browserLocale = (Locale) request.getSession().getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME);
if (null != browserLocale) {
log.debug("browser locale {}", browserLocale);
return browserLocale.getLanguage();
} else {
String langHeader = request.getHeader(Headers.ACCEPT_LANGUAGE_STRING);
if (null != langHeader) {
log.debug("browser locale {}", langHeader);
return langHeader.substring(0,2);
} else {
log.debug("browser default english");
return "en";
}
}
log.debug("computed local file name: {}", computedResourceName);
log.debug(
"file exists: {}",
resourceLoader.getResource("classpath:/" + computedResourceName).isReadable());
return computedResourceName;
}
private Map<String, Object> createAttributes() {
Map<String, Object> attributes = new HashMap<>();
attributes.put("source-highlighter", "coderay");
attributes.put("backend", "xhtml");
attributes.put("lang", determineLanguage());
attributes.put("icons", org.asciidoctor.Attributes.FONT_ICONS);
Map<String, Object> options = new HashMap<>();
options.put("attributes", attributes);
return options;
}
private String determineLanguage() {
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Locale browserLocale =
(Locale)
request.getSession().getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME);
if (null != browserLocale) {
log.debug("browser locale {}", browserLocale);
return browserLocale.getLanguage();
} else {
String langHeader = request.getHeader(Headers.ACCEPT_LANGUAGE_STRING);
if (null != langHeader) {
log.debug("browser locale {}", langHeader);
return langHeader.substring(0, 2);
} else {
log.debug("browser default english");
return "en";
}
}
}
}

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.container;
import java.util.Map;
import java.util.function.Function;
import javax.sql.DataSource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.Flyway;
@ -11,58 +14,54 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
import java.util.Map;
import java.util.function.Function;
@Configuration
@RequiredArgsConstructor
@Slf4j
public class DatabaseConfiguration {
private final DataSourceProperties properties;
private final LessonScanner lessonScanner;
private final DataSourceProperties properties;
private final LessonScanner lessonScanner;
@Bean
@Primary
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(properties.getDriverClassName());
dataSource.setUrl(properties.getUrl());
dataSource.setUsername(properties.getUsername());
dataSource.setPassword(properties.getPassword());
return dataSource;
}
@Bean
@Primary
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(properties.getDriverClassName());
dataSource.setUrl(properties.getUrl());
dataSource.setUsername(properties.getUsername());
dataSource.setPassword(properties.getPassword());
return dataSource;
}
/**
* Define 2 Flyway instances, 1 for WebGoat itself which it uses for internal storage like users and 1 for lesson
* specific tables we use. This way we clean the data in the lesson database quite easily see {@link RestartLessonService#restartLesson()}
* for how we clean the lesson related tables.
*/
@Bean(initMethod = "migrate")
public Flyway flyWayContainer() {
return Flyway
.configure()
.configuration(Map.of("driver", properties.getDriverClassName()))
.dataSource(dataSource())
.schemas("container")
.locations("db/container")
.load();
}
/**
* Define 2 Flyway instances, 1 for WebGoat itself which it uses for internal storage like users
* and 1 for lesson specific tables we use. This way we clean the data in the lesson database
* quite easily see {@link RestartLessonService#restartLesson()} for how we clean the lesson
* related tables.
*/
@Bean(initMethod = "migrate")
public Flyway flyWayContainer() {
return Flyway.configure()
.configuration(Map.of("driver", properties.getDriverClassName()))
.dataSource(dataSource())
.schemas("container")
.locations("db/container")
.load();
}
@Bean
public Function<String, Flyway> flywayLessons(LessonDataSource lessonDataSource) {
return schema -> Flyway
.configure()
.configuration(Map.of("driver", properties.getDriverClassName()))
.schemas(schema)
.dataSource(lessonDataSource)
.locations("lessons")
.load();
}
@Bean
public Function<String, Flyway> flywayLessons(LessonDataSource lessonDataSource) {
return schema ->
Flyway.configure()
.configuration(Map.of("driver", properties.getDriverClassName()))
.schemas(schema)
.dataSource(lessonDataSource)
.locations("lessons")
.load();
}
@Bean
public LessonDataSource lessonDataSource() {
return new LessonDataSource(dataSource());
}
@Bean
public LessonDataSource lessonDataSource() {
return new LessonDataSource(dataSource());
}
}

View File

@ -9,30 +9,29 @@ import org.springframework.web.servlet.ModelAndView;
/**
* *************************************************************************************************
*
* <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 - 2014 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
*
* <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 - 2014 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 Jeff Williams
@ -45,13 +44,13 @@ import org.springframework.web.servlet.ModelAndView;
@AllArgsConstructor
public class HammerHead {
private final Course course;
private final Course course;
/**
* Entry point for WebGoat, redirects to the first lesson found within the course.
*/
@RequestMapping(path = "/attack", method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView attack() {
return new ModelAndView("redirect:" + "start.mvc" + course.getFirstLesson().getLink());
}
/** Entry point for WebGoat, redirects to the first lesson found within the course. */
@RequestMapping(
path = "/attack",
method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView attack() {
return new ModelAndView("redirect:" + "start.mvc" + course.getFirstLesson().getLink());
}
}

View File

@ -1,70 +1,70 @@
package org.owasp.webgoat.container;
import org.owasp.webgoat.container.lessons.LessonConnectionInvocationHandler;
import org.springframework.jdbc.datasource.ConnectionProxy;
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.owasp.webgoat.container.lessons.LessonConnectionInvocationHandler;
import org.springframework.jdbc.datasource.ConnectionProxy;
public class LessonDataSource implements DataSource {
private final DataSource originalDataSource;
private final DataSource originalDataSource;
public LessonDataSource(DataSource dataSource) {
this.originalDataSource = dataSource;
}
public LessonDataSource(DataSource dataSource) {
this.originalDataSource = dataSource;
}
@Override
public Connection getConnection() throws SQLException {
var targetConnection = originalDataSource.getConnection();
return (Connection) Proxy.newProxyInstance(
ConnectionProxy.class.getClassLoader(),
new Class[]{ConnectionProxy.class},
new LessonConnectionInvocationHandler(targetConnection));
}
@Override
public Connection getConnection() throws SQLException {
var targetConnection = originalDataSource.getConnection();
return (Connection)
Proxy.newProxyInstance(
ConnectionProxy.class.getClassLoader(),
new Class[] {ConnectionProxy.class},
new LessonConnectionInvocationHandler(targetConnection));
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return originalDataSource.getConnection(username, password);
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return originalDataSource.getConnection(username, password);
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return originalDataSource.getLogWriter();
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return originalDataSource.getLogWriter();
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
originalDataSource.setLogWriter(out);
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
originalDataSource.setLogWriter(out);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
originalDataSource.setLoginTimeout(seconds);
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
originalDataSource.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
return originalDataSource.getLoginTimeout();
}
@Override
public int getLoginTimeout() throws SQLException {
return originalDataSource.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return originalDataSource.getParentLogger();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return originalDataSource.getParentLogger();
}
@Override
public <T> T unwrap(Class<T> clazz) throws SQLException {
return originalDataSource.unwrap(clazz);
}
@Override
public <T> T unwrap(Class<T> clazz) throws SQLException {
return originalDataSource.unwrap(clazz);
}
@Override
public boolean isWrapperFor(Class<?> clazz) throws SQLException {
return originalDataSource.isWrapperFor(clazz);
}
@Override
public boolean isWrapperFor(Class<?> clazz) throws SQLException {
return originalDataSource.isWrapperFor(clazz);
}
}

View File

@ -1,36 +1,41 @@
/**
* ************************************************************************************************
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* @author WebGoat
* @version $Id: $Id
* @since October 28, 2003
*/
package org.owasp.webgoat.container;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ResourceLoader;
import org.thymeleaf.IEngineConfiguration;
@ -38,45 +43,48 @@ import org.thymeleaf.templateresolver.FileTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Dynamically resolve a lesson. In the html file this can be invoked as:
*
* <code>
* Dynamically resolve a lesson. In the html file this can be invoked as: <code>
* <div th:case="true" th:replace="lesson:__${lesson.class.simpleName}__"></div>
* </code>
* <p>
* Thymeleaf will invoke this resolver based on the prefix and this implementation will resolve the html in the plugins directory
*
* <p>Thymeleaf will invoke this resolver based on the prefix and this implementation will resolve
* the html in the plugins directory
*/
@Slf4j
public class LessonTemplateResolver extends FileTemplateResolver {
private static final String PREFIX = "lesson:";
private ResourceLoader resourceLoader;
private Map<String, byte[]> resources = new HashMap<>();
private static final String PREFIX = "lesson:";
private ResourceLoader resourceLoader;
private Map<String, byte[]> resources = new HashMap<>();
public LessonTemplateResolver(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
setResolvablePatterns(Set.of(PREFIX + "*"));
}
public LessonTemplateResolver(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
setResolvablePatterns(Set.of(PREFIX + "*"));
}
@Override
protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map<String, Object> templateResolutionAttributes) {
var templateName = resourceName.substring(PREFIX.length());
byte[] resource = resources.get(templateName);
if (resource == null) {
try {
resource = resourceLoader.getResource("classpath:/" + templateName).getInputStream().readAllBytes();
} catch (IOException e) {
log.error("Unable to find lesson HTML: {}", template);
}
resources.put(templateName, resource);
}
return new StringTemplateResource(new String(resource, StandardCharsets.UTF_8));
@Override
protected ITemplateResource computeTemplateResource(
IEngineConfiguration configuration,
String ownerTemplate,
String template,
String resourceName,
String characterEncoding,
Map<String, Object> templateResolutionAttributes) {
var templateName = resourceName.substring(PREFIX.length());
byte[] resource = resources.get(templateName);
if (resource == null) {
try {
resource =
resourceLoader
.getResource("classpath:/" + templateName)
.getInputStream()
.readAllBytes();
} catch (IOException e) {
log.error("Unable to find lesson HTML: {}", template);
}
resources.put(templateName, resource);
}
return new StringTemplateResource(new String(resource, StandardCharsets.UTF_8));
}
}

View File

@ -1,36 +1,40 @@
/**
* ************************************************************************************************
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* @author WebGoat
* @version $Id: $Id
* @since October 28, 2003
*/
package org.owasp.webgoat.container;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.i18n.Language;
@ -62,175 +66,195 @@ import org.thymeleaf.templateresolver.ITemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;
/**
* Configuration for Spring MVC
*/
/** Configuration for Spring MVC */
@Configuration
@RequiredArgsConstructor
@Slf4j
public class MvcConfiguration implements WebMvcConfigurer {
private static final String UTF8 = "UTF-8";
private static final String UTF8 = "UTF-8";
private final LessonScanner lessonScanner;
private final LessonScanner lessonScanner;
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/lesson_content").setViewName("lesson_content");
registry.addViewController("/start.mvc").setViewName("main_new");
registry.addViewController("/scoreboard").setViewName("scoreboard");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/lesson_content").setViewName("lesson_content");
registry.addViewController("/start.mvc").setViewName("main_new");
registry.addViewController("/scoreboard").setViewName("scoreboard");
}
@Bean
public ViewResolver viewResolver(SpringTemplateEngine thymeleafTemplateEngine) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(thymeleafTemplateEngine);
resolver.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
return resolver;
}
@Bean
public ViewResolver viewResolver(SpringTemplateEngine thymeleafTemplateEngine) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(thymeleafTemplateEngine);
resolver.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
return resolver;
}
/**
* Responsible for loading lesson templates based on Thymeleaf, for example:
*
* <div th:include="/lessons/spoofcookie/templates/spoofcookieform.html" id="content"></div>
*/
@Bean
public ITemplateResolver lessonThymeleafTemplateResolver(ResourceLoader resourceLoader) {
var resolver = new FileTemplateResolver() {
@Override
protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map<String, Object> templateResolutionAttributes) {
try (var is = resourceLoader.getResource("classpath:" + resourceName).getInputStream()) {
return new StringTemplateResource(new String(is.readAllBytes(), StandardCharsets.UTF_8));
} catch (IOException e) {
return null;
}
/**
* Responsible for loading lesson templates based on Thymeleaf, for example:
*
* <p><div th:include="/lessons/spoofcookie/templates/spoofcookieform.html" id="content"></div>
*/
@Bean
public ITemplateResolver lessonThymeleafTemplateResolver(ResourceLoader resourceLoader) {
var resolver =
new FileTemplateResolver() {
@Override
protected ITemplateResource computeTemplateResource(
IEngineConfiguration configuration,
String ownerTemplate,
String template,
String resourceName,
String characterEncoding,
Map<String, Object> templateResolutionAttributes) {
try (var is =
resourceLoader.getResource("classpath:" + resourceName).getInputStream()) {
return new StringTemplateResource(
new String(is.readAllBytes(), StandardCharsets.UTF_8));
} catch (IOException e) {
return null;
}
}
};
resolver.setOrder(1);
return resolver;
}
resolver.setOrder(1);
return resolver;
}
/**
* Loads all normal WebGoat specific Thymeleaf templates
*/
@Bean
public ITemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/webgoat/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setOrder(2);
resolver.setCharacterEncoding(UTF8);
resolver.setApplicationContext(applicationContext);
return resolver;
}
/** Loads all normal WebGoat specific Thymeleaf templates */
@Bean
public ITemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/webgoat/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setOrder(2);
resolver.setCharacterEncoding(UTF8);
resolver.setApplicationContext(applicationContext);
return resolver;
}
/**
* Loads the html for the complete lesson, see lesson_content.html
*/
@Bean
public LessonTemplateResolver lessonTemplateResolver(ResourceLoader resourceLoader) {
LessonTemplateResolver resolver = new LessonTemplateResolver(resourceLoader);
resolver.setOrder(0);
resolver.setCacheable(false);
resolver.setCharacterEncoding(UTF8);
return resolver;
}
/** Loads the html for the complete lesson, see lesson_content.html */
@Bean
public LessonTemplateResolver lessonTemplateResolver(ResourceLoader resourceLoader) {
LessonTemplateResolver resolver = new LessonTemplateResolver(resourceLoader);
resolver.setOrder(0);
resolver.setCacheable(false);
resolver.setCharacterEncoding(UTF8);
return resolver;
}
/**
* Loads the lesson asciidoc.
*/
@Bean
public AsciiDoctorTemplateResolver asciiDoctorTemplateResolver(Language language, ResourceLoader resourceLoader) {
log.debug("template locale {}", language);
AsciiDoctorTemplateResolver resolver = new AsciiDoctorTemplateResolver(language, resourceLoader);
resolver.setCacheable(false);
resolver.setOrder(1);
resolver.setCharacterEncoding(UTF8);
return resolver;
}
/** Loads the lesson asciidoc. */
@Bean
public AsciiDoctorTemplateResolver asciiDoctorTemplateResolver(
Language language, ResourceLoader resourceLoader) {
log.debug("template locale {}", language);
AsciiDoctorTemplateResolver resolver =
new AsciiDoctorTemplateResolver(language, resourceLoader);
resolver.setCacheable(false);
resolver.setOrder(1);
resolver.setCharacterEncoding(UTF8);
return resolver;
}
@Bean
public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver springThymeleafTemplateResolver,
LessonTemplateResolver lessonTemplateResolver,
AsciiDoctorTemplateResolver asciiDoctorTemplateResolver,
ITemplateResolver lessonThymeleafTemplateResolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.addDialect(new SpringSecurityDialect());
engine.setTemplateResolvers(
Set.of(lessonTemplateResolver, asciiDoctorTemplateResolver, lessonThymeleafTemplateResolver, springThymeleafTemplateResolver));
return engine;
}
@Bean
public SpringTemplateEngine thymeleafTemplateEngine(
ITemplateResolver springThymeleafTemplateResolver,
LessonTemplateResolver lessonTemplateResolver,
AsciiDoctorTemplateResolver asciiDoctorTemplateResolver,
ITemplateResolver lessonThymeleafTemplateResolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.addDialect(new SpringSecurityDialect());
engine.setTemplateResolvers(
Set.of(
lessonTemplateResolver,
asciiDoctorTemplateResolver,
lessonThymeleafTemplateResolver,
springThymeleafTemplateResolver));
return engine;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//WebGoat internal
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/webgoat/static/css/");
registry.addResourceHandler("/js/**")
.addResourceLocations("classpath:/webgoat/static/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("classpath:/webgoat/static/plugins/");
registry.addResourceHandler("/fonts/**").addResourceLocations("classpath:/webgoat/static/fonts/");
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// WebGoat internal
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/webgoat/static/css/");
registry.addResourceHandler("/js/**").addResourceLocations("classpath:/webgoat/static/js/");
registry
.addResourceHandler("/plugins/**")
.addResourceLocations("classpath:/webgoat/static/plugins/");
registry
.addResourceHandler("/fonts/**")
.addResourceLocations("classpath:/webgoat/static/fonts/");
//WebGoat lessons
registry.addResourceHandler("/images/**").addResourceLocations(lessonScanner.applyPattern("classpath:/lessons/%s/images/").toArray(String[]::new));
registry.addResourceHandler("/lesson_js/**").addResourceLocations(lessonScanner.applyPattern("classpath:/lessons/%s/js/").toArray(String[]::new));
registry.addResourceHandler("/lesson_css/**").addResourceLocations(lessonScanner.applyPattern("classpath:/lessons/%s/css/").toArray(String[]::new));
registry.addResourceHandler("/lesson_templates/**").addResourceLocations(lessonScanner.applyPattern("classpath:/lessons/%s/templates/").toArray(String[]::new));
registry.addResourceHandler("/video/**").addResourceLocations(lessonScanner.applyPattern("classpath:/lessons/%s/video/").toArray(String[]::new));
}
// WebGoat lessons
registry
.addResourceHandler("/images/**")
.addResourceLocations(
lessonScanner.applyPattern("classpath:/lessons/%s/images/").toArray(String[]::new));
registry
.addResourceHandler("/lesson_js/**")
.addResourceLocations(
lessonScanner.applyPattern("classpath:/lessons/%s/js/").toArray(String[]::new));
registry
.addResourceHandler("/lesson_css/**")
.addResourceLocations(
lessonScanner.applyPattern("classpath:/lessons/%s/css/").toArray(String[]::new));
registry
.addResourceHandler("/lesson_templates/**")
.addResourceLocations(
lessonScanner.applyPattern("classpath:/lessons/%s/templates/").toArray(String[]::new));
registry
.addResourceHandler("/video/**")
.addResourceLocations(
lessonScanner.applyPattern("classpath:/lessons/%s/video/").toArray(String[]::new));
}
@Bean
public PluginMessages pluginMessages(Messages messages, Language language,
ResourcePatternResolver resourcePatternResolver) {
PluginMessages pluginMessages = new PluginMessages(messages, language, resourcePatternResolver);
pluginMessages.setDefaultEncoding("UTF-8");
pluginMessages.setBasenames("i18n/WebGoatLabels");
pluginMessages.setFallbackToSystemLocale(false);
return pluginMessages;
}
@Bean
public PluginMessages pluginMessages(
Messages messages, Language language, ResourcePatternResolver resourcePatternResolver) {
PluginMessages pluginMessages = new PluginMessages(messages, language, resourcePatternResolver);
pluginMessages.setDefaultEncoding("UTF-8");
pluginMessages.setBasenames("i18n/WebGoatLabels");
pluginMessages.setFallbackToSystemLocale(false);
return pluginMessages;
}
@Bean
public Language language(LocaleResolver localeResolver) {
return new Language(localeResolver);
}
@Bean
public Language language(LocaleResolver localeResolver) {
return new Language(localeResolver);
}
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
return localeResolver;
}
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
return localeResolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
lci.setParamName("lang");
return lci;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
@Bean
public Messages messageSource(Language language) {
Messages messages = new Messages(language);
messages.setDefaultEncoding("UTF-8");
messages.setBasename("classpath:i18n/messages");
messages.setFallbackToSystemLocale(false);
return messages;
}
@Bean
public LabelDebugger labelDebugger() {
return new LabelDebugger();
}
@Bean
public Messages messageSource(Language language) {
Messages messages = new Messages(language);
messages.setDefaultEncoding("UTF-8");
messages.setBasename("classpath:i18n/messages");
messages.setFallbackToSystemLocale(false);
return messages;
}
@Bean
public LabelDebugger labelDebugger() {
return new LabelDebugger();
}
}

View File

@ -1,36 +1,37 @@
/**
* ************************************************************************************************
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* @author WebGoat
* @version $Id: $Id
* @since October 28, 2003
*/
package org.owasp.webgoat.container;
import java.io.File;
import org.owasp.webgoat.container.session.UserSessionData;
import org.owasp.webgoat.container.session.WebSession;
import org.springframework.beans.factory.annotation.Value;
@ -43,33 +44,31 @@ import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.web.client.RestTemplate;
import java.io.File;
@Configuration
@ComponentScan(basePackages = { "org.owasp.webgoat.container", "org.owasp.webgoat.lessons"})
@ComponentScan(basePackages = {"org.owasp.webgoat.container", "org.owasp.webgoat.lessons"})
@PropertySource("classpath:application-webgoat.properties")
@EnableAutoConfiguration
public class WebGoat {
@Bean(name = "pluginTargetDirectory")
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
return new File(webgoatHome);
}
@Bean(name = "pluginTargetDirectory")
public File pluginTargetDirectory(@Value("${webgoat.user.directory}") final String webgoatHome) {
return new File(webgoatHome);
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public WebSession webSession() {
return new WebSession();
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public WebSession webSession() {
return new WebSession();
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public UserSessionData userSessionData() {
return new UserSessionData("test", "data");
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public UserSessionData userSessionData() {
return new UserSessionData("test", "data");
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

View File

@ -2,36 +2,35 @@
* ************************************************************************************************
* 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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* <p>
*
* @author WebGoat
* @version $Id: $Id
* @since December 12, 2015
*/
package org.owasp.webgoat.container;
import lombok.AllArgsConstructor;
import org.owasp.webgoat.container.i18n.Language;
import org.owasp.webgoat.container.users.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@ -44,59 +43,66 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
/**
* Security configuration for WebGoat.
*/
/** Security configuration for WebGoat. */
@Configuration
@AllArgsConstructor
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserService userDetailsService;
private final UserService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry security = http
.authorizeRequests()
.antMatchers("/css/**", "/images/**", "/js/**", "fonts/**", "/plugins/**", "/registration", "/register.mvc", "/actuator/**").permitAll()
.anyRequest().authenticated();
security.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/welcome.mvc", true)
.usernameParameter("username")
.passwordParameter("password")
.permitAll();
security.and()
.logout().deleteCookies("JSESSIONID").invalidateHttpSession(true);
security.and().csrf().disable();
@Override
protected void configure(HttpSecurity http) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry security =
http.authorizeRequests()
.antMatchers(
"/css/**",
"/images/**",
"/js/**",
"fonts/**",
"/plugins/**",
"/registration",
"/register.mvc",
"/actuator/**")
.permitAll()
.anyRequest()
.authenticated();
security
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/welcome.mvc", true)
.usernameParameter("username")
.passwordParameter("password")
.permitAll();
security.and().logout().deleteCookies("JSESSIONID").invalidateHttpSession(true);
security.and().csrf().disable();
http.headers().cacheControl().disable();
http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login"));
}
http.headers().cacheControl().disable();
http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login"));
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Bean
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return userDetailsService;
}
@Bean
@Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return userDetailsService;
}
@Override
@Bean
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
@Bean
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@SuppressWarnings("deprecation")
@Bean
public NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
@SuppressWarnings("deprecation")
@Bean
public NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}

View File

@ -10,12 +10,12 @@ import org.springframework.web.servlet.ModelAndView;
@RequiredArgsConstructor
public class WebWolfRedirect {
private final ApplicationContext applicationContext;
private final ApplicationContext applicationContext;
@GetMapping("/WebWolf")
public ModelAndView openWebWolf() {
var url = applicationContext.getEnvironment().getProperty("webwolf.url");
@GetMapping("/WebWolf")
public ModelAndView openWebWolf() {
var url = applicationContext.getEnvironment().getProperty("webwolf.url");
return new ModelAndView("redirect:" + url + "/home");
}
return new ModelAndView("redirect:" + url + "/home");
}
}

View File

@ -7,19 +7,20 @@ import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
/**
* Make environment available in the asciidoc code (which you cannot inject because it is handled by the framework)
* Make environment available in the asciidoc code (which you cannot inject because it is handled by
* the framework)
*/
@Component
public class EnvironmentExposure implements ApplicationContextAware {
private static ApplicationContext context;
private static ApplicationContext context;
public static Environment getEnv() {
return context.getEnvironment();
}
public static Environment getEnv() {
return context.getEnvironment();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
}

View File

@ -1,25 +1,25 @@
package org.owasp.webgoat.container.asciidoc;
import java.util.Map;
import org.asciidoctor.ast.ContentNode;
import org.asciidoctor.extension.InlineMacroProcessor;
import java.util.Map;
public class OperatingSystemMacro extends InlineMacroProcessor {
public OperatingSystemMacro(String macroName) {
super(macroName);
}
public OperatingSystemMacro(String macroName) {
super(macroName);
}
public OperatingSystemMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
public OperatingSystemMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
var osName = System.getProperty("os.name");
@Override
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
var osName = System.getProperty("os.name");
//see https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
return createPhraseNode(contentNode, "quoted", osName);
}
// see
// https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
return createPhraseNode(contentNode, "quoted", osName);
}
}

View File

@ -1,31 +1,31 @@
package org.owasp.webgoat.container.asciidoc;
import java.util.Map;
import org.asciidoctor.ast.ContentNode;
import org.asciidoctor.extension.InlineMacroProcessor;
import org.owasp.webgoat.container.users.WebGoatUser;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.Map;
public class UsernameMacro extends InlineMacroProcessor {
public UsernameMacro(String macroName) {
super(macroName);
public UsernameMacro(String macroName) {
super(macroName);
}
public UsernameMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
var auth = SecurityContextHolder.getContext().getAuthentication();
var username = "unknown";
if (auth.getPrincipal() instanceof WebGoatUser webGoatUser) {
username = webGoatUser.getUsername();
}
public UsernameMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
var auth = SecurityContextHolder.getContext().getAuthentication();
var username = "unknown";
if (auth.getPrincipal() instanceof WebGoatUser webGoatUser) {
username = webGoatUser.getUsername();
}
//see https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
return createPhraseNode(contentNode, "quoted", username);
}
// see
// https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
return createPhraseNode(contentNode, "quoted", username);
}
}

View File

@ -1,26 +1,25 @@
package org.owasp.webgoat.container.asciidoc;
import java.util.Map;
import org.asciidoctor.ast.ContentNode;
import org.asciidoctor.extension.InlineMacroProcessor;
import java.util.Map;
public class WebGoatTmpDirMacro extends InlineMacroProcessor {
public WebGoatTmpDirMacro(String macroName) {
super(macroName);
}
public WebGoatTmpDirMacro(String macroName) {
super(macroName);
}
public WebGoatTmpDirMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
public WebGoatTmpDirMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
var env = EnvironmentExposure.getEnv().getProperty("webgoat.server.directory");
@Override
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
var env = EnvironmentExposure.getEnv().getProperty("webgoat.server.directory");
//see https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
return createPhraseNode(contentNode, "quoted", env);
}
// see
// https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
return createPhraseNode(contentNode, "quoted", env);
}
}

View File

@ -1,25 +1,25 @@
package org.owasp.webgoat.container.asciidoc;
import java.util.Map;
import org.asciidoctor.ast.ContentNode;
import org.asciidoctor.extension.InlineMacroProcessor;
import java.util.Map;
public class WebGoatVersionMacro extends InlineMacroProcessor {
public WebGoatVersionMacro(String macroName) {
super(macroName);
}
public WebGoatVersionMacro(String macroName) {
super(macroName);
}
public WebGoatVersionMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
public WebGoatVersionMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
var webgoatVersion = EnvironmentExposure.getEnv().getProperty("webgoat.build.version");
@Override
public Object process(ContentNode contentNode, String target, Map<String, Object> attributes) {
var webgoatVersion = EnvironmentExposure.getEnv().getProperty("webgoat.build.version");
//see https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
return createPhraseNode(contentNode, "quoted", webgoatVersion);
}
// see
// https://discuss.asciidoctor.org/How-to-create-inline-macro-producing-HTML-In-AsciidoctorJ-td8313.html for why quoted is used
return createPhraseNode(contentNode, "quoted", webgoatVersion);
}
}

View File

@ -1,73 +1,73 @@
package org.owasp.webgoat.container.asciidoc;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.asciidoctor.ast.ContentNode;
import org.asciidoctor.extension.InlineMacroProcessor;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* Usage in asciidoc:
* <p>
* webWolfLink:here[] will display a href with here as text
*
* <p>webWolfLink:here[] will display a href with here as text
*/
public class WebWolfMacro extends InlineMacroProcessor {
public WebWolfMacro(String macroName) {
super(macroName);
public WebWolfMacro(String macroName) {
super(macroName);
}
public WebWolfMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
public Object process(ContentNode contentNode, String linkText, Map<String, Object> attributes) {
var env = EnvironmentExposure.getEnv();
var hostname = determineHost(env.getProperty("webwolf.port"));
var target = (String) attributes.getOrDefault("target", "home");
var href = hostname + "/" + target;
// are we using noLink in webWolfLink:landing[noLink]? Then display link with full href
if (displayCompleteLinkNoFormatting(attributes)) {
linkText = href;
}
public WebWolfMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
var options = new HashMap<String, Object>();
options.put("type", ":link");
options.put("target", href);
attributes.put("window", "_blank");
return createPhraseNode(contentNode, "anchor", linkText, attributes, options).convert();
}
private boolean displayCompleteLinkNoFormatting(Map<String, Object> attributes) {
return attributes.values().stream().anyMatch(a -> a.equals("noLink"));
}
/**
* Determine the host from the hostname and ports that were used. The purpose is to make it
* possible to use the application behind a reverse proxy. For instance in the docker
* compose/stack version with webgoat webwolf and nginx proxy. You do not have to use the
* indicated hostname, but if you do, you should define two hosts aliases 127.0.0.1
* www.webgoat.local www.webwolf.local
*/
private String determineHost(String port) {
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String host = request.getHeader("Host");
int semicolonIndex = host.indexOf(":");
if (semicolonIndex == -1 || host.endsWith(":80")) {
host = host.replace(":80", "").replace("www.webgoat.local", "www.webwolf.local");
} else {
host = host.substring(0, semicolonIndex);
host = host.concat(":").concat(port);
}
return "http://" + host + (includeWebWolfContext() ? "/WebWolf" : "");
}
@Override
public Object process(ContentNode contentNode, String linkText, Map<String, Object> attributes) {
var env = EnvironmentExposure.getEnv();
var hostname = determineHost(env.getProperty("webwolf.port"));
var target = (String) attributes.getOrDefault("target", "home");
var href = hostname + "/" + target;
//are we using noLink in webWolfLink:landing[noLink]? Then display link with full href
if (displayCompleteLinkNoFormatting(attributes)) {
linkText = href;
}
var options = new HashMap<String, Object>();
options.put("type", ":link");
options.put("target", href);
attributes.put("window", "_blank");
return createPhraseNode(contentNode, "anchor", linkText, attributes, options).convert();
}
private boolean displayCompleteLinkNoFormatting(Map<String, Object> attributes) {
return attributes.values().stream().anyMatch(a -> a.equals("noLink"));
}
/**
* Determine the host from the hostname and ports that were used.
* The purpose is to make it possible to use the application behind a reverse proxy. For instance in the docker
* compose/stack version with webgoat webwolf and nginx proxy.
* You do not have to use the indicated hostname, but if you do, you should define two hosts aliases
* 127.0.0.1 www.webgoat.local www.webwolf.local
*/
private String determineHost(String port) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String host = request.getHeader("Host");
int semicolonIndex = host.indexOf(":");
if (semicolonIndex == -1 || host.endsWith(":80")) {
host = host.replace(":80", "").replace("www.webgoat.local", "www.webwolf.local");
} else {
host = host.substring(0, semicolonIndex);
host = host.concat(":").concat(port);
}
return "http://" + host + (includeWebWolfContext() ? "/WebWolf" : "");
}
protected boolean includeWebWolfContext() {
return true;
}
protected boolean includeWebWolfContext() {
return true;
}
}

View File

@ -4,22 +4,22 @@ import java.util.Map;
/**
* Usage in asciidoc:
* <p>
* webWolfLink:here[] will display a href with here as text
* webWolfLink:landing[noLink] will display the complete url, for example: http://WW_HOST:WW_PORT/landing
*
* <p>webWolfLink:here[] will display a href with here as text webWolfLink:landing[noLink] will
* display the complete url, for example: http://WW_HOST:WW_PORT/landing
*/
public class WebWolfRootMacro extends WebWolfMacro {
public WebWolfRootMacro(String macroName) {
super(macroName);
}
public WebWolfRootMacro(String macroName) {
super(macroName);
}
public WebWolfRootMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
public WebWolfRootMacro(String macroName, Map<String, Object> config) {
super(macroName, config);
}
@Override
protected boolean includeWebWolfContext() {
return false;
}
@Override
protected boolean includeWebWolfContext() {
return false;
}
}

View File

@ -35,57 +35,58 @@ import org.springframework.beans.factory.annotation.Autowired;
public abstract class AssignmentEndpoint implements Initializeable {
@Autowired
private WebSession webSession;
@Autowired
private UserSessionData userSessionData;
@Getter
@Autowired
private PluginMessages messages;
@Autowired private WebSession webSession;
@Autowired private UserSessionData userSessionData;
@Getter @Autowired private PluginMessages messages;
protected WebSession getWebSession() {
return webSession;
}
protected WebSession getWebSession() {
return webSession;
}
protected UserSessionData getUserSessionData() {
return userSessionData;
}
protected UserSessionData getUserSessionData() {
return userSessionData;
}
/**
* Convenience method for create a successful result:
* <p>
* - Assignment is set to solved
* - Feedback message is set to 'assignment.solved'
* <p>
* Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
* @param assignment
*/
protected AttackResult.AttackResultBuilder success(AssignmentEndpoint assignment) {
return AttackResult.builder(messages).lessonCompleted(true).attemptWasMade().feedback("assignment.solved").assignment(assignment);
}
/**
* Convenience method for create a successful result:
*
* <p>- Assignment is set to solved - Feedback message is set to 'assignment.solved'
*
* <p>Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
* @param assignment
*/
protected AttackResult.AttackResultBuilder success(AssignmentEndpoint assignment) {
return AttackResult.builder(messages)
.lessonCompleted(true)
.attemptWasMade()
.feedback("assignment.solved")
.assignment(assignment);
}
/**
* Convenience method for create a failed result:
* <p>
* - Assignment is set to not solved
* - Feedback message is set to 'assignment.not.solved'
* <p>
* Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
* @param assignment
*/
protected AttackResult.AttackResultBuilder failed(AssignmentEndpoint assignment) {
return AttackResult.builder(messages).lessonCompleted(false).attemptWasMade().feedback("assignment.not.solved").assignment(assignment);
}
/**
* Convenience method for create a failed result:
*
* <p>- Assignment is set to not solved - Feedback message is set to 'assignment.not.solved'
*
* <p>Of course you can overwrite these values in a specific lesson
*
* @return a builder for creating a result from a lesson
* @param assignment
*/
protected AttackResult.AttackResultBuilder failed(AssignmentEndpoint assignment) {
return AttackResult.builder(messages)
.lessonCompleted(false)
.attemptWasMade()
.feedback("assignment.not.solved")
.assignment(assignment);
}
protected AttackResult.AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
return AttackResult.builder(messages).lessonCompleted(false).assignment(assignment);
}
protected AttackResult.AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
return AttackResult.builder(messages).lessonCompleted(false).assignment(assignment);
}
@Override
public void initialize(WebGoatUser user) {
}
@Override
public void initialize(WebGoatUser user) {}
}

View File

@ -5,12 +5,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by nbaars on 1/14/17.
*/
/** Created by nbaars on 1/14/17. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AssignmentHints {
String[] value() default {};
String[] value() default {};
}

View File

@ -1,22 +1,19 @@
package org.owasp.webgoat.container.assignments;
import org.springframework.web.bind.annotation.RequestMethod;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Created by nbaars on 1/14/17.
*/
/** Created by nbaars on 1/14/17. */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AssignmentPath {
String[] path() default {};
String[] path() default {};
RequestMethod[] method() default {};
RequestMethod[] method() default {};
String value() default "";
String value() default "";
}

View File

@ -25,100 +25,104 @@
package org.owasp.webgoat.container.assignments;
import static org.apache.commons.text.StringEscapeUtils.escapeJson;
import lombok.Getter;
import org.owasp.webgoat.container.i18n.PluginMessages;
import static org.apache.commons.text.StringEscapeUtils.escapeJson;
public class AttackResult {
public static class AttackResultBuilder {
public static class AttackResultBuilder {
private boolean lessonCompleted;
private PluginMessages messages;
private Object[] feedbackArgs;
private String feedbackResourceBundleKey;
private String output;
private Object[] outputArgs;
private AssignmentEndpoint assignment;
private boolean attemptWasMade = false;
public AttackResultBuilder(PluginMessages messages) {
this.messages = messages;
}
public AttackResultBuilder lessonCompleted(boolean lessonCompleted) {
this.lessonCompleted = lessonCompleted;
this.feedbackResourceBundleKey = "lesson.completed";
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;
}
public AttackResultBuilder feedback(String resourceBundleKey) {
this.feedbackResourceBundleKey = resourceBundleKey;
return this;
}
public AttackResultBuilder output(String output) {
this.output = output;
return this;
}
public AttackResultBuilder outputArgs(Object... args) {
this.outputArgs = args;
return this;
}
public AttackResultBuilder attemptWasMade() {
this.attemptWasMade = true;
return this;
}
public AttackResult build() {
return new AttackResult(lessonCompleted, messages.getMessage(feedbackResourceBundleKey, feedbackArgs), messages.getMessage(output, output, outputArgs), assignment.getClass().getSimpleName(), attemptWasMade);
}
public AttackResultBuilder assignment(AssignmentEndpoint assignment) {
this.assignment = assignment;
return this;
}
}
@Getter
private boolean lessonCompleted;
@Getter
private String feedback;
@Getter
private PluginMessages messages;
private Object[] feedbackArgs;
private String feedbackResourceBundleKey;
private String output;
@Getter
private final String assignment;
@Getter
private boolean attemptWasMade;
private Object[] outputArgs;
private AssignmentEndpoint assignment;
private boolean attemptWasMade = false;
public AttackResult(boolean lessonCompleted, String feedback, String output, String assignment, boolean attemptWasMade) {
this.lessonCompleted = lessonCompleted;
this.feedback = escapeJson(feedback);
this.output = escapeJson(output);
this.assignment = assignment;
this.attemptWasMade = attemptWasMade;
public AttackResultBuilder(PluginMessages messages) {
this.messages = messages;
}
public static AttackResultBuilder builder(PluginMessages messages) {
return new AttackResultBuilder(messages);
public AttackResultBuilder lessonCompleted(boolean lessonCompleted) {
this.lessonCompleted = lessonCompleted;
this.feedbackResourceBundleKey = "lesson.completed";
return this;
}
public boolean assignmentSolved() {
return lessonCompleted;
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;
}
public AttackResultBuilder feedback(String resourceBundleKey) {
this.feedbackResourceBundleKey = resourceBundleKey;
return this;
}
public AttackResultBuilder output(String output) {
this.output = output;
return this;
}
public AttackResultBuilder outputArgs(Object... args) {
this.outputArgs = args;
return this;
}
public AttackResultBuilder attemptWasMade() {
this.attemptWasMade = true;
return this;
}
public AttackResult build() {
return new AttackResult(
lessonCompleted,
messages.getMessage(feedbackResourceBundleKey, feedbackArgs),
messages.getMessage(output, output, outputArgs),
assignment.getClass().getSimpleName(),
attemptWasMade);
}
public AttackResultBuilder assignment(AssignmentEndpoint assignment) {
this.assignment = assignment;
return this;
}
}
@Getter private boolean lessonCompleted;
@Getter private String feedback;
@Getter private String output;
@Getter private final String assignment;
@Getter private boolean attemptWasMade;
public AttackResult(
boolean lessonCompleted,
String feedback,
String output,
String assignment,
boolean attemptWasMade) {
this.lessonCompleted = lessonCompleted;
this.feedback = escapeJson(feedback);
this.output = escapeJson(output);
this.assignment = assignment;
this.attemptWasMade = attemptWasMade;
}
public static AttackResultBuilder builder(PluginMessages messages) {
return new AttackResultBuilder(messages);
}
public boolean assignmentSolved() {
return lessonCompleted;
}
}

View File

@ -36,39 +36,46 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@RestControllerAdvice
public class LessonTrackerInterceptor implements ResponseBodyAdvice<Object> {
private UserTrackerRepository userTrackerRepository;
private WebSession webSession;
private UserTrackerRepository userTrackerRepository;
private WebSession webSession;
public LessonTrackerInterceptor(UserTrackerRepository userTrackerRepository, WebSession webSession) {
this.userTrackerRepository = userTrackerRepository;
this.webSession = webSession;
public LessonTrackerInterceptor(
UserTrackerRepository userTrackerRepository, WebSession webSession) {
this.userTrackerRepository = userTrackerRepository;
this.webSession = webSession;
}
@Override
public boolean supports(
MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> clazz) {
return true;
}
@Override
public Object beforeBodyWrite(
Object o,
MethodParameter methodParameter,
MediaType mediaType,
Class<? extends HttpMessageConverter<?>> aClass,
ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
if (o instanceof AttackResult attackResult) {
trackProgress(attackResult);
}
return o;
}
@Override
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> clazz) {
return true;
protected AttackResult trackProgress(AttackResult attackResult) {
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
if (userTracker == null) {
userTracker = new UserTracker(webSession.getUserName());
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
if (o instanceof AttackResult attackResult) {
trackProgress(attackResult);
}
return o;
}
protected AttackResult trackProgress(AttackResult attackResult) {
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
if (userTracker == null) {
userTracker = new UserTracker(webSession.getUserName());
}
if (attackResult.assignmentSolved()) {
userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment());
} else {
userTracker.assignmentFailed(webSession.getCurrentLesson());
}
userTrackerRepository.saveAndFlush(userTracker);
return attackResult;
if (attackResult.assignmentSolved()) {
userTracker.assignmentSolved(webSession.getCurrentLesson(), attackResult.getAssignment());
} else {
userTracker.assignmentFailed(webSession.getCurrentLesson());
}
userTrackerRepository.saveAndFlush(userTracker);
return attackResult;
}
}

View File

@ -1,36 +1,37 @@
/**
* ************************************************************************************************
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* @author WebGoat
* @version $Id: $Id
* @since October 28, 2003
*/
package org.owasp.webgoat.container.controller;
import javax.servlet.http.HttpServletRequest;
import org.owasp.webgoat.container.session.Course;
import org.owasp.webgoat.container.session.WebSession;
import org.springframework.stereotype.Controller;
@ -38,52 +39,52 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@Controller
public class StartLesson {
private final WebSession ws;
private final Course course;
private final WebSession ws;
private final Course course;
public StartLesson(WebSession ws, Course course) {
this.ws = ws;
this.course = course;
}
public StartLesson(WebSession ws, Course course) {
this.ws = ws;
this.course = course;
}
/**
* <p>start.</p>
*
* @return a {@link ModelAndView} object.
*/
@RequestMapping(path = "startlesson.mvc", method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView start() {
var model = new ModelAndView();
/**
* start.
*
* @return a {@link ModelAndView} object.
*/
@RequestMapping(
path = "startlesson.mvc",
method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView start() {
var model = new ModelAndView();
model.addObject("course", course);
model.addObject("lesson", ws.getCurrentLesson());
model.setViewName("lesson_content");
model.addObject("course", course);
model.addObject("lesson", ws.getCurrentLesson());
model.setViewName("lesson_content");
return model;
}
return model;
}
@RequestMapping(value = {"*.lesson"}, produces = "text/html")
public ModelAndView lessonPage(HttpServletRequest request) {
var model = new ModelAndView("lesson_content");
var path = request.getRequestURL().toString(); // we now got /a/b/c/AccessControlMatrix.lesson
var lessonName = path.substring(path.lastIndexOf('/') + 1, path.indexOf(".lesson"));
@RequestMapping(
value = {"*.lesson"},
produces = "text/html")
public ModelAndView lessonPage(HttpServletRequest request) {
var model = new ModelAndView("lesson_content");
var path = request.getRequestURL().toString(); // we now got /a/b/c/AccessControlMatrix.lesson
var lessonName = path.substring(path.lastIndexOf('/') + 1, path.indexOf(".lesson"));
course.getLessons()
.stream()
.filter(l -> l.getId().equals(lessonName))
.findFirst()
.ifPresent(lesson -> {
ws.setCurrentLesson(lesson);
model.addObject("lesson", lesson);
});
return model;
}
course.getLessons().stream()
.filter(l -> l.getId().equals(lessonName))
.findFirst()
.ifPresent(
lesson -> {
ws.setCurrentLesson(lesson);
model.addObject("lesson", lesson);
});
return model;
}
}

View File

@ -1,45 +1,42 @@
/**
*************************************************************************************************
* ************************************************************************************************
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* <p>This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
* Copyright (c) 2002 - 2014 Bruce Mayhew
* <p>Copyright (c) 2002 - 2014 Bruce Mayhew
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* <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.
*
* 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>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
* <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.
*
* Getting Source ==============
* <p>Getting Source ==============
*
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* @author WebGoat
* @since October 28, 2003
* @version $Id: $Id
*/
package org.owasp.webgoat.container.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* <p>Welcome class.</p>
* Welcome class.
*
* @author rlawson
* @version $Id: $Id
@ -47,29 +44,28 @@ import javax.servlet.http.HttpSession;
@Controller
public class Welcome {
private static final String WELCOMED = "welcomed";
/**
* <p>welcome.</p>
*
* @param request a {@link javax.servlet.http.HttpServletRequest} object.
* @return a {@link org.springframework.web.servlet.ModelAndView} object.
*/
@GetMapping(path = {"welcome.mvc"})
public ModelAndView welcome(HttpServletRequest request) {
private static final String WELCOMED = "welcomed";
// set the welcome attribute
// this is so the attack servlet does not also
// send them to the welcome page
HttpSession session = request.getSession();
if (session.getAttribute(WELCOMED) == null) {
session.setAttribute(WELCOMED, "true");
}
//go ahead and send them to webgoat (skip the welcome page)
ModelAndView model = new ModelAndView();
model.setViewName("forward:/attack?start=true");
return model;
/**
* welcome.
*
* @param request a {@link javax.servlet.http.HttpServletRequest} object.
* @return a {@link org.springframework.web.servlet.ModelAndView} object.
*/
@GetMapping(path = {"welcome.mvc"})
public ModelAndView welcome(HttpServletRequest request) {
// set the welcome attribute
// this is so the attack servlet does not also
// send them to the welcome page
HttpSession session = request.getSession();
if (session.getAttribute(WELCOMED) == null) {
session.setAttribute(WELCOMED, "true");
}
// go ahead and send them to webgoat (skip the welcome page)
ModelAndView model = new ModelAndView();
model.setViewName("forward:/attack?start=true");
return model;
}
}

View File

@ -25,15 +25,15 @@
package org.owasp.webgoat.container.i18n;
import java.util.Locale;
import lombok.AllArgsConstructor;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.LocaleResolver;
import java.util.Locale;
/**
* Wrapper around the LocaleResolver from Spring so we do not need to bother with passing the HttpRequest object
* when asking for a Locale.
* Wrapper around the LocaleResolver from Spring so we do not need to bother with passing the
* HttpRequest object when asking for a Locale.
*
* @author nbaars
* @date 2/7/17
@ -41,9 +41,10 @@ import java.util.Locale;
@AllArgsConstructor
public class Language {
private final LocaleResolver localeResolver;
private final LocaleResolver localeResolver;
public Locale getLocale() {
return localeResolver.resolveLocale(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());
}
public Locale getLocale() {
return localeResolver.resolveLocale(
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());
}
}

View File

@ -25,36 +25,35 @@
package org.owasp.webgoat.container.i18n;
import java.util.Properties;
import lombok.AllArgsConstructor;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import java.util.Properties;
/**
* <p>ExposedReloadableResourceMessageBundleSource class.</p>
* Extends the reloadable message source with a way to get all messages
* ExposedReloadableResourceMessageBundleSource class. Extends the reloadable message source with a
* way to get all messages
*
* @author zupzup
*/
@AllArgsConstructor
public class Messages extends ReloadableResourceBundleMessageSource {
private final Language language;
private final Language language;
/**
* Gets all messages for presented Locale.
*
* @return all messages
*/
public Properties getMessages() {
return getMergedProperties(language.getLocale()).getProperties();
}
/**
* Gets all messages for presented Locale.
*
* @return all messages
*/
public Properties getMessages() {
return getMergedProperties(language.getLocale()).getProperties();
}
public String getMessage(String code, Object... args) {
return getMessage(code, args, language.getLocale());
}
public String getMessage(String code, Object... args) {
return getMessage(code, args, language.getLocale());
}
public String getMessage(String code, String defaultValue, Object... args) {
return super.getMessage(code, args, defaultValue, language.getLocale());
}
public String getMessage(String code, String defaultValue, Object... args) {
return super.getMessage(code, args, defaultValue, language.getLocale());
}
}

View File

@ -25,11 +25,10 @@
package org.owasp.webgoat.container.i18n;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
import java.util.Properties;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* Message resource bundle for plugins.
@ -38,49 +37,49 @@ import java.util.Properties;
* @date 2/4/17
*/
public class PluginMessages extends ReloadableResourceBundleMessageSource {
private static final String PROPERTIES_SUFFIX = ".properties";
private static final String PROPERTIES_SUFFIX = ".properties";
private final Language language;
private final ResourcePatternResolver resourcePatternResolver;
private final Language language;
private final ResourcePatternResolver resourcePatternResolver;
public PluginMessages(
Messages messages, Language language, ResourcePatternResolver resourcePatternResolver) {
this.language = language;
this.setParentMessageSource(messages);
this.setBasename("WebGoatLabels");
this.resourcePatternResolver = resourcePatternResolver;
}
public PluginMessages(Messages messages, Language language, ResourcePatternResolver resourcePatternResolver) {
this.language = language;
this.setParentMessageSource(messages);
this.setBasename("WebGoatLabels");
this.resourcePatternResolver = resourcePatternResolver;
@Override
protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) {
Properties properties = new Properties();
long lastModified = System.currentTimeMillis();
try {
var resources =
resourcePatternResolver.getResources(
"classpath:/lessons/**/i18n" + "/WebGoatLabels" + PROPERTIES_SUFFIX);
for (var resource : resources) {
String sourcePath = resource.getURI().toString().replace(PROPERTIES_SUFFIX, "");
PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder);
properties.putAll(holder.getProperties());
}
} catch (IOException e) {
logger.error("Unable to read plugin message", e);
}
@Override
protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) {
Properties properties = new Properties();
long lastModified = System.currentTimeMillis();
return new PropertiesHolder(properties, lastModified);
}
try {
var resources = resourcePatternResolver.getResources("classpath:/lessons/**/i18n" +
"/WebGoatLabels" + PROPERTIES_SUFFIX);
for (var resource : resources) {
String sourcePath = resource.getURI().toString().replace(PROPERTIES_SUFFIX, "");
PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder);
properties.putAll(holder.getProperties());
}
} catch (IOException e) {
logger.error("Unable to read plugin message", e);
}
public Properties getMessages() {
return getMergedProperties(language.getLocale()).getProperties();
}
return new PropertiesHolder(properties, lastModified);
}
public String getMessage(String code, Object... args) {
return getMessage(code, args, language.getLocale());
}
public Properties getMessages() {
return getMergedProperties(language.getLocale()).getProperties();
}
public String getMessage(String code, Object... args) {
return getMessage(code, args, language.getLocale());
}
public String getMessage(String code, String defaultValue, Object... args) {
return super.getMessage(code, args, defaultValue, language.getLocale());
}
public String getMessage(String code, String defaultValue, Object... args) {
return super.getMessage(code, args, defaultValue, language.getLocale());
}
}

View File

@ -1,34 +1,34 @@
package org.owasp.webgoat.container.lessons;
import lombok.*;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
import lombok.*;
/**
* ************************************************************************************************
* 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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* <p>
*
* @author nbaars
@ -40,30 +40,33 @@ import java.util.List;
@Entity
public class Assignment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String path;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Transient
private List<String> hints;
private String name;
private String path;
private Assignment() {
//Hibernate
@Transient private List<String> hints;
private Assignment() {
// Hibernate
}
public Assignment(String name) {
this(name, name, new ArrayList<>());
}
public Assignment(String name, String path, List<String> hints) {
if (path.equals("") || path.equals("/") || path.equals("/WebGoat/")) {
throw new IllegalStateException(
"The path of assignment '"
+ name
+ "' overrides WebGoat endpoints, please choose a path within the scope of the"
+ " lesson");
}
public Assignment(String name) {
this(name, name, new ArrayList<>());
}
public Assignment(String name, String path, List<String> hints) {
if (path.equals("") || path.equals("/") || path.equals("/WebGoat/")) {
throw new IllegalStateException("The path of assignment '" + name + "' overrides WebGoat endpoints, please choose a path within the scope of the lesson");
}
this.name = name;
this.path = path;
this.hints = hints;
}
this.name = name;
this.path = path;
this.hints = hints;
}
}

View File

@ -4,30 +4,29 @@ import lombok.Getter;
/**
* *************************************************************************************************
*
* <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 - 2014 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
*
* <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 - 2014 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>
@ -35,40 +34,35 @@ import lombok.Getter;
* @since October 28, 2003
*/
public enum Category {
INTRODUCTION("Introduction", 5),
GENERAL("General", 100),
INTRODUCTION("Introduction", 5),
GENERAL("General", 100),
A1("(A1) Broken Access Control", 301),
A2("(A2) Cryptographic Failures", 302),
A3("(A3) Injection", 303),
A1("(A1) Broken Access Control", 301),
A2("(A2) Cryptographic Failures", 302),
A3("(A3) Injection", 303),
A5("(A5) Security Misconfiguration", 305),
A6("(A6) Vuln & Outdated Components", 306),
A7("(A7) Identity & Auth Failure", 307),
A8("(A8) Software & Data Integrity", 308),
A9("(A9) Security Logging Failures", 309),
A10("(A10) Server-side Request Forgery", 310),
CLIENT_SIDE("Client side", 1700),
A5("(A5) Security Misconfiguration", 305),
A6("(A6) Vuln & Outdated Components", 306),
A7("(A7) Identity & Auth Failure", 307),
A8("(A8) Software & Data Integrity", 308),
A9("(A9) Security Logging Failures", 309),
A10("(A10) Server-side Request Forgery", 310),
CHALLENGE("Challenges", 3000);
CLIENT_SIDE("Client side", 1700),
@Getter
private String name;
@Getter
private Integer ranking;
CHALLENGE("Challenges", 3000);
Category(String name, Integer ranking) {
this.name = name;
this.ranking = ranking;
}
@Getter private String name;
@Getter private Integer ranking;
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return getName();
}
Category(String name, Integer ranking) {
this.name = name;
this.ranking = ranking;
}
/** {@inheritDoc} */
@Override
public String toString() {
return getName();
}
}

View File

@ -22,6 +22,11 @@
package org.owasp.webgoat.container.lessons;
import static java.util.stream.Collectors.groupingBy;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -36,91 +41,103 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
@Slf4j
@Configuration
public class CourseConfiguration {
private final List<Lesson> lessons;
private final List<AssignmentEndpoint> assignments;
private final Map<String, List<AssignmentEndpoint>> assignmentsByPackage;
private final List<Lesson> lessons;
private final List<AssignmentEndpoint> assignments;
private final Map<String, List<AssignmentEndpoint>> assignmentsByPackage;
public CourseConfiguration(List<Lesson> lessons, List<AssignmentEndpoint> assignments) {
this.lessons = lessons;
this.assignments = assignments;
assignmentsByPackage = this.assignments.stream().collect(groupingBy(a -> a.getClass().getPackageName()));
}
public CourseConfiguration(List<Lesson> lessons, List<AssignmentEndpoint> assignments) {
this.lessons = lessons;
this.assignments = assignments;
assignmentsByPackage =
this.assignments.stream().collect(groupingBy(a -> a.getClass().getPackageName()));
}
@Bean
public Course course() {
lessons.stream().forEach(l -> l.setAssignments(createAssignment(l)));
return new Course(lessons);
}
@Bean
public Course course() {
lessons.stream().forEach(l -> l.setAssignments(createAssignment(l)));
return new Course(lessons);
}
private List<Assignment> createAssignment(Lesson lesson) {
var endpoints = assignmentsByPackage.get(lesson.getClass().getPackageName());
if (CollectionUtils.isEmpty(endpoints)) {
log.warn("Lesson: {} has no endpoints, is this intentionally?", lesson.getTitle());
return new ArrayList<>();
}
return endpoints.stream()
.map(e -> new Assignment(e.getClass().getSimpleName(), getPath(e.getClass()), getHints(e.getClass())))
.toList();
private List<Assignment> createAssignment(Lesson lesson) {
var endpoints = assignmentsByPackage.get(lesson.getClass().getPackageName());
if (CollectionUtils.isEmpty(endpoints)) {
log.warn("Lesson: {} has no endpoints, is this intentionally?", lesson.getTitle());
return new ArrayList<>();
}
return endpoints.stream()
.map(
e ->
new Assignment(
e.getClass().getSimpleName(), getPath(e.getClass()), getHints(e.getClass())))
.toList();
}
private String getPath(Class<? extends AssignmentEndpoint> e) {
for (Method m : e.getMethods()) {
if (methodReturnTypeIsOfTypeAttackResult(m)) {
var mapping = getMapping(m);
if (mapping != null) {
return mapping;
}
}
private String getPath(Class<? extends AssignmentEndpoint> e) {
for (Method m : e.getMethods()) {
if (methodReturnTypeIsOfTypeAttackResult(m)) {
var mapping = getMapping(m);
if (mapping != null) {
return mapping;
}
throw new IllegalStateException("Assignment endpoint: " + e + " has no mapping like @GetMapping/@PostMapping etc," +
"with return type 'AttackResult' or 'ResponseEntity<AttackResult>' please consider adding one");
}
}
throw new IllegalStateException(
"Assignment endpoint: "
+ e
+ " has no mapping like @GetMapping/@PostMapping etc,with return type 'AttackResult' or"
+ " 'ResponseEntity<AttackResult>' please consider adding one");
}
private boolean methodReturnTypeIsOfTypeAttackResult(Method m) {
if (m.getReturnType() == AttackResult.class) {
return true;
}
var genericType = m.getGenericReturnType();
if (genericType instanceof ParameterizedType) {
return ((ParameterizedType) m.getGenericReturnType()).getActualTypeArguments()[0] == AttackResult.class;
}
return false;
private boolean methodReturnTypeIsOfTypeAttackResult(Method m) {
if (m.getReturnType() == AttackResult.class) {
return true;
}
var genericType = m.getGenericReturnType();
if (genericType instanceof ParameterizedType) {
return ((ParameterizedType) m.getGenericReturnType()).getActualTypeArguments()[0]
== AttackResult.class;
}
return false;
}
private String getMapping(Method m) {
String[] paths = null;
//Find the path, either it is @GetMapping("/attack") of GetMapping(path = "/attack") both are valid, we need to consider both
if (m.getAnnotation(RequestMapping.class) != null) {
paths = ArrayUtils.addAll(m.getAnnotation(RequestMapping.class).value(), m.getAnnotation(RequestMapping.class).path());
} else if (m.getAnnotation(PostMapping.class) != null) {
paths = ArrayUtils.addAll(m.getAnnotation(PostMapping.class).value(), m.getAnnotation(PostMapping.class).path());
} else if (m.getAnnotation(GetMapping.class) != null) {
paths = ArrayUtils.addAll(m.getAnnotation(GetMapping.class).value(), m.getAnnotation(GetMapping.class).path());
} else if (m.getAnnotation(PutMapping.class) != null) {
paths = ArrayUtils.addAll(m.getAnnotation(PutMapping.class).value(), m.getAnnotation(PutMapping.class).path());
}
if (paths == null) {
return null;
} else {
return Arrays.stream(paths).filter(path -> !"".equals(path)).findFirst().orElse("");
}
private String getMapping(Method m) {
String[] paths = null;
// Find the path, either it is @GetMapping("/attack") of GetMapping(path = "/attack") both are
// valid, we need to consider both
if (m.getAnnotation(RequestMapping.class) != null) {
paths =
ArrayUtils.addAll(
m.getAnnotation(RequestMapping.class).value(),
m.getAnnotation(RequestMapping.class).path());
} else if (m.getAnnotation(PostMapping.class) != null) {
paths =
ArrayUtils.addAll(
m.getAnnotation(PostMapping.class).value(),
m.getAnnotation(PostMapping.class).path());
} else if (m.getAnnotation(GetMapping.class) != null) {
paths =
ArrayUtils.addAll(
m.getAnnotation(GetMapping.class).value(), m.getAnnotation(GetMapping.class).path());
} else if (m.getAnnotation(PutMapping.class) != null) {
paths =
ArrayUtils.addAll(
m.getAnnotation(PutMapping.class).value(), m.getAnnotation(PutMapping.class).path());
}
if (paths == null) {
return null;
} else {
return Arrays.stream(paths).filter(path -> !"".equals(path)).findFirst().orElse("");
}
}
private List<String> getHints(Class<? extends AssignmentEndpoint> e) {
if (e.isAnnotationPresent(AssignmentHints.class)) {
return List.of(e.getAnnotationsByType(AssignmentHints.class)[0].value());
}
return Collections.emptyList();
private List<String> getHints(Class<? extends AssignmentEndpoint> e) {
if (e.isAnnotationPresent(AssignmentHints.class)) {
return List.of(e.getAnnotationsByType(AssignmentHints.class)[0].value());
}
return Collections.emptyList();
}
}

View File

@ -1,28 +1,28 @@
/***************************************************************************************************
*
*
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
*
* Copyright (c) 2002 - 2014 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.
*
*
*/
package org.owasp.webgoat.container.lessons;
@ -30,7 +30,7 @@ package org.owasp.webgoat.container.lessons;
import lombok.Value;
/**
* <p>Hint class.</p>
* Hint class.
*
* @author rlawson
* @version $Id: $Id
@ -38,6 +38,6 @@ import lombok.Value;
@Value
public class Hint {
private String hint;
private String assignmentPath;
private String hint;
private String assignmentPath;
}

View File

@ -3,10 +3,10 @@ package org.owasp.webgoat.container.lessons;
import org.owasp.webgoat.container.users.WebGoatUser;
/**
* Interface for initialization of a lesson. It is called when a new user is added to WebGoat and when a users
* reset a lesson. Make sure to clean beforehand and then re-initialize the lesson.
* Interface for initialization of a lesson. It is called when a new user is added to WebGoat and
* when a users reset a lesson. Make sure to clean beforehand and then re-initialize the lesson.
*/
public interface Initializeable {
void initialize(WebGoatUser webGoatUser);
void initialize(WebGoatUser webGoatUser);
}

View File

@ -22,115 +22,103 @@
package org.owasp.webgoat.container.lessons;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
public abstract class Lesson {
private static int count = 1;
private Integer id = null;
private List<Assignment> assignments;
private static int count = 1;
private Integer id = null;
private List<Assignment> assignments;
/**
* Constructor for the Lesson object
*/
protected Lesson() {
id = ++count;
}
/** Constructor for the Lesson object */
protected Lesson() {
id = ++count;
}
/**
* getName.
*
* @return a {@link java.lang.String} object.
*/
public String getName() {
String className = getClass().getName();
return className.substring(className.lastIndexOf('.') + 1);
}
/**
* <p>getName.</p>
*
* @return a {@link java.lang.String} object.
*/
public String getName() {
String className = getClass().getName();
return className.substring(className.lastIndexOf('.') + 1);
}
/**
* Gets the category attribute of the Lesson object
*
* @return The category value
*/
public Category getCategory() {
return getDefaultCategory();
}
/**
* Gets the category attribute of the Lesson object
*
* @return The category value
*/
public Category getCategory() {
return getDefaultCategory();
}
/**
* getDefaultCategory.
*
* @return a {@link org.owasp.webgoat.container.lessons.Category} object.
*/
protected abstract Category getDefaultCategory();
/**
* <p>getDefaultCategory.</p>
*
* @return a {@link org.owasp.webgoat.container.lessons.Category} object.
*/
protected abstract Category getDefaultCategory();
/**
* Gets the title attribute of the HelloScreen object
*
* @return The title value
*/
public abstract String getTitle();
/**
* Gets the title attribute of the HelloScreen object
*
* @return The title value
*/
public abstract String getTitle();
/**
* Returns the default "path" portion of a lesson's URL.
*
* <p>
*
* <p>Legacy webgoat lesson links are of the form "attack?Screen=Xmenu=Ystage=Z". This method
* returns the path portion of the url, i.e., "attack" in the string above.
*
* <p>Newer, Spring-Controller-based classes will override this method to return "*.do"-styled
* paths.
*
* @return a {@link java.lang.String} object.
*/
protected String getPath() {
return "#lesson/";
}
/**
* <p>Returns the default "path" portion of a lesson's URL.</p>
* <p>
* <p>
* Legacy webgoat lesson links are of the form
* "attack?Screen=Xmenu=Ystage=Z". This method returns the path portion of
* the url, i.e., "attack" in the string above.
* <p>
* Newer, Spring-Controller-based classes will override this method to
* return "*.do"-styled paths.
*
* @return a {@link java.lang.String} object.
*/
protected String getPath() {
return "#lesson/";
}
/**
* Get the link that can be used to request this screen.
* <p>
* Rendering the link in the browser may result in Javascript sending
* additional requests to perform necessary actions or to obtain data
* relevant to the lesson or the element of the lesson selected by the
* user. Thanks to using the hash mark "#" and Javascript handling the
* clicks, the user will experience less waiting as the pages do not have
* to reload entirely.
*
* @return a {@link java.lang.String} object.
*/
public String getLink() {
return String.format("%s%s.lesson", getPath(), getId());
}
/**
* Description of the Method
*
* @return Description of the Return Value
*/
public String toString() {
return getTitle();
}
public final String getId() {
return this.getClass().getSimpleName();
}
public final String getPackage() {
var packageName = this.getClass().getPackageName();
//package name is the direct package name below lessons (any subpackage will be removed)
return packageName.replaceAll("org.owasp.webgoat.lessons.", "").replaceAll("\\..*", "");
}
/**
* Get the link that can be used to request this screen.
*
* <p>Rendering the link in the browser may result in Javascript sending additional requests to
* perform necessary actions or to obtain data relevant to the lesson or the element of the lesson
* selected by the user. Thanks to using the hash mark "#" and Javascript handling the clicks, the
* user will experience less waiting as the pages do not have to reload entirely.
*
* @return a {@link java.lang.String} object.
*/
public String getLink() {
return String.format("%s%s.lesson", getPath(), getId());
}
/**
* Description of the Method
*
* @return Description of the Return Value
*/
public String toString() {
return getTitle();
}
public final String getId() {
return this.getClass().getSimpleName();
}
public final String getPackage() {
var packageName = this.getClass().getPackageName();
// package name is the direct package name below lessons (any subpackage will be removed)
return packageName.replaceAll("org.owasp.webgoat.lessons.", "").replaceAll("\\..*", "");
}
}

View File

@ -1,39 +1,38 @@
package org.owasp.webgoat.container.lessons;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.users.WebGoatUser;
import org.springframework.security.core.context.SecurityContextHolder;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.users.WebGoatUser;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* Handler which sets the correct schema for the currently bounded user. This way users are not seeing each other
* data and we can reset data for just one particular user.
* Handler which sets the correct schema for the currently bounded user. This way users are not
* seeing each other data and we can reset data for just one particular user.
*/
@Slf4j
public class LessonConnectionInvocationHandler implements InvocationHandler {
private final Connection targetConnection;
private final Connection targetConnection;
public LessonConnectionInvocationHandler(Connection targetConnection) {
this.targetConnection = targetConnection;
}
public LessonConnectionInvocationHandler(Connection targetConnection) {
this.targetConnection = targetConnection;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
var authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof WebGoatUser user) {
try (var statement = targetConnection.createStatement()) {
statement.execute("SET SCHEMA \"" + user.getUsername() + "\"");
}
}
try {
return method.invoke(targetConnection, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
var authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof WebGoatUser user) {
try (var statement = targetConnection.createStatement()) {
statement.execute("SET SCHEMA \"" + user.getUsername() + "\"");
}
}
try {
return method.invoke(targetConnection, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}

View File

@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* <p>LessonInfoModel class.</p>
* LessonInfoModel class.
*
* @author dm
* @version $Id: $Id
@ -13,9 +13,8 @@ import lombok.Getter;
@AllArgsConstructor
public class LessonInfoModel {
private String lessonTitle;
private boolean hasSource;
private boolean hasSolution;
private boolean hasPlan;
private String lessonTitle;
private boolean hasSource;
private boolean hasSolution;
private boolean hasPlan;
}

View File

@ -1,166 +1,162 @@
/**
* *************************************************************************************************
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* <p>
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*
* <p>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 - 2014 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.
*/
package org.owasp.webgoat.container.lessons;
import java.util.ArrayList;
import java.util.List;
/**
* <p>LessonMenuItem class.</p>
* LessonMenuItem class.
*
* @author rlawson
* @version $Id: $Id
*/
public class LessonMenuItem {
private String name;
private LessonMenuItemType type;
private List<LessonMenuItem> children = new ArrayList<>();
private boolean complete;
private String link;
private int ranking;
private String name;
private LessonMenuItemType type;
private List<LessonMenuItem> children = new ArrayList<>();
private boolean complete;
private String link;
private int ranking;
/**
* <p>Getter for the field <code>name</code>.</p>
*
* @return the name
*/
public String getName() {
return name;
}
/**
* Getter for the field <code>name</code>.
*
* @return the name
*/
public String getName() {
return name;
}
/**
* <p>Setter for the field <code>name</code>.</p>
*
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* Setter for the field <code>name</code>.
*
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* <p>Getter for the field <code>children</code>.</p>
*
* @return the children
*/
public List<LessonMenuItem> getChildren() {
return children;
}
/**
* Getter for the field <code>children</code>.
*
* @return the children
*/
public List<LessonMenuItem> getChildren() {
return children;
}
/**
* <p>Setter for the field <code>children</code>.</p>
*
* @param children the children to set
*/
public void setChildren(List<LessonMenuItem> children) {
this.children = children;
}
/**
* Setter for the field <code>children</code>.
*
* @param children the children to set
*/
public void setChildren(List<LessonMenuItem> children) {
this.children = children;
}
/**
* <p>Getter for the field <code>type</code>.</p>
*
* @return the type
*/
public LessonMenuItemType getType() {
return type;
}
/**
* Getter for the field <code>type</code>.
*
* @return the type
*/
public LessonMenuItemType getType() {
return type;
}
/**
* <p>Setter for the field <code>type</code>.</p>
*
* @param type the type to set
*/
public void setType(LessonMenuItemType type) {
this.type = type;
}
/**
* Setter for the field <code>type</code>.
*
* @param type the type to set
*/
public void setType(LessonMenuItemType type) {
this.type = type;
}
/**
* <p>addChild.</p>
*
* @param child a {@link LessonMenuItem} object.
*/
public void addChild(LessonMenuItem child) {
children.add(child);
}
/**
* addChild.
*
* @param child a {@link LessonMenuItem} object.
*/
public void addChild(LessonMenuItem child) {
children.add(child);
}
@Override
public String toString() {
StringBuilder bldr = new StringBuilder();
bldr.append("Name: ").append(name).append(" | ");
bldr.append("Type: ").append(type).append(" | ");
return bldr.toString();
}
@Override
public String toString() {
StringBuilder bldr = new StringBuilder();
bldr.append("Name: ").append(name).append(" | ");
bldr.append("Type: ").append(type).append(" | ");
return bldr.toString();
}
/**
* <p>isComplete.</p>
*
* @return the complete
*/
public boolean isComplete() {
return complete;
}
/**
* isComplete.
*
* @return the complete
*/
public boolean isComplete() {
return complete;
}
/**
* <p>Setter for the field <code>complete</code>.</p>
*
* @param complete the complete to set
*/
public void setComplete(boolean complete) {
this.complete = complete;
}
/**
* Setter for the field <code>complete</code>.
*
* @param complete the complete to set
*/
public void setComplete(boolean complete) {
this.complete = complete;
}
/**
* <p>Getter for the field <code>link</code>.</p>
*
* @return the link
*/
public String getLink() {
return link;
}
/**
* Getter for the field <code>link</code>.
*
* @return the link
*/
public String getLink() {
return link;
}
/**
* <p>Setter for the field <code>link</code>.</p>
*
* @param link the link to set
*/
public void setLink(String link) {
this.link = link;
}
public void setRanking(int ranking) {
this.ranking = ranking;
}
public int getRanking() {
return this.ranking;
}
/**
* Setter for the field <code>link</code>.
*
* @param link the link to set
*/
public void setLink(String link) {
this.link = link;
}
public void setRanking(int ranking) {
this.ranking = ranking;
}
public int getRanking() {
return this.ranking;
}
}

View File

@ -1,40 +1,40 @@
/***************************************************************************************************
*
*
*
*
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
* please see http://www.owasp.org/
*
*
* Copyright (c) 2002 - 2014 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.
*
*
*/
package org.owasp.webgoat.container.lessons;
/**
* <p>LessonMenuItemType class.</p>
* LessonMenuItemType class.
*
* @author rlawson
* @version $Id: $Id
*/
public enum LessonMenuItemType {
CATEGORY,
LESSON,
STAGE
CATEGORY,
LESSON,
STAGE
}

View File

@ -1,46 +1,42 @@
package org.owasp.webgoat.container.lessons;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class LessonScanner {
private static final Pattern lessonPattern = Pattern.compile("^.*/lessons/([^/]*)/.*$");
private static final Pattern lessonPattern = Pattern.compile("^.*/lessons/([^/]*)/.*$");
@Getter
private final Set<String> lessons = new HashSet<>();
@Getter private final Set<String> lessons = new HashSet<>();
public LessonScanner(ResourcePatternResolver resourcePatternResolver) {
try {
var resources = resourcePatternResolver.getResources("classpath:/lessons/*/*");
for (var resource : resources) {
//WG can run as a fat jar or as directly from file system we need to support both so use the URL
var url = resource.getURL();
var matcher = lessonPattern.matcher(url.toString());
if (matcher.matches()) {
lessons.add(matcher.group(1));
}
}
log.debug("Found {} lessons", lessons.size());
} catch (IOException e) {
log.warn("No lessons found...");
public LessonScanner(ResourcePatternResolver resourcePatternResolver) {
try {
var resources = resourcePatternResolver.getResources("classpath:/lessons/*/*");
for (var resource : resources) {
// WG can run as a fat jar or as directly from file system we need to support both so use
// the URL
var url = resource.getURL();
var matcher = lessonPattern.matcher(url.toString());
if (matcher.matches()) {
lessons.add(matcher.group(1));
}
}
log.debug("Found {} lessons", lessons.size());
} catch (IOException e) {
log.warn("No lessons found...");
}
}
public List<String> applyPattern(String pattern) {
return lessons.stream().map(lesson -> String.format(pattern, lesson)).toList();
}
public List<String> applyPattern(String pattern) {
return lessons.stream().map(lesson -> String.format(pattern, lesson)).toList();
}
}

View File

@ -9,11 +9,10 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class EnvironmentService {
private final ApplicationContext context;
@GetMapping("/server-directory")
public String homeDirectory() {
return context.getEnvironment().getProperty("webgoat.server.directory");
}
private final ApplicationContext context;
@GetMapping("/server-directory")
public String homeDirectory() {
return context.getEnvironment().getProperty("webgoat.server.directory");
}
}

View File

@ -6,6 +6,8 @@
package org.owasp.webgoat.container.service;
import java.util.Collection;
import java.util.List;
import org.owasp.webgoat.container.lessons.Assignment;
import org.owasp.webgoat.container.lessons.Hint;
import org.owasp.webgoat.container.lessons.Lesson;
@ -14,11 +16,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collection;
import java.util.List;
/**
* <p>HintService class.</p>
* HintService class.
*
* @author rlawson
* @version $Id: $Id
@ -26,36 +25,33 @@ import java.util.List;
@RestController
public class HintService {
public static final String URL_HINTS_MVC = "/service/hint.mvc";
private final WebSession webSession;
public static final String URL_HINTS_MVC = "/service/hint.mvc";
private final WebSession webSession;
public HintService(WebSession webSession) {
this.webSession = webSession;
}
public HintService(WebSession webSession) {
this.webSession = webSession;
}
/**
* Returns hints for current lesson
*
* @return a {@link java.util.List} object.
*/
@GetMapping(path = URL_HINTS_MVC, produces = "application/json")
@ResponseBody
public List<Hint> getHints() {
Lesson l = webSession.getCurrentLesson();
return createAssignmentHints(l);
}
/**
* Returns hints for current lesson
*
* @return a {@link java.util.List} object.
*/
@GetMapping(path = URL_HINTS_MVC, produces = "application/json")
@ResponseBody
public List<Hint> getHints() {
Lesson l = webSession.getCurrentLesson();
return createAssignmentHints(l);
}
private List<Hint> createAssignmentHints(Lesson l) {
if (l != null) {
return l.getAssignments().stream()
.map(this::createHint)
.flatMap(Collection::stream)
.toList();
}
return List.of();
private List<Hint> createAssignmentHints(Lesson l) {
if (l != null) {
return l.getAssignments().stream().map(this::createHint).flatMap(Collection::stream).toList();
}
return List.of();
}
private List<Hint> createHint(Assignment a) {
return a.getHints().stream().map(h -> new Hint(h, a.getPath())).toList();
}
private List<Hint> createHint(Assignment a) {
return a.getHints().stream().map(h -> new Hint(h, a.getPath())).toList();
}
}

View File

@ -1,34 +1,33 @@
/**
* *************************************************************************************************
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* <p>
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*
* <p>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 - 2014 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.
*/
package org.owasp.webgoat.container.service;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.session.LabelDebugger;
@ -40,10 +39,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
/**
* <p>LabelDebugService class.</p>
* LabelDebugService class.
*
* @author nbaars
* @version $Id: $Id
@ -53,45 +50,47 @@ import java.util.Map;
@AllArgsConstructor
public class LabelDebugService {
private static final String URL_DEBUG_LABELS_MVC = "/service/debug/labels.mvc";
private static final String KEY_ENABLED = "enabled";
private static final String KEY_SUCCESS = "success";
private static final String URL_DEBUG_LABELS_MVC = "/service/debug/labels.mvc";
private static final String KEY_ENABLED = "enabled";
private static final String KEY_SUCCESS = "success";
private LabelDebugger labelDebugger;
private LabelDebugger labelDebugger;
/**
* Checks if debugging of labels is enabled or disabled
*
* @return a {@link org.springframework.http.ResponseEntity} object.
*/
@RequestMapping(path = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody
ResponseEntity<Map<String, Object>> checkDebuggingStatus() {
log.debug("Checking label debugging, it is {}", labelDebugger.isEnabled());
Map<String, Object> result = createResponse(labelDebugger.isEnabled());
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* Checks if debugging of labels is enabled or disabled
*
* @return a {@link org.springframework.http.ResponseEntity} object.
*/
@RequestMapping(path = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody ResponseEntity<Map<String, Object>> checkDebuggingStatus() {
log.debug("Checking label debugging, it is {}", labelDebugger.isEnabled());
Map<String, Object> result = createResponse(labelDebugger.isEnabled());
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* Sets the enabled flag on the label debugger to the given parameter
*
* @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object
* @return a {@link org.springframework.http.ResponseEntity} object.
*/
@RequestMapping(value = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE, params = KEY_ENABLED)
public @ResponseBody
ResponseEntity<Map<String, Object>> setDebuggingStatus(@RequestParam("enabled") Boolean enabled) {
log.debug("Setting label debugging to {} ", labelDebugger.isEnabled());
Map<String, Object> result = createResponse(enabled);
labelDebugger.setEnabled(enabled);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* Sets the enabled flag on the label debugger to the given parameter
*
* @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object
* @return a {@link org.springframework.http.ResponseEntity} object.
*/
@RequestMapping(
value = URL_DEBUG_LABELS_MVC,
produces = MediaType.APPLICATION_JSON_VALUE,
params = KEY_ENABLED)
public @ResponseBody ResponseEntity<Map<String, Object>> setDebuggingStatus(
@RequestParam("enabled") Boolean enabled) {
log.debug("Setting label debugging to {} ", labelDebugger.isEnabled());
Map<String, Object> result = createResponse(enabled);
labelDebugger.setEnabled(enabled);
return new ResponseEntity<>(result, HttpStatus.OK);
}
/**
* @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object
* @return a {@link java.util.Map} object.
*/
private Map<String, Object> createResponse(Boolean enabled) {
return Map.of(KEY_SUCCESS, Boolean.TRUE, KEY_ENABLED, enabled);
}
/**
* @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object
* @return a {@link java.util.Map} object.
*/
private Map<String, Object> createResponse(Boolean enabled) {
return Map.of(KEY_SUCCESS, Boolean.TRUE, KEY_ENABLED, enabled);
}
}

View File

@ -1,34 +1,33 @@
/**
* *************************************************************************************************
*
* <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 - 2014 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
*
* <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 - 2014 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.
*/
package org.owasp.webgoat.container.service;
import java.util.Properties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.i18n.Messages;
@ -40,11 +39,8 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Properties;
/**
* <p>LabelService class.</p>
* LabelService class.
*
* @author zupzup
*/
@ -53,19 +49,19 @@ import java.util.Properties;
@RequiredArgsConstructor
public class LabelService {
public static final String URL_LABELS_MVC = "/service/labels.mvc";
private final Messages messages;
private final PluginMessages pluginMessages;
public static final String URL_LABELS_MVC = "/service/labels.mvc";
private final Messages messages;
private final PluginMessages pluginMessages;
/**
* @return a map of all the labels
*/
@GetMapping(path = URL_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<Properties> fetchLabels() {
var allProperties = new Properties();
allProperties.putAll(messages.getMessages());
allProperties.putAll(pluginMessages.getMessages());
return new ResponseEntity<>(allProperties, HttpStatus.OK);
}
/**
* @return a map of all the labels
*/
@GetMapping(path = URL_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<Properties> fetchLabels() {
var allProperties = new Properties();
allProperties.putAll(messages.getMessages());
allProperties.putAll(pluginMessages.getMessages());
return new ResponseEntity<>(allProperties, HttpStatus.OK);
}
}

View File

@ -8,9 +8,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>LessonInfoService class.</p>
* LessonInfoService class.
*
* @author dm
* @version $Id: $Id
@ -19,18 +18,16 @@ import org.springframework.web.bind.annotation.RestController;
@AllArgsConstructor
public class LessonInfoService {
private final WebSession webSession;
/**
* <p>getLessonInfo.</p>
*
* @return a {@link LessonInfoModel} object.
*/
@RequestMapping(path = "/service/lessoninfo.mvc", produces = "application/json")
public @ResponseBody
LessonInfoModel getLessonInfo() {
Lesson lesson = webSession.getCurrentLesson();
return new LessonInfoModel(lesson.getTitle(), false, false, false);
}
private final WebSession webSession;
/**
* getLessonInfo.
*
* @return a {@link LessonInfoModel} object.
*/
@RequestMapping(path = "/service/lessoninfo.mvc", produces = "application/json")
public @ResponseBody LessonInfoModel getLessonInfo() {
Lesson lesson = webSession.getCurrentLesson();
return new LessonInfoModel(lesson.getTitle(), false, false, false);
}
}

View File

@ -1,34 +1,36 @@
/**
* *************************************************************************************************
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* <p>
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*
* <p>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 - 2014 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.
*/
package org.owasp.webgoat.container.service;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import org.owasp.webgoat.container.lessons.Assignment;
import org.owasp.webgoat.container.lessons.Category;
@ -45,13 +47,8 @@ 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.Map;
/**
* <p>LessonMenuService class.</p>
* LessonMenuService class.
*
* @author rlawson
* @version $Id: $Id
@ -60,72 +57,68 @@ import java.util.Map;
@AllArgsConstructor
public class LessonMenuService {
public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc";
private final Course course;
private final WebSession webSession;
private UserTrackerRepository userTrackerRepository;
public static final String URL_LESSONMENU_MVC = "/service/lessonmenu.mvc";
private final Course course;
private final WebSession webSession;
private UserTrackerRepository userTrackerRepository;
@Value("#{'${exclude.categories}'.split(',')}")
private List<String> excludeCategories;
@Value("#{'${exclude.categories}'.split(',')}")
private List<String> excludeCategories;
@Value("#{'${exclude.lessons}'.split(',')}")
private List<String> excludeLessons;
@Value("#{'${exclude.lessons}'.split(',')}")
private List<String> excludeLessons;
/**
* Returns the lesson menu which is used to build the left nav
*
* @return a {@link java.util.List} object.
*/
@RequestMapping(path = URL_LESSONMENU_MVC, produces = "application/json")
public
@ResponseBody
List<LessonMenuItem> showLeftNav() {
List<LessonMenuItem> menu = new ArrayList<>();
List<Category> categories = course.getCategories();
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
/**
* Returns the lesson menu which is used to build the left nav
*
* @return a {@link java.util.List} object.
*/
@RequestMapping(path = URL_LESSONMENU_MVC, produces = "application/json")
public @ResponseBody List<LessonMenuItem> showLeftNav() {
List<LessonMenuItem> menu = new ArrayList<>();
List<Category> categories = course.getCategories();
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
for (Category category : categories) {
if (excludeCategories.contains(category.name())) {
continue;
}
LessonMenuItem categoryItem = new LessonMenuItem();
categoryItem.setName(category.getName());
categoryItem.setType(LessonMenuItemType.CATEGORY);
// check for any lessons for this category
List<Lesson> lessons = course.getLessons(category);
lessons = lessons.stream().sorted(Comparator.comparing(Lesson::getTitle)).toList();
for (Lesson lesson : lessons) {
if (excludeLessons.contains(lesson.getName())) {
continue;
}
LessonMenuItem lessonItem = new LessonMenuItem();
lessonItem.setName(lesson.getTitle());
lessonItem.setLink(lesson.getLink());
lessonItem.setType(LessonMenuItemType.LESSON);
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson);
lessonItem.setComplete(lessonSolved);
categoryItem.addChild(lessonItem);
}
categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking());
menu.add(categoryItem);
for (Category category : categories) {
if (excludeCategories.contains(category.name())) {
continue;
}
LessonMenuItem categoryItem = new LessonMenuItem();
categoryItem.setName(category.getName());
categoryItem.setType(LessonMenuItemType.CATEGORY);
// check for any lessons for this category
List<Lesson> lessons = course.getLessons(category);
lessons = lessons.stream().sorted(Comparator.comparing(Lesson::getTitle)).toList();
for (Lesson lesson : lessons) {
if (excludeLessons.contains(lesson.getName())) {
continue;
}
return menu;
LessonMenuItem lessonItem = new LessonMenuItem();
lessonItem.setName(lesson.getTitle());
lessonItem.setLink(lesson.getLink());
lessonItem.setType(LessonMenuItemType.LESSON);
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
boolean lessonSolved = lessonCompleted(lessonTracker.getLessonOverview(), lesson);
lessonItem.setComplete(lessonSolved);
categoryItem.addChild(lessonItem);
}
categoryItem.getChildren().sort((o1, o2) -> o1.getRanking() - o2.getRanking());
menu.add(categoryItem);
}
return menu;
}
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;
}
}
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;
}
}
return result;
}
}

View File

@ -1,5 +1,6 @@
package org.owasp.webgoat.container.service;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@ -10,11 +11,8 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
/**
* <p>LessonProgressService class.</p>
* LessonProgressService class.
*
* @author webgoat
*/
@ -22,38 +20,38 @@ import java.util.List;
@RequiredArgsConstructor
public class LessonProgressService {
private final UserTrackerRepository userTrackerRepository;
private final WebSession webSession;
private final UserTrackerRepository userTrackerRepository;
private final WebSession webSession;
/**
* Endpoint for fetching the complete lesson overview which informs the user about whether all the assignments are solved.
* Used as the last page of the lesson to generate a lesson overview.
*
* @return list of assignments
*/
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
@ResponseBody
public List<LessonOverview> lessonOverview() {
var userTracker = userTrackerRepository.findByUser(webSession.getUserName());
var currentLesson = webSession.getCurrentLesson();
/**
* Endpoint for fetching the complete lesson overview which informs the user about whether all the
* assignments are solved. Used as the last page of the lesson to generate a lesson overview.
*
* @return list of assignments
*/
@RequestMapping(value = "/service/lessonoverview.mvc", produces = "application/json")
@ResponseBody
public List<LessonOverview> lessonOverview() {
var userTracker = userTrackerRepository.findByUser(webSession.getUserName());
var currentLesson = webSession.getCurrentLesson();
if (currentLesson != null) {
var lessonTracker = userTracker.getLessonTracker(currentLesson);
return lessonTracker.getLessonOverview().entrySet().stream()
.map(entry -> new LessonOverview(entry.getKey(), entry.getValue()))
.toList();
}
return List.of();
if (currentLesson != null) {
var lessonTracker = userTracker.getLessonTracker(currentLesson);
return lessonTracker.getLessonOverview().entrySet().stream()
.map(entry -> new LessonOverview(entry.getKey(), entry.getValue()))
.toList();
}
return List.of();
}
@AllArgsConstructor
@Getter
//Jackson does not really like returning a map of <Assignment, Boolean> directly, see http://stackoverflow.com/questions/11628698/can-we-make-object-as-key-in-map-when-using-json
//so creating intermediate object is the easiest solution
private static class LessonOverview {
@AllArgsConstructor
@Getter
// Jackson does not really like returning a map of <Assignment, Boolean> directly, see
// http://stackoverflow.com/questions/11628698/can-we-make-object-as-key-in-map-when-using-json
// so creating intermediate object is the easiest solution
private static class LessonOverview {
private Assignment assignment;
private Boolean solved;
}
private Assignment assignment;
private Boolean solved;
}
}

View File

@ -6,9 +6,8 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* <p>LessonTitleService class.</p>
* LessonTitleService class.
*
* @author dm
* @version $Id: $Id
@ -16,23 +15,20 @@ import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class LessonTitleService {
private final WebSession webSession;
private final WebSession webSession;
public LessonTitleService(final WebSession webSession) {
this.webSession = webSession;
}
/**
* Returns the title for the current attack
*
* @return a {@link java.lang.String} object.
*/
@RequestMapping(path = "/service/lessontitle.mvc", produces = "application/html")
public
@ResponseBody
String showPlan() {
Lesson lesson = webSession.getCurrentLesson();
return lesson != null ? lesson.getTitle() : "";
}
public LessonTitleService(final WebSession webSession) {
this.webSession = webSession;
}
/**
* Returns the title for the current attack
*
* @return a {@link java.lang.String} object.
*/
@RequestMapping(path = "/service/lessontitle.mvc", produces = "application/html")
public @ResponseBody String showPlan() {
Lesson lesson = webSession.getCurrentLesson();
return lesson != null ? lesson.getTitle() : "";
}
}

View File

@ -1,34 +1,34 @@
/**
* *************************************************************************************************
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
* <p>
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at
* https://github.com/WebGoat/WebGoat, a repository for free software projects.
*
* <p>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 - 2014 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.
*/
package org.owasp.webgoat.container.service;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@ -43,11 +43,8 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.List;
/**
* <p>ReportCardService</p>
* ReportCardService
*
* @author nbaars
* @version $Id: $Id
@ -56,52 +53,53 @@ import java.util.List;
@AllArgsConstructor
public class ReportCardService {
private final WebSession webSession;
private final UserTrackerRepository userTrackerRepository;
private final Course course;
private final PluginMessages pluginMessages;
private final WebSession webSession;
private final UserTrackerRepository userTrackerRepository;
private final Course course;
private final PluginMessages pluginMessages;
/**
* 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() {
final ReportCard reportCard = new ReportCard();
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
reportCard.setTotalNumberOfAssignments(course.getTotalOfAssignments());
/**
* 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() {
final ReportCard reportCard = new ReportCard();
reportCard.setTotalNumberOfLessons(course.getTotalOfLessons());
reportCard.setTotalNumberOfAssignments(course.getTotalOfAssignments());
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
reportCard.setNumberOfAssignmentsSolved(userTracker.numberOfAssignmentsSolved());
reportCard.setNumberOfLessonsSolved(userTracker.numberOfLessonsSolved());
for (Lesson lesson : course.getLessons()) {
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
final LessonStatistics lessonStatistics = new LessonStatistics();
lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle()));
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
reportCard.lessonStatistics.add(lessonStatistics);
}
return reportCard;
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
reportCard.setNumberOfAssignmentsSolved(userTracker.numberOfAssignmentsSolved());
reportCard.setNumberOfLessonsSolved(userTracker.numberOfLessonsSolved());
for (Lesson lesson : course.getLessons()) {
LessonTracker lessonTracker = userTracker.getLessonTracker(lesson);
final LessonStatistics lessonStatistics = new LessonStatistics();
lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle()));
lessonStatistics.setNumberOfAttempts(lessonTracker.getNumberOfAttempts());
lessonStatistics.setSolved(lessonTracker.isLessonSolved());
reportCard.lessonStatistics.add(lessonStatistics);
}
return reportCard;
}
@Getter
@Setter
private final class ReportCard {
@Getter
@Setter
private final class ReportCard {
private int totalNumberOfLessons;
private int totalNumberOfAssignments;
private int solvedLessons;
private int numberOfAssignmentsSolved;
private int numberOfLessonsSolved;
private List<LessonStatistics> lessonStatistics = new ArrayList<>();
}
private int totalNumberOfLessons;
private int totalNumberOfAssignments;
private int solvedLessons;
private int numberOfAssignmentsSolved;
private int numberOfLessonsSolved;
private List<LessonStatistics> lessonStatistics = new ArrayList<>();
}
@Setter
@Getter
private final class LessonStatistics {
private String name;
private boolean solved;
private int numberOfAttempts;
}
@Setter
@Getter
private final class LessonStatistics {
private String name;
private boolean solved;
private int numberOfAttempts;
}
}

View File

@ -24,6 +24,8 @@
package org.owasp.webgoat.container.service;
import java.util.List;
import java.util.function.Function;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flywaydb.core.Flyway;
@ -37,33 +39,30 @@ import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.List;
import java.util.function.Function;
@Controller
@AllArgsConstructor
@Slf4j
public class RestartLessonService {
private final WebSession webSession;
private final UserTrackerRepository userTrackerRepository;
private final Function<String, Flyway> flywayLessons;
private final List<Initializeable> lessonsToInitialize;
private final WebSession webSession;
private final UserTrackerRepository userTrackerRepository;
private final Function<String, Flyway> flywayLessons;
private final List<Initializeable> lessonsToInitialize;
@RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text")
@ResponseStatus(value = HttpStatus.OK)
public void restartLesson() {
Lesson al = webSession.getCurrentLesson();
log.debug("Restarting lesson: " + al);
@RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text")
@ResponseStatus(value = HttpStatus.OK)
public void restartLesson() {
Lesson al = webSession.getCurrentLesson();
log.debug("Restarting lesson: " + al);
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
userTracker.reset(al);
userTrackerRepository.save(userTracker);
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
userTracker.reset(al);
userTrackerRepository.save(userTracker);
var flyway = flywayLessons.apply(webSession.getUserName());
flyway.clean();
flyway.migrate();
var flyway = flywayLessons.apply(webSession.getUserName());
flyway.clean();
flyway.migrate();
lessonsToInitialize.forEach(i -> i.initialize(webSession.getUser()));
}
lessonsToInitialize.forEach(i -> i.initialize(webSession.getUser()));
}
}

View File

@ -17,17 +17,17 @@ import org.springframework.web.bind.annotation.ResponseBody;
@RequiredArgsConstructor
public class SessionService {
private final WebSession webSession;
private final RestartLessonService restartLessonService;
private final Messages messages;
private final WebSession webSession;
private final RestartLessonService restartLessonService;
private final Messages messages;
@RequestMapping(path = "/service/enable-security.mvc", produces = "application/json")
@ResponseBody
public String applySecurity() {
webSession.toggleSecurity();
restartLessonService.restartLesson();
@RequestMapping(path = "/service/enable-security.mvc", produces = "application/json")
@ResponseBody
public String applySecurity() {
webSession.toggleSecurity();
restartLessonService.restartLesson();
var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled";
return messages.getMessage(msg);
}
var msg = webSession.isSecurityEnabled() ? "security.enabled" : "security.disabled";
return messages.getMessage(msg);
}
}

View File

@ -1,36 +1,36 @@
package org.owasp.webgoat.container.session;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.lessons.Category;
import org.owasp.webgoat.container.lessons.Lesson;
import java.util.List;
/**
* ************************************************************************************************
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>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
@ -39,60 +39,61 @@ import java.util.List;
@Slf4j
public class Course {
private List<Lesson> lessons;
private List<Lesson> lessons;
public Course(List<Lesson> lessons) {
this.lessons = lessons;
}
public Course(List<Lesson> lessons) {
this.lessons = lessons;
}
/**
* Gets the categories attribute of the Course object
*
* @return The categories value
*/
public List<Category> getCategories() {
return lessons.parallelStream().map(Lesson::getCategory).distinct().sorted().toList();
}
/**
* Gets the categories attribute of the Course object
*
* @return The categories value
*/
public List<Category> getCategories() {
return lessons.parallelStream().map(Lesson::getCategory).distinct().sorted().toList();
}
/**
* Gets the firstLesson attribute of the Course object
*
* @return The firstLesson value
*/
public Lesson getFirstLesson() {
// Category 0 is the admin function. We want the first real category
// to be returned. This is normally the General category and the Http Basics lesson
return getLessons(getCategories().get(0)).get(0);
}
/**
* Gets the firstLesson attribute of the Course object
*
* @return The firstLesson value
*/
public Lesson getFirstLesson() {
// Category 0 is the admin function. We want the first real category
// to be returned. This is normally the General category and the Http Basics lesson
return getLessons(getCategories().get(0)).get(0);
}
/**
* <p>Getter for the field <code>lessons</code>.</p>
*
* @return a {@link java.util.List} object.
*/
public List<Lesson> getLessons() {
return this.lessons;
}
/**
* Getter for the field <code>lessons</code>.
*
* @return a {@link java.util.List} object.
*/
public List<Lesson> getLessons() {
return this.lessons;
}
/**
* <p>Getter for the field <code>lessons</code>.</p>
*
* @param category a {@link org.owasp.webgoat.container.lessons.Category} object.
* @return a {@link java.util.List} object.
*/
public List<Lesson> getLessons(Category category) {
return this.lessons.stream().filter(l -> l.getCategory() == category).toList();
}
/**
* Getter for the field <code>lessons</code>.
*
* @param category a {@link org.owasp.webgoat.container.lessons.Category} object.
* @return a {@link java.util.List} object.
*/
public List<Lesson> getLessons(Category category) {
return this.lessons.stream().filter(l -> l.getCategory() == category).toList();
}
public void setLessons(List<Lesson> lessons) {
this.lessons = lessons;
}
public void setLessons(List<Lesson> lessons) {
this.lessons = lessons;
}
public int getTotalOfLessons() {
return this.lessons.size();
}
public int getTotalOfLessons() {
return this.lessons.size();
}
public int getTotalOfAssignments() {
return this.lessons.stream().reduce(0, (total, lesson) -> lesson.getAssignments().size() + total, Integer::sum);
}
public int getTotalOfAssignments() {
return this.lessons.stream()
.reduce(0, (total, lesson) -> lesson.getAssignments().size() + total, Integer::sum);
}
}

View File

@ -3,44 +3,40 @@ package org.owasp.webgoat.container.session;
import java.io.Serializable;
/**
* <p>LabelDebugger class.</p>
* LabelDebugger class.
*
* @author dm
* @version $Id: $Id
*/
public class LabelDebugger implements Serializable {
private boolean enabled = false;
private boolean enabled = false;
/**
* <p>isEnabled.</p>
*
* @return a boolean.
*/
public boolean isEnabled() {
return enabled;
}
/**
* isEnabled.
*
* @return a boolean.
*/
public boolean isEnabled() {
return enabled;
}
/**
* <p>Enables label debugging</p>
*/
public void enable() {
this.enabled = true;
}
/** Enables label debugging */
public void enable() {
this.enabled = true;
}
/**
* <p>Disables label debugging</p>
*/
public void disable() {
this.enabled = false;
}
/**
* <p>Sets the status to enabled</p>
* @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/** Disables label debugging */
public void disable() {
this.enabled = false;
}
/**
* Sets the status to enabled
*
* @param enabled {@link org.owasp.webgoat.container.session.LabelDebugger} object
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View File

@ -2,35 +2,31 @@ package org.owasp.webgoat.container.session;
import java.util.HashMap;
/**
* Created by jason on 1/4/17.
*/
/** Created by jason on 1/4/17. */
public class UserSessionData {
private HashMap<String,Object> userSessionData = new HashMap<>();
private HashMap<String, Object> userSessionData = new HashMap<>();
public UserSessionData() {
public UserSessionData() {}
public UserSessionData(String key, String value) {
setValue(key, value);
}
// GETTERS & SETTERS
public Object getValue(String key) {
if (!userSessionData.containsKey(key)) {
return null;
}
// else
return userSessionData.get(key);
}
public UserSessionData(String key, String value) {
setValue(key,value);
public void setValue(String key, Object value) {
if (userSessionData.containsKey(key)) {
userSessionData.replace(key, value);
} else {
userSessionData.put(key, value);
}
//GETTERS & SETTERS
public Object getValue(String key) {
if (!userSessionData.containsKey(key)) {
return null;
}
// else
return userSessionData.get(key);
}
public void setValue(String key, Object value) {
if (userSessionData.containsKey(key)) {
userSessionData.replace(key,value);
} else {
userSessionData.put(key,value);
}
}
}
}

View File

@ -1,34 +1,36 @@
package org.owasp.webgoat.container.session;
import java.io.Serializable;
import org.owasp.webgoat.container.lessons.Lesson;
import org.owasp.webgoat.container.users.WebGoatUser;
import org.springframework.security.core.context.SecurityContextHolder;
import java.io.Serializable;
/**
* *************************************************************************************************
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later
* version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
* <p>
* You should have received a copy of the GNU General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>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 - 2014 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 Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
@ -37,51 +39,52 @@ import java.io.Serializable;
*/
public class WebSession implements Serializable {
private static final long serialVersionUID = -4270066103101711560L;
private final WebGoatUser currentUser;
private transient Lesson currentLesson;
private boolean securityEnabled;
private static final long serialVersionUID = -4270066103101711560L;
private final WebGoatUser currentUser;
private transient Lesson currentLesson;
private boolean securityEnabled;
public WebSession() {
this.currentUser = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
public WebSession() {
this.currentUser =
(WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
/**
* <p> Setter for the field <code>currentScreen</code>. </p>
*
* @param lesson current lesson
*/
public void setCurrentLesson(Lesson lesson) {
this.currentLesson = lesson;
}
/**
* Setter for the field <code>currentScreen</code>.
*
* @param lesson current lesson
*/
public void setCurrentLesson(Lesson lesson) {
this.currentLesson = lesson;
}
/**
* <p> getCurrentLesson. </p>
*
* @return a {@link Lesson} object.
*/
public Lesson getCurrentLesson() {
return this.currentLesson;
}
/**
* getCurrentLesson.
*
* @return a {@link Lesson} object.
*/
public Lesson getCurrentLesson() {
return this.currentLesson;
}
/**
* Gets the userName attribute of the WebSession object
*
* @return The userName value
*/
public String getUserName() {
return currentUser.getUsername();
}
/**
* Gets the userName attribute of the WebSession object
*
* @return The userName value
*/
public String getUserName() {
return currentUser.getUsername();
}
public WebGoatUser getUser() {
return currentUser;
}
public WebGoatUser getUser() {
return currentUser;
}
public void toggleSecurity() {
this.securityEnabled = !this.securityEnabled;
}
public void toggleSecurity() {
this.securityEnabled = !this.securityEnabled;
}
public boolean isSecurityEnabled() {
return securityEnabled;
}
public boolean isSecurityEnabled() {
return securityEnabled;
}
}

View File

@ -1,40 +1,38 @@
package org.owasp.webgoat.container.users;
import lombok.Getter;
import org.owasp.webgoat.container.lessons.Lesson;
import org.owasp.webgoat.container.lessons.Assignment;
import javax.persistence.*;
import java.util.*;
import java.util.stream.Collectors;
import javax.persistence.*;
import lombok.Getter;
import org.owasp.webgoat.container.lessons.Assignment;
import org.owasp.webgoat.container.lessons.Lesson;
/**
* ************************************************************************************************
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>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
@ -43,72 +41,69 @@ import java.util.stream.Collectors;
@Entity
public class LessonTracker {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Getter
private String lessonName;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Assignment> solvedAssignments = new HashSet<>();
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Assignment> allAssignments = new HashSet<>();
@Getter
private int numberOfAttempts = 0;
@Version
private Integer version;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private LessonTracker() {
//JPA
}
@Getter private String lessonName;
public LessonTracker(Lesson lesson) {
lessonName = lesson.getId();
allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments());
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Assignment> solvedAssignments = new HashSet<>();
public Optional<Assignment> getAssignment(String name) {
return allAssignments.stream().filter(a -> a.getName().equals(name)).findFirst();
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private final Set<Assignment> allAssignments = new HashSet<>();
/**
* Mark an assignment as solved
*
* @param solvedAssignment the assignment which the user solved
*/
public void assignmentSolved(String solvedAssignment) {
getAssignment(solvedAssignment).ifPresent(solvedAssignments::add);
}
@Getter private int numberOfAttempts = 0;
@Version private Integer version;
/**
* @return did they user solved all solvedAssignments for the lesson?
*/
public boolean isLessonSolved() {
return allAssignments.size() == solvedAssignments.size();
}
private LessonTracker() {
// JPA
}
/**
* Increase the number attempts to solve the lesson
*/
public void incrementAttempts() {
numberOfAttempts++;
}
public LessonTracker(Lesson lesson) {
lessonName = lesson.getId();
allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments());
}
/**
* Reset the tracker. We do not reset the number of attempts here!
*/
void reset() {
solvedAssignments.clear();
}
public Optional<Assignment> getAssignment(String name) {
return allAssignments.stream().filter(a -> a.getName().equals(name)).findFirst();
}
/**
* @return list containing all the assignments solved or not
*/
public Map<Assignment, Boolean> getLessonOverview() {
List<Assignment> notSolved = allAssignments.stream()
.filter(i -> !solvedAssignments.contains(i))
.toList();
Map<Assignment, Boolean> overview = notSolved.stream().collect(Collectors.toMap(a -> a, b -> false));
overview.putAll(solvedAssignments.stream().collect(Collectors.toMap(a -> a, b -> true)));
return overview;
}
/**
* Mark an assignment as solved
*
* @param solvedAssignment the assignment which the user solved
*/
public void assignmentSolved(String solvedAssignment) {
getAssignment(solvedAssignment).ifPresent(solvedAssignments::add);
}
/**
* @return did they user solved all solvedAssignments for the lesson?
*/
public boolean isLessonSolved() {
return allAssignments.size() == solvedAssignments.size();
}
/** Increase the number attempts to solve the lesson */
public void incrementAttempts() {
numberOfAttempts++;
}
/** Reset the tracker. We do not reset the number of attempts here! */
void reset() {
solvedAssignments.clear();
}
/**
* @return list containing all the assignments solved or not
*/
public Map<Assignment, Boolean> getLessonOverview() {
List<Assignment> notSolved =
allAssignments.stream().filter(i -> !solvedAssignments.contains(i)).toList();
Map<Assignment, Boolean> overview =
notSolved.stream().collect(Collectors.toMap(a -> a, b -> false));
overview.putAll(solvedAssignments.stream().collect(Collectors.toMap(a -> a, b -> true)));
return overview;
}
}

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.container.users;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
@ -9,10 +12,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
/**
* @author nbaars
* @since 3/19/17.
@ -22,25 +21,29 @@ import javax.validation.Valid;
@Slf4j
public class RegistrationController {
private UserValidator userValidator;
private UserService userService;
private AuthenticationManager authenticationManager;
private UserValidator userValidator;
private UserService userService;
private AuthenticationManager authenticationManager;
@GetMapping("/registration")
public String showForm(UserForm userForm) {
return "registration";
@GetMapping("/registration")
public String showForm(UserForm userForm) {
return "registration";
}
@PostMapping("/register.mvc")
public String registration(
@ModelAttribute("userForm") @Valid UserForm userForm,
BindingResult bindingResult,
HttpServletRequest request)
throws ServletException {
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "registration";
}
userService.addUser(userForm.getUsername(), userForm.getPassword());
request.login(userForm.getUsername(), userForm.getPassword());
@PostMapping("/register.mvc")
public String registration(@ModelAttribute("userForm") @Valid UserForm userForm, BindingResult bindingResult, HttpServletRequest request) throws ServletException {
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "registration";
}
userService.addUser(userForm.getUsername(), userForm.getPassword());
request.login(userForm.getUsername(), userForm.getPassword());
return "redirect:/attack";
}
return "redirect:/attack";
}
}

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.container.users;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.owasp.webgoat.container.i18n.PluginMessages;
@ -8,10 +11,6 @@ import org.owasp.webgoat.container.session.Course;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* Temp endpoint just for the CTF.
*
@ -22,52 +21,63 @@ import java.util.Optional;
@AllArgsConstructor
public class Scoreboard {
private final UserTrackerRepository userTrackerRepository;
private final UserRepository userRepository;
private final Course course;
private final PluginMessages pluginMessages;
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;
}
@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 = new ArrayList<>();
for (WebGoatUser user : allUsers) {
if (user.getUsername().startsWith("csrf-")) {
//the csrf- assignment specific users do not need to be in the overview
continue;
}
UserTracker userTracker = userTrackerRepository.findByUser(user.getUsername());
rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker)));
}
/* sort on number of captured flags to present an ordered ranking */
rankings.sort((o1, o2) -> o2.getFlagsCaptured().size() - o1.getFlagsCaptured().size());
return rankings;
@GetMapping("/scoreboard-data")
public List<Ranking> getRankings() {
List<WebGoatUser> allUsers = userRepository.findAll();
List<Ranking> rankings = new ArrayList<>();
for (WebGoatUser user : allUsers) {
if (user.getUsername().startsWith("csrf-")) {
// the csrf- assignment specific users do not need to be in the overview
continue;
}
UserTracker userTracker = userTrackerRepository.findByUser(user.getUsername());
rankings.add(new Ranking(user.getUsername(), challengesSolved(userTracker)));
}
/* sort on number of captured flags to present an ordered ranking */
rankings.sort((o1, o2) -> o2.getFlagsCaptured().size() - o1.getFlagsCaptured().size());
return rankings;
}
private List<String> challengesSolved(UserTracker userTracker) {
List<String> challenges = List.of("Challenge1", "Challenge2", "Challenge3", "Challenge4", "Challenge5", "Challenge6", "Challenge7", "Challenge8", "Challenge9");
return challenges.stream()
.map(userTracker::getLessonTracker)
.flatMap(Optional::stream)
.filter(LessonTracker::isLessonSolved)
.map(LessonTracker::getLessonName)
.map(this::toLessonTitle)
.toList();
}
private List<String> challengesSolved(UserTracker userTracker) {
List<String> challenges =
List.of(
"Challenge1",
"Challenge2",
"Challenge3",
"Challenge4",
"Challenge5",
"Challenge6",
"Challenge7",
"Challenge8",
"Challenge9");
return challenges.stream()
.map(userTracker::getLessonTracker)
.flatMap(Optional::stream)
.filter(LessonTracker::isLessonSolved)
.map(LessonTracker::getLessonName)
.map(this::toLessonTitle)
.toList();
}
private String toLessonTitle(String id) {
String titleKey = course.getLessons().stream()
.filter(l -> l.getId().equals(id))
.findFirst()
.map(Lesson::getTitle)
.orElse("No title");
return pluginMessages.getMessage(titleKey, titleKey);
}
private String toLessonTitle(String id) {
String titleKey =
course.getLessons().stream()
.filter(l -> l.getId().equals(id))
.findFirst()
.map(Lesson::getTitle)
.orElse("No title");
return pluginMessages.getMessage(titleKey, titleKey);
}
}

View File

@ -1,11 +1,10 @@
package org.owasp.webgoat.container.users;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
/**
* @author nbaars
@ -15,16 +14,18 @@ import javax.validation.constraints.Size;
@Setter
public class UserForm {
@NotNull
@Size(min = 6, max = 45)
@Pattern(regexp = "[a-z0-9-]*", message = "can only contain lowercase letters, digits, and -")
private String username;
@NotNull
@Size(min = 6, max = 10)
private String password;
@NotNull
@Size(min = 6, max = 10)
private String matchingPassword;
@NotNull
private String agree;
@NotNull
@Size(min = 6, max = 45)
@Pattern(regexp = "[a-z0-9-]*", message = "can only contain lowercase letters, digits, and -")
private String username;
@NotNull
@Size(min = 6, max = 10)
private String password;
@NotNull
@Size(min = 6, max = 10)
private String matchingPassword;
@NotNull private String agree;
}

View File

@ -1,8 +1,7 @@
package org.owasp.webgoat.container.users;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author nbaars
@ -10,10 +9,9 @@ import java.util.List;
*/
public interface UserRepository extends JpaRepository<WebGoatUser, String> {
WebGoatUser findByUsername(String username);
WebGoatUser findByUsername(String username);
List<WebGoatUser> findAll();
boolean existsByUsername(String username);
List<WebGoatUser> findAll();
boolean existsByUsername(String username);
}

View File

@ -1,5 +1,7 @@
package org.owasp.webgoat.container.users;
import java.util.List;
import java.util.function.Function;
import lombok.AllArgsConstructor;
import org.flywaydb.core.Flyway;
import org.owasp.webgoat.container.lessons.Initializeable;
@ -8,9 +10,6 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.function.Function;
/**
* @author nbaars
* @since 3/19/17.
@ -19,42 +18,42 @@ import java.util.function.Function;
@AllArgsConstructor
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final UserTrackerRepository userTrackerRepository;
private final JdbcTemplate jdbcTemplate;
private final Function<String, Flyway> flywayLessons;
private final List<Initializeable> lessonInitializables;
private final UserRepository userRepository;
private final UserTrackerRepository userTrackerRepository;
private final JdbcTemplate jdbcTemplate;
private final Function<String, Flyway> flywayLessons;
private final List<Initializeable> lessonInitializables;
@Override
public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException {
WebGoatUser webGoatUser = userRepository.findByUsername(username);
if (webGoatUser == null) {
throw new UsernameNotFoundException("User not found");
} else {
webGoatUser.createUser();
lessonInitializables.forEach(l -> l.initialize(webGoatUser));
}
return webGoatUser;
@Override
public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException {
WebGoatUser webGoatUser = userRepository.findByUsername(username);
if (webGoatUser == null) {
throw new UsernameNotFoundException("User not found");
} else {
webGoatUser.createUser();
lessonInitializables.forEach(l -> l.initialize(webGoatUser));
}
return webGoatUser;
}
public void addUser(String username, String password) {
//get user if there exists one by the name
var userAlreadyExists = userRepository.existsByUsername(username);
var webGoatUser = userRepository.save(new WebGoatUser(username, password));
public void addUser(String username, String password) {
// get user if there exists one by the name
var userAlreadyExists = userRepository.existsByUsername(username);
var webGoatUser = userRepository.save(new WebGoatUser(username, password));
if (!userAlreadyExists) {
userTrackerRepository.save(new UserTracker(username)); //if user previously existed it will not get another tracker
createLessonsForUser(webGoatUser);
}
if (!userAlreadyExists) {
userTrackerRepository.save(
new UserTracker(username)); // if user previously existed it will not get another tracker
createLessonsForUser(webGoatUser);
}
}
private void createLessonsForUser(WebGoatUser webGoatUser) {
jdbcTemplate.execute("CREATE SCHEMA \"" + webGoatUser.getUsername() + "\" authorization dba");
flywayLessons.apply(webGoatUser.getUsername()).migrate();
}
public List<WebGoatUser> getAllUsers() {
return userRepository.findAll();
}
private void createLessonsForUser(WebGoatUser webGoatUser) {
jdbcTemplate.execute("CREATE SCHEMA \"" + webGoatUser.getUsername() + "\" authorization dba");
flywayLessons.apply(webGoatUser.getUsername()).migrate();
}
public List<WebGoatUser> getAllUsers() {
return userRepository.findAll();
}
}

View File

@ -15,7 +15,6 @@ import org.springframework.data.annotation.Id;
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class UserSession {
private WebGoatUser webGoatUser;
@Id
private String sessionId;
private WebGoatUser webGoatUser;
@Id private String sessionId;
}

View File

@ -1,43 +1,41 @@
package org.owasp.webgoat.container.users;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.lessons.Lesson;
import org.owasp.webgoat.container.lessons.Assignment;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.*;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.lessons.Assignment;
import org.owasp.webgoat.container.lessons.Lesson;
/**
* ************************************************************************************************
*
* <p>
* <p>
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
*
* <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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>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
@ -47,80 +45,83 @@ import java.util.stream.Collectors;
@Entity
public class UserTracker {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "username")
private String user;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<LessonTracker> lessonTrackers = new HashSet<>();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private UserTracker() {}
@Column(name = "username")
private String user;
public UserTracker(final String user) {
this.user = user;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<LessonTracker> lessonTrackers = new HashSet<>();
private UserTracker() {}
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(Lesson 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();
}
}
/**
* 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(Lesson 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();
}
/**
* 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(Lesson lesson, String assignmentName) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
lessonTracker.assignmentSolved(assignmentName);
}
public void assignmentSolved(Lesson lesson, String assignmentName) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
lessonTracker.assignmentSolved(assignmentName);
}
public void assignmentFailed(Lesson lesson) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
}
public void assignmentFailed(Lesson lesson) {
LessonTracker lessonTracker = getLessonTracker(lesson);
lessonTracker.incrementAttempts();
}
public void reset(Lesson al) {
LessonTracker lessonTracker = getLessonTracker(al);
lessonTracker.reset();
}
public void reset(Lesson 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 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;
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;
}
}

View File

@ -8,6 +8,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
*/
public interface UserTrackerRepository extends JpaRepository<UserTracker, String> {
UserTracker findByUser(String user);
UserTracker findByUser(String user);
}

View File

@ -13,23 +13,23 @@ import org.springframework.validation.Validator;
@AllArgsConstructor
public class UserValidator implements Validator {
private final UserRepository userRepository;
private final UserRepository userRepository;
@Override
public boolean supports(Class<?> clazz) {
return UserForm.class.equals(clazz);
@Override
public boolean supports(Class<?> clazz) {
return UserForm.class.equals(clazz);
}
@Override
public void validate(Object o, Errors errors) {
UserForm userForm = (UserForm) o;
if (userRepository.findByUsername(userForm.getUsername()) != null) {
errors.rejectValue("username", "username.duplicate");
}
@Override
public void validate(Object o, Errors errors) {
UserForm userForm = (UserForm) o;
if (userRepository.findByUsername(userForm.getUsername()) != null) {
errors.rejectValue("username", "username.duplicate");
}
if (!userForm.getMatchingPassword().equals(userForm.getPassword())) {
errors.rejectValue("matchingPassword", "password.diff");
}
if (!userForm.getMatchingPassword().equals(userForm.getPassword())) {
errors.rejectValue("matchingPassword", "password.diff");
}
}
}

View File

@ -1,17 +1,16 @@
package org.owasp.webgoat.container.users;
import java.util.Collection;
import java.util.Collections;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
import lombok.Getter;
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;
/**
* @author nbaars
* @since 3/19/17.
@ -20,79 +19,72 @@ import java.util.Collections;
@Entity
public class WebGoatUser implements UserDetails {
public static final String ROLE_USER = "WEBGOAT_USER";
public static final String ROLE_ADMIN = "WEBGOAT_ADMIN";
public static final String ROLE_USER = "WEBGOAT_USER";
public static final String ROLE_ADMIN = "WEBGOAT_ADMIN";
@Id
private String username;
private String password;
private String role = ROLE_USER;
@Transient
private User user;
@Id private String username;
private String password;
private String role = ROLE_USER;
@Transient private User user;
protected WebGoatUser() {
}
protected WebGoatUser() {}
public WebGoatUser(String username, String password) {
this(username, password, ROLE_USER);
}
public WebGoatUser(String username, String password) {
this(username, password, ROLE_USER);
}
public WebGoatUser(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
createUser();
}
public WebGoatUser(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
createUser();
}
public void createUser() {
this.user = new User(username, password, getAuthorities());
}
public void createUser() {
this.user = new User(username, password, getAuthorities());
}
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singleton(new SimpleGrantedAuthority(getRole()));
}
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singleton(new SimpleGrantedAuthority(getRole()));
}
public String getRole() {
return this.role;
}
public String getRole() {
return this.role;
}
public String getUsername() {
return this.username;
}
public String getUsername() {
return this.username;
}
public String getPassword() {
return this.password;
}
public String getPassword() {
return this.password;
}
@Override
public boolean isAccountNonExpired() {
return this.user.isAccountNonExpired();
}
@Override
public boolean isAccountNonExpired() {
return this.user.isAccountNonExpired();
}
@Override
public boolean isAccountNonLocked() {
return this.user.isAccountNonLocked();
}
@Override
public boolean isAccountNonLocked() {
return this.user.isAccountNonLocked();
}
@Override
public boolean isCredentialsNonExpired() {
return this.user.isCredentialsNonExpired();
}
@Override
public boolean isCredentialsNonExpired() {
return this.user.isCredentialsNonExpired();
}
@Override
public boolean isEnabled() {
return this.user.isEnabled();
}
@Override
public boolean isEnabled() {
return this.user.isEnabled();
}
public boolean equals(Object obj) {
return obj instanceof WebGoatUser webGoatUser && this.user.equals(webGoatUser.user);
}
public int hashCode() {
return user.hashCode();
}
public boolean equals(Object obj) {
return obj instanceof WebGoatUser webGoatUser && this.user.equals(webGoatUser.user);
}
public int hashCode() {
return user.hashCode();
}
}

View File

@ -25,63 +25,72 @@ package org.owasp.webgoat.lessons.authbypass;
import java.util.HashMap;
import java.util.Map;
/**
* Created by appsec on 7/18/17.
*/
/** Created by appsec on 7/18/17. */
public class AccountVerificationHelper {
//simulating database storage of verification credentials
private static final Integer verifyUserId = 1223445;
private static final Map<String, String> userSecQuestions = new HashMap<>();
// simulating database storage of verification credentials
private static final Integer verifyUserId = 1223445;
private static final Map<String, String> userSecQuestions = new HashMap<>();
static {
userSecQuestions.put("secQuestion0", "Dr. Watson");
userSecQuestions.put("secQuestion1", "Baker Street");
static {
userSecQuestions.put("secQuestion0", "Dr. Watson");
userSecQuestions.put("secQuestion1", "Baker Street");
}
private static final Map<Integer, Map> secQuestionStore = new HashMap<>();
static {
secQuestionStore.put(verifyUserId, userSecQuestions);
}
// end 'data store set up'
// this is to aid feedback in the attack process and is not intended to be part of the
// 'vulnerable' code
public boolean didUserLikelylCheat(HashMap<String, String> submittedAnswers) {
boolean likely = false;
if (submittedAnswers.size() == secQuestionStore.get(verifyUserId).size()) {
likely = true;
}
private static final Map<Integer, Map> secQuestionStore = new HashMap<>();
static {
secQuestionStore.put(verifyUserId, userSecQuestions);
if ((submittedAnswers.containsKey("secQuestion0")
&& submittedAnswers
.get("secQuestion0")
.equals(secQuestionStore.get(verifyUserId).get("secQuestion0")))
&& (submittedAnswers.containsKey("secQuestion1")
&& submittedAnswers
.get("secQuestion1")
.equals(secQuestionStore.get(verifyUserId).get("secQuestion1")))) {
likely = true;
} else {
likely = false;
}
// end 'data store set up'
// this is to aid feedback in the attack process and is not intended to be part of the 'vulnerable' code
public boolean didUserLikelylCheat(HashMap<String, String> submittedAnswers) {
boolean likely = false;
if (submittedAnswers.size() == secQuestionStore.get(verifyUserId).size()) {
likely = true;
}
if ((submittedAnswers.containsKey("secQuestion0") && submittedAnswers.get("secQuestion0").equals(secQuestionStore.get(verifyUserId).get("secQuestion0")))
&& (submittedAnswers.containsKey("secQuestion1") && submittedAnswers.get("secQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1")))) {
likely = true;
} else {
likely = false;
}
return likely;
return likely;
}
// end of cheating check ... the method below is the one of real interest. Can you find the flaw?
public boolean verifyAccount(Integer userId, HashMap<String, String> submittedQuestions) {
// short circuit if no questions are submitted
if (submittedQuestions.entrySet().size() != secQuestionStore.get(verifyUserId).size()) {
return false;
}
//end of cheating check ... the method below is the one of real interest. Can you find the flaw?
public boolean verifyAccount(Integer userId, HashMap<String, String> submittedQuestions) {
//short circuit if no questions are submitted
if (submittedQuestions.entrySet().size() != secQuestionStore.get(verifyUserId).size()) {
return false;
}
if (submittedQuestions.containsKey("secQuestion0") && !submittedQuestions.get("secQuestion0").equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) {
return false;
}
if (submittedQuestions.containsKey("secQuestion1") && !submittedQuestions.get("secQuestion1").equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) {
return false;
}
// else
return true;
if (submittedQuestions.containsKey("secQuestion0")
&& !submittedQuestions
.get("secQuestion0")
.equals(secQuestionStore.get(verifyUserId).get("secQuestion0"))) {
return false;
}
if (submittedQuestions.containsKey("secQuestion1")
&& !submittedQuestions
.get("secQuestion1")
.equals(secQuestionStore.get(verifyUserId).get("secQuestion1"))) {
return false;
}
// else
return true;
}
}

View File

@ -29,13 +29,13 @@ import org.springframework.stereotype.Component;
@Component
public class AuthBypass extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.A7;
}
@Override
public Category getDefaultCategory() {
return Category.A7;
}
@Override
public String getTitle() {
return "auth-bypass.title";
}
@Override
public String getTitle() {
return "auth-bypass.title";
}
}

View File

@ -22,6 +22,13 @@
package org.owasp.webgoat.lessons.authbypass;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -33,63 +40,54 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by jason on 1/5/17.
*/
/** Created by jason on 1/5/17. */
@RestController
@AssignmentHints({"auth-bypass.hints.verify.1", "auth-bypass.hints.verify.2", "auth-bypass.hints.verify.3", "auth-bypass.hints.verify.4"})
@AssignmentHints({
"auth-bypass.hints.verify.1",
"auth-bypass.hints.verify.2",
"auth-bypass.hints.verify.3",
"auth-bypass.hints.verify.4"
})
public class VerifyAccount extends AssignmentEndpoint {
@Autowired
private WebSession webSession;
@Autowired private WebSession webSession;
@Autowired
UserSessionData userSessionData;
@PostMapping(path = "/auth-bypass/verify-account", produces = {"application/json"})
@ResponseBody
public AttackResult completed(@RequestParam String userId, @RequestParam String verifyMethod, HttpServletRequest req) throws ServletException, IOException {
AccountVerificationHelper verificationHelper = new AccountVerificationHelper();
Map<String, String> submittedAnswers = parseSecQuestions(req);
if (verificationHelper.didUserLikelylCheat((HashMap) submittedAnswers)) {
return failed(this)
.feedback("verify-account.cheated")
.output("Yes, you guessed correctly, but see the feedback message")
.build();
}
// else
if (verificationHelper.verifyAccount(Integer.valueOf(userId), (HashMap) submittedAnswers)) {
userSessionData.setValue("account-verified-id", userId);
return success(this)
.feedback("verify-account.success")
.build();
} else {
return failed(this)
.feedback("verify-account.failed")
.build();
}
@Autowired UserSessionData userSessionData;
@PostMapping(
path = "/auth-bypass/verify-account",
produces = {"application/json"})
@ResponseBody
public AttackResult completed(
@RequestParam String userId, @RequestParam String verifyMethod, HttpServletRequest req)
throws ServletException, IOException {
AccountVerificationHelper verificationHelper = new AccountVerificationHelper();
Map<String, String> submittedAnswers = parseSecQuestions(req);
if (verificationHelper.didUserLikelylCheat((HashMap) submittedAnswers)) {
return failed(this)
.feedback("verify-account.cheated")
.output("Yes, you guessed correctly, but see the feedback message")
.build();
}
private HashMap<String, String> parseSecQuestions(HttpServletRequest req) {
Map<String, String> userAnswers = new HashMap<>();
List<String> paramNames = Collections.list(req.getParameterNames());
for (String paramName : paramNames) {
//String paramName = req.getParameterNames().nextElement();
if (paramName.contains("secQuestion")) {
userAnswers.put(paramName, req.getParameter(paramName));
}
}
return (HashMap) userAnswers;
// else
if (verificationHelper.verifyAccount(Integer.valueOf(userId), (HashMap) submittedAnswers)) {
userSessionData.setValue("account-verified-id", userId);
return success(this).feedback("verify-account.success").build();
} else {
return failed(this).feedback("verify-account.failed").build();
}
}
private HashMap<String, String> parseSecQuestions(HttpServletRequest req) {
Map<String, String> userAnswers = new HashMap<>();
List<String> paramNames = Collections.list(req.getParameterNames());
for (String paramName : paramNames) {
// String paramName = req.getParameterNames().nextElement();
if (paramName.contains("secQuestion")) {
userAnswers.put(paramName, req.getParameter(paramName));
}
}
return (HashMap) userAnswers;
}
}

View File

@ -28,13 +28,13 @@ import org.springframework.stereotype.Component;
@Component
public class BypassRestrictions extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.CLIENT_SIDE;
}
@Override
public Category getDefaultCategory() {
return Category.CLIENT_SIDE;
}
@Override
public String getTitle() {
return "bypass-restrictions.title";
}
@Override
public String getTitle() {
return "bypass-restrictions.title";
}
}

View File

@ -32,24 +32,29 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class BypassRestrictionsFieldRestrictions extends AssignmentEndpoint {
@PostMapping("/BypassRestrictions/FieldRestrictions")
@ResponseBody
public AttackResult completed(@RequestParam String select, @RequestParam String radio, @RequestParam String checkbox, @RequestParam String shortInput, @RequestParam String readOnlyInput) {
if (select.equals("option1") || select.equals("option2")) {
return failed(this).build();
}
if (radio.equals("option1") || radio.equals("option2")) {
return failed(this).build();
}
if (checkbox.equals("on") || checkbox.equals("off")) {
return failed(this).build();
}
if (shortInput.length() <= 5) {
return failed(this).build();
}
if ("change".equals(readOnlyInput)) {
return failed(this).build();
}
return success(this).build();
@PostMapping("/BypassRestrictions/FieldRestrictions")
@ResponseBody
public AttackResult completed(
@RequestParam String select,
@RequestParam String radio,
@RequestParam String checkbox,
@RequestParam String shortInput,
@RequestParam String readOnlyInput) {
if (select.equals("option1") || select.equals("option2")) {
return failed(this).build();
}
if (radio.equals("option1") || radio.equals("option2")) {
return failed(this).build();
}
if (checkbox.equals("on") || checkbox.equals("off")) {
return failed(this).build();
}
if (shortInput.length() <= 5) {
return failed(this).build();
}
if ("change".equals(readOnlyInput)) {
return failed(this).build();
}
return success(this).build();
}
}

View File

@ -32,40 +32,48 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class BypassRestrictionsFrontendValidation extends AssignmentEndpoint {
@PostMapping("/BypassRestrictions/frontendValidation")
@ResponseBody
public AttackResult completed(@RequestParam String field1, @RequestParam String field2, @RequestParam String field3, @RequestParam String field4, @RequestParam String field5, @RequestParam String field6, @RequestParam String field7, @RequestParam Integer error) {
final String regex1 = "^[a-z]{3}$";
final String regex2 = "^[0-9]{3}$";
final String regex3 = "^[a-zA-Z0-9 ]*$";
final String regex4 = "^(one|two|three|four|five|six|seven|eight|nine)$";
final String regex5 = "^\\d{5}$";
final String regex6 = "^\\d{5}(-\\d{4})?$";
final String regex7 = "^[2-9]\\d{2}-?\\d{3}-?\\d{4}$";
if (error > 0) {
return failed(this).build();
}
if (field1.matches(regex1)) {
return failed(this).build();
}
if (field2.matches(regex2)) {
return failed(this).build();
}
if (field3.matches(regex3)) {
return failed(this).build();
}
if (field4.matches(regex4)) {
return failed(this).build();
}
if (field5.matches(regex5)) {
return failed(this).build();
}
if (field6.matches(regex6)) {
return failed(this).build();
}
if (field7.matches(regex7)) {
return failed(this).build();
}
return success(this).build();
@PostMapping("/BypassRestrictions/frontendValidation")
@ResponseBody
public AttackResult completed(
@RequestParam String field1,
@RequestParam String field2,
@RequestParam String field3,
@RequestParam String field4,
@RequestParam String field5,
@RequestParam String field6,
@RequestParam String field7,
@RequestParam Integer error) {
final String regex1 = "^[a-z]{3}$";
final String regex2 = "^[0-9]{3}$";
final String regex3 = "^[a-zA-Z0-9 ]*$";
final String regex4 = "^(one|two|three|four|five|six|seven|eight|nine)$";
final String regex5 = "^\\d{5}$";
final String regex6 = "^\\d{5}(-\\d{4})?$";
final String regex7 = "^[2-9]\\d{2}-?\\d{3}-?\\d{4}$";
if (error > 0) {
return failed(this).build();
}
if (field1.matches(regex1)) {
return failed(this).build();
}
if (field2.matches(regex2)) {
return failed(this).build();
}
if (field3.matches(regex3)) {
return failed(this).build();
}
if (field4.matches(regex4)) {
return failed(this).build();
}
if (field5.matches(regex5)) {
return failed(this).build();
}
if (field6.matches(regex6)) {
return failed(this).build();
}
if (field7.matches(regex7)) {
return failed(this).build();
}
return success(this).build();
}
}

View File

@ -9,13 +9,13 @@ import org.owasp.webgoat.container.lessons.Lesson;
*/
public class ChallengeIntro extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public String getTitle() {
return "challenge0.title";
}
@Override
public String getTitle() {
return "challenge0.title";
}
}

View File

@ -22,11 +22,10 @@
package org.owasp.webgoat.lessons.challenges;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Data;
/**
* @author nbaars
@ -36,9 +35,9 @@ import java.time.LocalDateTime;
@Data
public class Email implements Serializable {
private LocalDateTime time;
private String contents;
private String sender;
private String title;
private String recipient;
private LocalDateTime time;
private String contents;
private String sender;
private String title;
private String recipient;
}

View File

@ -22,6 +22,11 @@
package org.owasp.webgoat.lessons.challenges;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.IntStream;
import javax.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -37,12 +42,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.IntStream;
/**
* @author nbaars
* @since 3/23/17.
@ -50,39 +49,41 @@ import java.util.stream.IntStream;
@RestController
public class Flag extends AssignmentEndpoint {
public static final Map<Integer, String> FLAGS = new HashMap<>();
@Autowired
private UserTrackerRepository userTrackerRepository;
@Autowired
private WebSession webSession;
public static final Map<Integer, String> FLAGS = new HashMap<>();
@Autowired private UserTrackerRepository userTrackerRepository;
@Autowired private WebSession webSession;
@AllArgsConstructor
private class FlagPosted {
@Getter
private boolean lessonCompleted;
}
@AllArgsConstructor
private class FlagPosted {
@Getter private boolean lessonCompleted;
}
@PostConstruct
public void initFlags() {
IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString()));
}
@PostConstruct
public void initFlags() {
IntStream.range(1, 10).forEach(i -> FLAGS.put(i, UUID.randomUUID().toString()));
}
@RequestMapping(path = "/challenge/flag", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public AttackResult postFlag(@RequestParam String flag) {
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
String currentChallenge = webSession.getCurrentLesson().getName();
int challengeNumber = Integer.valueOf(currentChallenge.substring(currentChallenge.length() - 1, currentChallenge.length()));
String expectedFlag = FLAGS.get(challengeNumber);
final AttackResult attackResult;
if (expectedFlag.equals(flag)) {
userTracker.assignmentSolved(webSession.getCurrentLesson(), "Assignment" + challengeNumber);
attackResult = success(this).feedback("challenge.flag.correct").build();
} else {
userTracker.assignmentFailed(webSession.getCurrentLesson());
attackResult = failed(this).feedback("challenge.flag.incorrect").build();
}
userTrackerRepository.save(userTracker);
return attackResult;
@RequestMapping(
path = "/challenge/flag",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public AttackResult postFlag(@RequestParam String flag) {
UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName());
String currentChallenge = webSession.getCurrentLesson().getName();
int challengeNumber =
Integer.valueOf(
currentChallenge.substring(currentChallenge.length() - 1, currentChallenge.length()));
String expectedFlag = FLAGS.get(challengeNumber);
final AttackResult attackResult;
if (expectedFlag.equals(flag)) {
userTracker.assignmentSolved(webSession.getCurrentLesson(), "Assignment" + challengeNumber);
attackResult = success(this).feedback("challenge.flag.correct").build();
} else {
userTracker.assignmentFailed(webSession.getCurrentLesson());
attackResult = failed(this).feedback("challenge.flag.incorrect").build();
}
userTrackerRepository.save(userTracker);
return attackResult;
}
}

View File

@ -30,8 +30,8 @@ package org.owasp.webgoat.lessons.challenges;
*/
public interface SolutionConstants {
//TODO should be random generated when starting the server
String PASSWORD = "!!webgoat_admin_1234!!";
String PASSWORD_TOM = "thisisasecretfortomonly";
String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2";
// TODO should be random generated when starting the server
String PASSWORD = "!!webgoat_admin_1234!!";
String PASSWORD_TOM = "thisisasecretfortomonly";
String ADMIN_PASSWORD_LINK = "375afe1104f4a487a73823c50a9292a2";
}

View File

@ -1,5 +1,8 @@
package org.owasp.webgoat.lessons.challenges.challenge1;
import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD;
import javax.servlet.http.HttpServletRequest;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.lessons.challenges.Flag;
@ -9,33 +12,30 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD;
/**
* ************************************************************************************************
* 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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* <p>
*
* @author WebGoat
@ -45,20 +45,25 @@ import static org.owasp.webgoat.lessons.challenges.SolutionConstants.PASSWORD;
@RestController
public class Assignment1 extends AssignmentEndpoint {
@PostMapping("/challenge/1")
@ResponseBody
public AttackResult completed(@RequestParam String username, @RequestParam String password, HttpServletRequest request) {
boolean ipAddressKnown = true;
boolean passwordCorrect = "admin".equals(username) && PASSWORD.replace("1234", String.format("%04d",ImageServlet.PINCODE)).equals(password);
if (passwordCorrect && ipAddressKnown) {
return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(1)).build();
} else if (passwordCorrect) {
return failed(this).feedback("ip.address.unknown").build();
}
return failed(this).build();
@PostMapping("/challenge/1")
@ResponseBody
public AttackResult completed(
@RequestParam String username, @RequestParam String password, HttpServletRequest request) {
boolean ipAddressKnown = true;
boolean passwordCorrect =
"admin".equals(username)
&& PASSWORD
.replace("1234", String.format("%04d", ImageServlet.PINCODE))
.equals(password);
if (passwordCorrect && ipAddressKnown) {
return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(1)).build();
} else if (passwordCorrect) {
return failed(this).feedback("ip.address.unknown").build();
}
return failed(this).build();
}
public static boolean containsHeader(HttpServletRequest request) {
return StringUtils.hasText(request.getHeader("X-Forwarded-For"));
}
public static boolean containsHeader(HttpServletRequest request) {
return StringUtils.hasText(request.getHeader("X-Forwarded-For"));
}
}

View File

@ -11,13 +11,13 @@ import org.springframework.stereotype.Component;
@Component
public class Challenge1 extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public String getTitle() {
return "challenge1.title";
}
@Override
public String getTitle() {
return "challenge1.title";
}
}

View File

@ -1,36 +1,41 @@
package org.owasp.webgoat.lessons.challenges.challenge1;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import java.io.IOException;
import java.security.SecureRandom;
import javax.servlet.http.HttpServlet;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
import java.security.SecureRandom;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
@RestController
public class ImageServlet extends HttpServlet {
private static final long serialVersionUID = 9132775506936676850L;
static final public int PINCODE = new SecureRandom().nextInt(10000);
@RequestMapping(method = {GET, POST}, value = "/challenge/logo", produces = MediaType.IMAGE_PNG_VALUE)
@ResponseBody
public byte[] logo() throws IOException {
byte[] in = new ClassPathResource("lessons/challenges/images/webgoat2.png").getInputStream().readAllBytes();
String pincode = String.format("%04d", PINCODE);
in[81216]=(byte) pincode.charAt(0);
in[81217]=(byte) pincode.charAt(1);
in[81218]=(byte) pincode.charAt(2);
in[81219]=(byte) pincode.charAt(3);
private static final long serialVersionUID = 9132775506936676850L;
public static final int PINCODE = new SecureRandom().nextInt(10000);
return in;
}
@RequestMapping(
method = {GET, POST},
value = "/challenge/logo",
produces = MediaType.IMAGE_PNG_VALUE)
@ResponseBody
public byte[] logo() throws IOException {
byte[] in =
new ClassPathResource("lessons/challenges/images/webgoat2.png")
.getInputStream()
.readAllBytes();
String pincode = String.format("%04d", PINCODE);
in[81216] = (byte) pincode.charAt(0);
in[81217] = (byte) pincode.charAt(1);
in[81218] = (byte) pincode.charAt(2);
in[81219] = (byte) pincode.charAt(3);
return in;
}
}

View File

@ -22,6 +22,8 @@
package org.owasp.webgoat.lessons.challenges.challenge5;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.LessonDataSource;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
@ -33,38 +35,41 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@RestController
@Slf4j
public class Assignment5 extends AssignmentEndpoint {
private final LessonDataSource dataSource;
private final LessonDataSource dataSource;
public Assignment5(LessonDataSource dataSource) {
this.dataSource = dataSource;
public Assignment5(LessonDataSource dataSource) {
this.dataSource = dataSource;
}
@PostMapping("/challenge/5")
@ResponseBody
public AttackResult login(
@RequestParam String username_login, @RequestParam String password_login) throws Exception {
if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) {
return failed(this).feedback("required4").build();
}
@PostMapping("/challenge/5")
@ResponseBody
public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception {
if (!StringUtils.hasText(username_login) || !StringUtils.hasText(password_login)) {
return failed(this).feedback("required4").build();
}
if (!"Larry".equals(username_login)) {
return failed(this).feedback("user.not.larry").feedbackArgs(username_login).build();
}
try (var connection = dataSource.getConnection()) {
PreparedStatement statement = connection.prepareStatement("select password from challenge_users where userid = '" + username_login + "' and password = '" + password_login + "'");
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(5)).build();
} else {
return failed(this).feedback("challenge.close").build();
}
}
if (!"Larry".equals(username_login)) {
return failed(this).feedback("user.not.larry").feedbackArgs(username_login).build();
}
try (var connection = dataSource.getConnection()) {
PreparedStatement statement =
connection.prepareStatement(
"select password from challenge_users where userid = '"
+ username_login
+ "' and password = '"
+ password_login
+ "'");
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
return success(this).feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(5)).build();
} else {
return failed(this).feedback("challenge.close").build();
}
}
}
}

View File

@ -33,13 +33,13 @@ import org.springframework.stereotype.Component;
@Component
public class Challenge5 extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public String getTitle() {
return "challenge5.title";
}
@Override
public String getTitle() {
return "challenge5.title";
}
}

View File

@ -1,11 +1,15 @@
package org.owasp.webgoat.lessons.challenges.challenge7;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.owasp.webgoat.lessons.challenges.Email;
import org.owasp.webgoat.lessons.challenges.SolutionConstants;
import org.owasp.webgoat.lessons.challenges.Flag;
import org.owasp.webgoat.lessons.challenges.SolutionConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
@ -21,11 +25,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
/**
* @author nbaars
* @since 4/8/17.
@ -34,53 +33,67 @@ import java.time.LocalDateTime;
@Slf4j
public class Assignment7 extends AssignmentEndpoint {
private static final String TEMPLATE = "Hi, you requested a password reset link, please use this "
+ "<a target='_blank' href='%s:8080/WebGoat/challenge/7/reset-password/%s'>link</a> to reset your password."
+ "\n \n\n"
+ "If you did not request this password change you can ignore this message."
+ "\n"
+ "If you have any comments or questions, please do not hesitate to reach us at support@webgoat-cloud.org"
+ "\n\n"
+ "Kind regards, \nTeam WebGoat";
private static final String TEMPLATE =
"Hi, you requested a password reset link, please use this <a target='_blank'"
+ " href='%s:8080/WebGoat/challenge/7/reset-password/%s'>link</a> to reset your"
+ " password.\n"
+ " \n\n"
+ "If you did not request this password change you can ignore this message.\n"
+ "If you have any comments or questions, please do not hesitate to reach us at"
+ " support@webgoat-cloud.org\n\n"
+ "Kind regards, \n"
+ "Team WebGoat";
@Autowired
private RestTemplate restTemplate;
@Value("${webwolf.mail.url}")
private String webWolfMailURL;
@Autowired private RestTemplate restTemplate;
@GetMapping("/challenge/7/reset-password/{link}")
public ResponseEntity<String> resetPassword(@PathVariable(value = "link") String link) {
if (link.equals(SolutionConstants.ADMIN_PASSWORD_LINK)) {
return ResponseEntity.accepted().body("<h1>Success!!</h1>"
+ "<img src='/WebGoat/images/hi-five-cat.jpg'>"
+ "<br/><br/>Here is your flag: " + "<b>" + Flag.FLAGS.get(7) + "</b>");
}
return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT).body("That is not the reset link for admin");
@Value("${webwolf.mail.url}")
private String webWolfMailURL;
@GetMapping("/challenge/7/reset-password/{link}")
public ResponseEntity<String> resetPassword(@PathVariable(value = "link") String link) {
if (link.equals(SolutionConstants.ADMIN_PASSWORD_LINK)) {
return ResponseEntity.accepted()
.body(
"<h1>Success!!</h1>"
+ "<img src='/WebGoat/images/hi-five-cat.jpg'>"
+ "<br/><br/>Here is your flag: "
+ "<b>"
+ Flag.FLAGS.get(7)
+ "</b>");
}
return ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT)
.body("That is not the reset link for admin");
}
@PostMapping("/challenge/7")
@ResponseBody
public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request) throws URISyntaxException {
if (StringUtils.hasText(email)) {
String username = email.substring(0, email.indexOf("@"));
if (StringUtils.hasText(username)) {
URI uri = new URI(request.getRequestURL().toString());
Email mail = Email.builder()
.title("Your password reset link for challenge 7")
.contents(String.format(TEMPLATE, uri.getScheme() + "://" + uri.getHost(), new PasswordResetLink().createPasswordReset(username, "webgoat")))
.sender("password-reset@webgoat-cloud.net")
.recipient(username)
.time(LocalDateTime.now()).build();
restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
}
}
return success(this).feedback("email.send").feedbackArgs(email).build();
@PostMapping("/challenge/7")
@ResponseBody
public AttackResult sendPasswordResetLink(@RequestParam String email, HttpServletRequest request)
throws URISyntaxException {
if (StringUtils.hasText(email)) {
String username = email.substring(0, email.indexOf("@"));
if (StringUtils.hasText(username)) {
URI uri = new URI(request.getRequestURL().toString());
Email mail =
Email.builder()
.title("Your password reset link for challenge 7")
.contents(
String.format(
TEMPLATE,
uri.getScheme() + "://" + uri.getHost(),
new PasswordResetLink().createPasswordReset(username, "webgoat")))
.sender("password-reset@webgoat-cloud.net")
.recipient(username)
.time(LocalDateTime.now())
.build();
restTemplate.postForEntity(webWolfMailURL, mail, Object.class);
}
}
return success(this).feedback("email.send").feedbackArgs(email).build();
}
@GetMapping(value = "/challenge/7/.git", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public ClassPathResource git() {
return new ClassPathResource("challenge7/git.zip");
}
@GetMapping(value = "/challenge/7/.git", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public ClassPathResource git() {
return new ClassPathResource("challenge7/git.zip");
}
}

View File

@ -11,13 +11,13 @@ import org.springframework.stereotype.Component;
@Component
public class Challenge7 extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public String getTitle() {
return "challenge7.title";
}
@Override
public String getTitle() {
return "challenge7.title";
}
}

View File

@ -10,34 +10,36 @@ import java.util.Random;
*/
public class PasswordResetLink {
public String createPasswordReset(String username, String key) {
Random random = new Random();
if (username.equalsIgnoreCase("admin")) {
//Admin has a fix reset link
random.setSeed(key.length());
}
return scramble(random, scramble(random, scramble(random, MD5.getHashString(username))));
public String createPasswordReset(String username, String key) {
Random random = new Random();
if (username.equalsIgnoreCase("admin")) {
// Admin has a fix reset link
random.setSeed(key.length());
}
return scramble(random, scramble(random, scramble(random, MD5.getHashString(username))));
}
public static String scramble(Random random, String inputString) {
char[] a = inputString.toCharArray();
for (int i = 0; i < a.length; i++) {
int j = random.nextInt(a.length);
char temp = a[i];
a[i] = a[j];
a[j] = temp;
}
return new String(a);
public static String scramble(Random random, String inputString) {
char[] a = inputString.toCharArray();
for (int i = 0; i < a.length; i++) {
int j = random.nextInt(a.length);
char temp = a[i];
a[i] = a[j];
a[j] = temp;
}
return new String(a);
}
public static void main(String[] args) {
if (args == null || args.length != 2) {
System.out.println("Need a username and key");
System.exit(1);
}
String username = args[0];
String key = args[1];
System.out.println("Generation password reset link for " + username);
System.out.println("Created password reset link: " + new PasswordResetLink().createPasswordReset(username, key));
public static void main(String[] args) {
if (args == null || args.length != 2) {
System.out.println("Need a username and key");
System.exit(1);
}
String username = args[0];
String key = args[1];
System.out.println("Generation password reset link for " + username);
System.out.println(
"Created password reset link: "
+ new PasswordResetLink().createPasswordReset(username, key));
}
}

View File

@ -1,5 +1,9 @@
package org.owasp.webgoat.lessons.challenges.challenge8;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -11,11 +15,6 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author nbaars
* @since 4/8/17.
@ -24,46 +23,54 @@ import java.util.stream.Collectors;
@Slf4j
public class Assignment8 extends AssignmentEndpoint {
private static final Map<Integer, Integer> votes = new HashMap<>();
private static final Map<Integer, Integer> votes = new HashMap<>();
static {
votes.put(1, 400);
votes.put(2, 120);
votes.put(3, 140);
votes.put(4, 150);
votes.put(5, 300);
}
static {
votes.put(1, 400);
votes.put(2, 120);
votes.put(3, 140);
votes.put(4, 150);
votes.put(5, 300);
}
@GetMapping(value = "/challenge/8/vote/{stars}", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<?> vote(@PathVariable(value = "stars") int nrOfStars, HttpServletRequest request) {
//Simple implementation of VERB Based Authentication
String msg = "";
if (request.getMethod().equals("GET")) {
var json = Map.of("error", true, "message", "Sorry but you need to login first in order to vote");
return ResponseEntity.status(200).body(json);
}
Integer allVotesForStar = votes.getOrDefault(nrOfStars, 0);
votes.put(nrOfStars, allVotesForStar + 1);
return ResponseEntity.ok().header("X-Flag", "Thanks for voting, your flag is: " + Flag.FLAGS.get(8)).build();
@GetMapping(value = "/challenge/8/vote/{stars}", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<?> vote(
@PathVariable(value = "stars") int nrOfStars, HttpServletRequest request) {
// Simple implementation of VERB Based Authentication
String msg = "";
if (request.getMethod().equals("GET")) {
var json =
Map.of("error", true, "message", "Sorry but you need to login first in order to vote");
return ResponseEntity.status(200).body(json);
}
Integer allVotesForStar = votes.getOrDefault(nrOfStars, 0);
votes.put(nrOfStars, allVotesForStar + 1);
return ResponseEntity.ok()
.header("X-Flag", "Thanks for voting, your flag is: " + Flag.FLAGS.get(8))
.build();
}
@GetMapping("/challenge/8/votes/")
public ResponseEntity<?> getVotes() {
return ResponseEntity.ok(votes.entrySet().stream().collect(Collectors.toMap(e -> "" + e.getKey(), e -> e.getValue())));
}
@GetMapping("/challenge/8/votes/")
public ResponseEntity<?> getVotes() {
return ResponseEntity.ok(
votes.entrySet().stream()
.collect(Collectors.toMap(e -> "" + e.getKey(), e -> e.getValue())));
}
@GetMapping("/challenge/8/votes/average")
public ResponseEntity<Map<String, Integer>> average() {
int totalNumberOfVotes = votes.values().stream().mapToInt(i -> i.intValue()).sum();
int categories = votes.entrySet().stream().mapToInt(e -> e.getKey() * e.getValue()).reduce(0, (a, b) -> a + b);
var json = Map.of("average", (int) Math.ceil((double) categories / totalNumberOfVotes));
return ResponseEntity.ok(json);
}
@GetMapping("/challenge/8/votes/average")
public ResponseEntity<Map<String, Integer>> average() {
int totalNumberOfVotes = votes.values().stream().mapToInt(i -> i.intValue()).sum();
int categories =
votes.entrySet().stream()
.mapToInt(e -> e.getKey() * e.getValue())
.reduce(0, (a, b) -> a + b);
var json = Map.of("average", (int) Math.ceil((double) categories / totalNumberOfVotes));
return ResponseEntity.ok(json);
}
@GetMapping("/challenge/8/notUsed")
public AttackResult notUsed() {
throw new IllegalStateException("Should never be called, challenge specific method");
}
@GetMapping("/challenge/8/notUsed")
public AttackResult notUsed() {
throw new IllegalStateException("Should never be called, challenge specific method");
}
}

View File

@ -11,13 +11,13 @@ import org.springframework.stereotype.Component;
@Component
public class Challenge8 extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public Category getDefaultCategory() {
return Category.CHALLENGE;
}
@Override
public String getTitle() {
return "challenge8.title";
}
@Override
public String getTitle() {
return "challenge8.title";
}
}

View File

@ -33,13 +33,13 @@ import org.springframework.stereotype.Component;
@Component
public class ChromeDevTools extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.GENERAL;
}
@Override
public Category getDefaultCategory() {
return Category.GENERAL;
}
@Override
public String getTitle() {
return "3.chrome-dev-tools.title";//3rd lesson in General
}
@Override
public String getTitle() {
return "3.chrome-dev-tools.title"; // 3rd lesson in General
}
}

View File

@ -39,16 +39,16 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class NetworkDummy extends AssignmentEndpoint {
@PostMapping("/ChromeDevTools/dummy")
@ResponseBody
public AttackResult completed(@RequestParam String successMessage) {
UserSessionData userSessionData = getUserSessionData();
String answer = (String) userSessionData.getValue("randValue");
@PostMapping("/ChromeDevTools/dummy")
@ResponseBody
public AttackResult completed(@RequestParam String successMessage) {
UserSessionData userSessionData = getUserSessionData();
String answer = (String) userSessionData.getValue("randValue");
if (successMessage != null && successMessage.equals(answer)) {
return success(this).feedback("xss-dom-message-success").build();
} else {
return failed(this).feedback("xss-dom-message-failure").build();
}
if (successMessage != null && successMessage.equals(answer)) {
return success(this).feedback("xss-dom-message-success").build();
} else {
return failed(this).feedback("xss-dom-message-failure").build();
}
}
}

View File

@ -32,8 +32,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* Assignment where the user has to look through an HTTP Request
* using the Developer Tools and find a specific number.
* Assignment where the user has to look through an HTTP Request using the Developer Tools and find
* a specific number.
*
* @author TMelzer
* @since 30.11.18
@ -42,19 +42,21 @@ import org.springframework.web.bind.annotation.RestController;
@AssignmentHints({"networkHint1", "networkHint2"})
public class NetworkLesson extends AssignmentEndpoint {
@PostMapping(value = "/ChromeDevTools/network", params = {"network_num", "number"})
@ResponseBody
public AttackResult completed(@RequestParam String network_num, @RequestParam String number) {
if (network_num.equals(number)) {
return success(this).feedback("network.success").output("").build();
} else {
return failed(this).feedback("network.failed").build();
}
@PostMapping(
value = "/ChromeDevTools/network",
params = {"network_num", "number"})
@ResponseBody
public AttackResult completed(@RequestParam String network_num, @RequestParam String number) {
if (network_num.equals(number)) {
return success(this).feedback("network.success").output("").build();
} else {
return failed(this).feedback("network.failed").build();
}
}
@PostMapping(path = "/ChromeDevTools/network", params = "networkNum")
@ResponseBody
public ResponseEntity<?> ok(@RequestParam String networkNum) {
return ResponseEntity.ok().build();
}
@PostMapping(path = "/ChromeDevTools/network", params = "networkNum")
@ResponseBody
public ResponseEntity<?> ok(@RequestParam String networkNum) {
return ResponseEntity.ok().build();
}
}

View File

@ -11,13 +11,13 @@ import org.springframework.stereotype.Component;
@Component
public class CIA extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.GENERAL;
}
@Override
public Category getDefaultCategory() {
return Category.GENERAL;
}
@Override
public String getTitle() {
return "4.cia.title";//4th lesson in general
}
@Override
public String getTitle() {
return "4.cia.title"; // 4th lesson in general
}
}

View File

@ -11,38 +11,43 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
public class CIAQuiz extends AssignmentEndpoint {
String[] solutions = {"Solution 3", "Solution 1", "Solution 4", "Solution 2"};
boolean[] guesses = new boolean[solutions.length];
String[] solutions = {"Solution 3", "Solution 1", "Solution 4", "Solution 2"};
boolean[] guesses = new boolean[solutions.length];
@PostMapping("/cia/quiz")
@ResponseBody
public AttackResult completed(@RequestParam String[] question_0_solution, @RequestParam String[] question_1_solution, @RequestParam String[] question_2_solution, @RequestParam String[] question_3_solution) {
int correctAnswers = 0;
@PostMapping("/cia/quiz")
@ResponseBody
public AttackResult completed(
@RequestParam String[] question_0_solution,
@RequestParam String[] question_1_solution,
@RequestParam String[] question_2_solution,
@RequestParam String[] question_3_solution) {
int correctAnswers = 0;
String[] givenAnswers = {question_0_solution[0], question_1_solution[0], question_2_solution[0], question_3_solution[0]};
String[] givenAnswers = {
question_0_solution[0], question_1_solution[0], question_2_solution[0], question_3_solution[0]
};
for (int i = 0; i < solutions.length; i++) {
if (givenAnswers[i].contains(solutions[i])) {
// answer correct
correctAnswers++;
guesses[i] = true;
} else {
// answer incorrect
guesses[i] = false;
}
}
if (correctAnswers == solutions.length) {
return success(this).build();
} else {
return failed(this).build();
}
for (int i = 0; i < solutions.length; i++) {
if (givenAnswers[i].contains(solutions[i])) {
// answer correct
correctAnswers++;
guesses[i] = true;
} else {
// answer incorrect
guesses[i] = false;
}
}
@GetMapping("/cia/quiz")
@ResponseBody
public boolean[] getResults() {
return this.guesses;
if (correctAnswers == solutions.length) {
return success(this).build();
} else {
return failed(this).build();
}
}
@GetMapping("/cia/quiz")
@ResponseBody
public boolean[] getResults() {
return this.guesses;
}
}

View File

@ -8,25 +8,26 @@ import org.springframework.stereotype.Component;
* ************************************************************************************************
* 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 - 2014 Bruce Mayhew
* <p>
* This program is free software; you can redistribute it and/or modify it under the terms of the
*
* <p>Copyright (c) 2002 - 2014 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
*
* <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* <p>You should have received a copy of the GNU General Public License along with this program; if
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* <p>
* Getting Source ==============
* <p>
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
* projects.
*
* <p>Getting Source ==============
*
* <p>Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository
* for free software projects.
*
* <p>
*
* @author WebGoat
@ -36,13 +37,13 @@ import org.springframework.stereotype.Component;
@Component
public class ClientSideFiltering extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.CLIENT_SIDE;
}
@Override
public Category getDefaultCategory() {
return Category.CLIENT_SIDE;
}
@Override
public String getTitle() {
return "client.side.filtering.title";
}
@Override
public String getTitle() {
return "client.side.filtering.title";
}
}

View File

@ -31,14 +31,19 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@AssignmentHints({"ClientSideFilteringHint1", "ClientSideFilteringHint2", "ClientSideFilteringHint3", "ClientSideFilteringHint4"})
@AssignmentHints({
"ClientSideFilteringHint1",
"ClientSideFilteringHint2",
"ClientSideFilteringHint3",
"ClientSideFilteringHint4"
})
public class ClientSideFilteringAssignment extends AssignmentEndpoint {
@PostMapping("/clientSideFiltering/attack1")
@ResponseBody
public AttackResult completed(@RequestParam String answer) {
return "450000".equals(answer)
? success(this).feedback("assignment.solved").build() :
failed(this).feedback("ClientSideFiltering.incorrect").build();
}
@PostMapping("/clientSideFiltering/attack1")
@ResponseBody
public AttackResult completed(@RequestParam String answer) {
return "450000".equals(answer)
? success(this).feedback("assignment.solved").build()
: failed(this).feedback("ClientSideFiltering.incorrect").build();
}
}

View File

@ -35,17 +35,21 @@ import org.springframework.web.bind.annotation.RestController;
* @since 4/6/17.
*/
@RestController
@AssignmentHints({"client.side.filtering.free.hint1", "client.side.filtering.free.hint2", "client.side.filtering.free.hint3"})
@AssignmentHints({
"client.side.filtering.free.hint1",
"client.side.filtering.free.hint2",
"client.side.filtering.free.hint3"
})
public class ClientSideFilteringFreeAssignment extends AssignmentEndpoint {
public static final String SUPER_COUPON_CODE = "get_it_for_free";
public static final String SUPER_COUPON_CODE = "get_it_for_free";
@PostMapping("/clientSideFiltering/getItForFree")
@ResponseBody
public AttackResult completed(@RequestParam String checkoutCode) {
if (SUPER_COUPON_CODE.equals(checkoutCode)) {
return success(this).build();
}
return failed(this).build();
@PostMapping("/clientSideFiltering/getItForFree")
@ResponseBody
public AttackResult completed(@RequestParam String checkoutCode) {
if (SUPER_COUPON_CODE.equals(checkoutCode)) {
return success(this).build();
}
return failed(this).build();
}
}

View File

@ -22,6 +22,20 @@
package org.owasp.webgoat.lessons.clientsidefiltering;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
@ -33,79 +47,66 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.annotation.PostConstruct;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@Slf4j
public class Salaries {
@Value("${webgoat.user.directory}")
private String webGoatHomeDirectory;
@Value("${webgoat.user.directory}")
private String webGoatHomeDirectory;
@PostConstruct
public void copyFiles() {
ClassPathResource classPathResource = new ClassPathResource("lessons/employees.xml");
File targetDirectory = new File(webGoatHomeDirectory, "/ClientSideFiltering");
if (!targetDirectory.exists()) {
targetDirectory.mkdir();
}
try {
FileCopyUtils.copy(classPathResource.getInputStream(), new FileOutputStream(new File(targetDirectory, "employees.xml")));
} catch (IOException e) {
throw new RuntimeException(e);
}
@PostConstruct
public void copyFiles() {
ClassPathResource classPathResource = new ClassPathResource("lessons/employees.xml");
File targetDirectory = new File(webGoatHomeDirectory, "/ClientSideFiltering");
if (!targetDirectory.exists()) {
targetDirectory.mkdir();
}
@GetMapping("clientSideFiltering/salaries")
@ResponseBody
public List<Map<String, Object>> invoke() {
NodeList nodes = null;
File d = new File(webGoatHomeDirectory, "ClientSideFiltering/employees.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath path = factory.newXPath();
int columns = 5;
List<Map<String, Object>> json = new ArrayList<>();
java.util.Map<String, Object> employeeJson = new HashMap<>();
try (InputStream is = new FileInputStream(d)) {
InputSource inputSource = new InputSource(is);
StringBuilder sb = new StringBuilder();
sb.append("/Employees/Employee/UserID | ");
sb.append("/Employees/Employee/FirstName | ");
sb.append("/Employees/Employee/LastName | ");
sb.append("/Employees/Employee/SSN | ");
sb.append("/Employees/Employee/Salary ");
String expression = sb.toString();
nodes = (NodeList) path.evaluate(expression, inputSource, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
if (i % columns == 0) {
employeeJson = new HashMap<>();
json.add(employeeJson);
}
Node node = nodes.item(i);
employeeJson.put(node.getNodeName(), node.getTextContent());
}
} catch (XPathExpressionException e) {
log.error("Unable to parse xml", e);
} catch (IOException e) {
log.error("Unable to read employees.xml at location: '{}'", d);
}
return json;
try {
FileCopyUtils.copy(
classPathResource.getInputStream(),
new FileOutputStream(new File(targetDirectory, "employees.xml")));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@GetMapping("clientSideFiltering/salaries")
@ResponseBody
public List<Map<String, Object>> invoke() {
NodeList nodes = null;
File d = new File(webGoatHomeDirectory, "ClientSideFiltering/employees.xml");
XPathFactory factory = XPathFactory.newInstance();
XPath path = factory.newXPath();
int columns = 5;
List<Map<String, Object>> json = new ArrayList<>();
java.util.Map<String, Object> employeeJson = new HashMap<>();
try (InputStream is = new FileInputStream(d)) {
InputSource inputSource = new InputSource(is);
StringBuilder sb = new StringBuilder();
sb.append("/Employees/Employee/UserID | ");
sb.append("/Employees/Employee/FirstName | ");
sb.append("/Employees/Employee/LastName | ");
sb.append("/Employees/Employee/SSN | ");
sb.append("/Employees/Employee/Salary ");
String expression = sb.toString();
nodes = (NodeList) path.evaluate(expression, inputSource, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
if (i % columns == 0) {
employeeJson = new HashMap<>();
json.add(employeeJson);
}
Node node = nodes.item(i);
employeeJson.put(node.getNodeName(), node.getTextContent());
}
} catch (XPathExpressionException e) {
log.error("Unable to parse xml", e);
} catch (IOException e) {
log.error("Unable to read employees.xml at location: '{}'", d);
}
return json;
}
}

View File

@ -23,18 +23,16 @@
package org.owasp.webgoat.lessons.clientsidefiltering;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Optional;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Optional;
/**
* @author nbaars
* @since 4/6/17.
@ -43,47 +41,46 @@ import java.util.Optional;
@RequestMapping("/clientSideFiltering/challenge-store")
public class ShopEndpoint {
@AllArgsConstructor
private class CheckoutCodes {
@AllArgsConstructor
private class CheckoutCodes {
@Getter
private List<CheckoutCode> codes;
@Getter private List<CheckoutCode> codes;
public Optional<CheckoutCode> get(String code) {
return codes.stream().filter(c -> c.getCode().equals(code)).findFirst();
}
public Optional<CheckoutCode> get(String code) {
return codes.stream().filter(c -> c.getCode().equals(code)).findFirst();
}
}
@AllArgsConstructor
@Getter
private class CheckoutCode {
private String code;
private int discount;
@AllArgsConstructor
@Getter
private class CheckoutCode {
private String code;
private int discount;
}
private CheckoutCodes checkoutCodes;
public ShopEndpoint() {
List<CheckoutCode> codes = Lists.newArrayList();
codes.add(new CheckoutCode("webgoat", 25));
codes.add(new CheckoutCode("owasp", 25));
codes.add(new CheckoutCode("owasp-webgoat", 50));
this.checkoutCodes = new CheckoutCodes(codes);
}
@GetMapping(value = "/coupons/{code}", produces = MediaType.APPLICATION_JSON_VALUE)
public CheckoutCode getDiscountCode(@PathVariable String code) {
if (ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE.equals(code)) {
return new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100);
}
return checkoutCodes.get(code).orElse(new CheckoutCode("no", 0));
}
private CheckoutCodes checkoutCodes;
public ShopEndpoint() {
List<CheckoutCode> codes = Lists.newArrayList();
codes.add(new CheckoutCode("webgoat", 25));
codes.add(new CheckoutCode("owasp", 25));
codes.add(new CheckoutCode("owasp-webgoat", 50));
this.checkoutCodes = new CheckoutCodes(codes);
}
@GetMapping(value = "/coupons/{code}", produces = MediaType.APPLICATION_JSON_VALUE)
public CheckoutCode getDiscountCode(@PathVariable String code) {
if (ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE.equals(code)) {
return new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100);
}
return checkoutCodes.get(code).orElse(new CheckoutCode("no", 0));
}
@GetMapping(value = "/coupons", produces = MediaType.APPLICATION_JSON_VALUE)
public CheckoutCodes all() {
List<CheckoutCode> all = Lists.newArrayList();
all.addAll(this.checkoutCodes.getCodes());
all.add(new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100));
return new CheckoutCodes(all);
}
@GetMapping(value = "/coupons", produces = MediaType.APPLICATION_JSON_VALUE)
public CheckoutCodes all() {
List<CheckoutCode> all = Lists.newArrayList();
all.addAll(this.checkoutCodes.getCodes());
all.add(new CheckoutCode(ClientSideFilteringFreeAssignment.SUPER_COUPON_CODE, 100));
return new CheckoutCodes(all);
}
}

View File

@ -1,8 +1,5 @@
package org.owasp.webgoat.lessons.cryptography;
import lombok.extern.slf4j.Slf4j;
import javax.xml.bind.DatatypeConverter;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
@ -19,117 +16,128 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.Base64;
import javax.xml.bind.DatatypeConverter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class CryptoUtil {
private static final BigInteger[] FERMAT_PRIMES =
{ BigInteger.valueOf(3),
BigInteger.valueOf(5),
BigInteger.valueOf(17),
BigInteger.valueOf(257),
BigInteger.valueOf(65537) };
private static final BigInteger[] FERMAT_PRIMES = {
BigInteger.valueOf(3),
BigInteger.valueOf(5),
BigInteger.valueOf(17),
BigInteger.valueOf(257),
BigInteger.valueOf(65537)
};
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
RSAKeyGenParameterSpec kpgSpec = new RSAKeyGenParameterSpec(2048, FERMAT_PRIMES[new SecureRandom().nextInt(FERMAT_PRIMES.length)]);
keyPairGenerator.initialize(kpgSpec);
//keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
public static KeyPair generateKeyPair()
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
RSAKeyGenParameterSpec kpgSpec =
new RSAKeyGenParameterSpec(
2048, FERMAT_PRIMES[new SecureRandom().nextInt(FERMAT_PRIMES.length)]);
keyPairGenerator.initialize(kpgSpec);
// keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
}
public static String getPrivateKeyInPEM(KeyPair keyPair) {
String encodedString = "-----BEGIN PRIVATE KEY-----\n";
encodedString =
encodedString
+ new String(
Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()),
Charset.forName("UTF-8"))
+ "\n";
encodedString = encodedString + "-----END PRIVATE KEY-----\n";
return encodedString;
}
public static String signMessage(String message, PrivateKey privateKey) {
log.debug("start signMessage");
String signature = null;
try {
// Initiate signature verification
Signature instance = Signature.getInstance("SHA256withRSA");
instance.initSign(privateKey);
instance.update(message.getBytes("UTF-8"));
// actual verification against signature
signature = new String(Base64.getEncoder().encode(instance.sign()), Charset.forName("UTF-8"));
log.info("signe the signature with result: {}", signature);
} catch (Exception e) {
log.error("Signature signing failed", e);
}
public static String getPrivateKeyInPEM(KeyPair keyPair) {
String encodedString = "-----BEGIN PRIVATE KEY-----\n";
encodedString = encodedString+new String(Base64.getEncoder().encode(keyPair.getPrivate().getEncoded()),Charset.forName("UTF-8"))+"\n";
encodedString = encodedString+"-----END PRIVATE KEY-----\n";
return encodedString;
log.debug("end signMessage");
return signature;
}
public static boolean verifyMessage(
String message, String base64EncSignature, PublicKey publicKey) {
log.debug("start verifyMessage");
boolean result = false;
try {
base64EncSignature = base64EncSignature.replace("\r", "").replace("\n", "").replace(" ", "");
// get raw signature from base64 encrypted string in header
byte[] decodedSignature = Base64.getDecoder().decode(base64EncSignature);
// Initiate signature verification
Signature instance = Signature.getInstance("SHA256withRSA");
instance.initVerify(publicKey);
instance.update(message.getBytes("UTF-8"));
// actual verification against signature
result = instance.verify(decodedSignature);
log.info("Verified the signature with result: {}", result);
} catch (Exception e) {
log.error("Signature verification failed", e);
}
public static String signMessage(String message, PrivateKey privateKey) {
log.debug("end verifyMessage");
return result;
}
log.debug("start signMessage");
String signature = null;
try {
//Initiate signature verification
Signature instance = Signature.getInstance("SHA256withRSA");
instance.initSign(privateKey);
instance.update(message.getBytes("UTF-8"));
//actual verification against signature
signature = new String(Base64.getEncoder().encode(instance.sign()), Charset.forName("UTF-8"));
public static boolean verifyAssignment(String modulus, String signature, PublicKey publicKey) {
log.info("signe the signature with result: {}", signature);
} catch (Exception e) {
log.error("Signature signing failed", e);
}
/* first check if the signature is correct, i.e. right private key and right hash */
boolean result = false;
log.debug("end signMessage");
return signature;
}
public static boolean verifyMessage(String message, String base64EncSignature,
PublicKey publicKey) {
if (modulus != null && signature != null) {
result = verifyMessage(modulus, signature, publicKey);
log.debug("start verifyMessage");
boolean result = false;
try {
base64EncSignature = base64EncSignature.replace("\r", "").replace("\n", "")
.replace(" ", "");
//get raw signature from base64 encrypted string in header
byte[] decodedSignature = Base64.getDecoder().decode(base64EncSignature);
//Initiate signature verification
Signature instance = Signature.getInstance("SHA256withRSA");
instance.initVerify(publicKey);
instance.update(message.getBytes("UTF-8"));
//actual verification against signature
result = instance.verify(decodedSignature);
/*
* next check if the submitted modulus is the correct modulus of the public key
*/
RSAPublicKey rsaPubKey = (RSAPublicKey) publicKey;
if (modulus.length() == 512) {
modulus = "00".concat(modulus);
}
result =
result
&& (DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray())
.equals(modulus.toUpperCase()));
}
return result;
}
log.info("Verified the signature with result: {}", result);
} catch (Exception e) {
log.error("Signature verification failed", e);
}
public static PrivateKey getPrivateKeyFromPEM(String privateKeyPem)
throws NoSuchAlgorithmException, InvalidKeySpecException {
privateKeyPem = privateKeyPem.replace("-----BEGIN PRIVATE KEY-----", "");
privateKeyPem = privateKeyPem.replace("-----END PRIVATE KEY-----", "");
privateKeyPem = privateKeyPem.replace("\n", "").replace("\r", "");
log.debug("end verifyMessage");
return result;
}
public static boolean verifyAssignment(String modulus, String signature, PublicKey publicKey) {
/* first check if the signature is correct, i.e. right private key and right hash */
boolean result = false;
if (modulus != null && signature != null) {
result = verifyMessage(modulus, signature, publicKey);
/*
* next check if the submitted modulus is the correct modulus of the public key
*/
RSAPublicKey rsaPubKey = (RSAPublicKey) publicKey;
if (modulus.length()==512) {
modulus = "00".concat(modulus);
}
result = result && (DatatypeConverter.printHexBinary(rsaPubKey.getModulus().toByteArray()).equals(modulus.toUpperCase()));
}
return result;
}
public static PrivateKey getPrivateKeyFromPEM(String privateKeyPem) throws NoSuchAlgorithmException, InvalidKeySpecException {
privateKeyPem = privateKeyPem.replace("-----BEGIN PRIVATE KEY-----", "");
privateKeyPem = privateKeyPem.replace("-----END PRIVATE KEY-----", "");
privateKeyPem = privateKeyPem.replace("\n", "").replace("\r", "");
byte [] decoded = Base64.getDecoder().decode(privateKeyPem);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
byte[] decoded = Base64.getDecoder().decode(privateKeyPem);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
}

View File

@ -28,14 +28,13 @@ import org.springframework.stereotype.Component;
@Component
public class Cryptography extends Lesson {
@Override
public Category getDefaultCategory() {
return Category.A2;
}
@Override
public String getTitle() {
return "6.crypto.title";//first lesson in general
}
@Override
public Category getDefaultCategory() {
return Category.A2;
}
@Override
public String getTitle() {
return "6.crypto.title"; // first lesson in general
}
}

View File

@ -22,6 +22,9 @@
package org.owasp.webgoat.lessons.cryptography;
import java.util.Base64;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AttackResult;
import org.springframework.http.MediaType;
@ -31,43 +34,42 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Random;
@RestController
public class EncodingAssignment extends AssignmentEndpoint {
public static String getBasicAuth(String username, String password) {
return Base64.getEncoder().encodeToString(username.concat(":").concat(password).getBytes());
public static String getBasicAuth(String username, String password) {
return Base64.getEncoder().encodeToString(username.concat(":").concat(password).getBytes());
}
@GetMapping(path = "/crypto/encoding/basic", produces = MediaType.TEXT_HTML_VALUE)
@ResponseBody
public String getBasicAuth(HttpServletRequest request) {
String basicAuth = (String) request.getSession().getAttribute("basicAuth");
String username = request.getUserPrincipal().getName();
if (basicAuth == null) {
String password =
HashingAssignment.SECRETS[new Random().nextInt(HashingAssignment.SECRETS.length)];
basicAuth = getBasicAuth(username, password);
request.getSession().setAttribute("basicAuth", basicAuth);
}
@GetMapping(path="/crypto/encoding/basic",produces=MediaType.TEXT_HTML_VALUE)
@ResponseBody
public String getBasicAuth(HttpServletRequest request) {
String basicAuth = (String) request.getSession().getAttribute("basicAuth");
String username = request.getUserPrincipal().getName();
if (basicAuth == null) {
String password = HashingAssignment.SECRETS[new Random().nextInt(HashingAssignment.SECRETS.length)];
basicAuth = getBasicAuth(username, password);
request.getSession().setAttribute("basicAuth", basicAuth);
}
return "Authorization: Basic ".concat(basicAuth);
}
@PostMapping("/crypto/encoding/basic-auth")
@ResponseBody
public AttackResult completed(HttpServletRequest request, @RequestParam String answer_user, @RequestParam String answer_pwd) {
String basicAuth = (String) request.getSession().getAttribute("basicAuth");
if (basicAuth !=null && answer_user!=null && answer_pwd !=null
&& basicAuth.equals(getBasicAuth(answer_user,answer_pwd)))
{
return success(this)
.feedback("crypto-encoding.success")
.build();
} else {
return failed(this).feedback("crypto-encoding.empty").build();
}
return "Authorization: Basic ".concat(basicAuth);
}
@PostMapping("/crypto/encoding/basic-auth")
@ResponseBody
public AttackResult completed(
HttpServletRequest request,
@RequestParam String answer_user,
@RequestParam String answer_pwd) {
String basicAuth = (String) request.getSession().getAttribute("basicAuth");
if (basicAuth != null
&& answer_user != null
&& answer_pwd != null
&& basicAuth.equals(getBasicAuth(answer_user, answer_pwd))) {
return success(this).feedback("crypto-encoding.success").build();
} else {
return failed(this).feedback("crypto-encoding.empty").build();
}
}
}

View File

@ -22,6 +22,11 @@
package org.owasp.webgoat.lessons.cryptography;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -32,79 +37,69 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
@RestController
@AssignmentHints({"crypto-hashing.hints.1","crypto-hashing.hints.2"})
@AssignmentHints({"crypto-hashing.hints.1", "crypto-hashing.hints.2"})
public class HashingAssignment extends AssignmentEndpoint {
public static final String[] SECRETS = {"secret","admin","password", "123456", "passw0rd"};
@RequestMapping(path="/crypto/hashing/md5",produces=MediaType.TEXT_HTML_VALUE)
@ResponseBody
public String getMd5(HttpServletRequest request) throws NoSuchAlgorithmException {
String md5Hash = (String) request.getSession().getAttribute("md5Hash");
if (md5Hash == null) {
String secret = SECRETS[new Random().nextInt(SECRETS.length)];
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(secret.getBytes());
byte[] digest = md.digest();
md5Hash = DatatypeConverter
.printHexBinary(digest).toUpperCase();
request.getSession().setAttribute("md5Hash", md5Hash);
request.getSession().setAttribute("md5Secret", secret);
}
return md5Hash;
public static final String[] SECRETS = {"secret", "admin", "password", "123456", "passw0rd"};
@RequestMapping(path = "/crypto/hashing/md5", produces = MediaType.TEXT_HTML_VALUE)
@ResponseBody
public String getMd5(HttpServletRequest request) throws NoSuchAlgorithmException {
String md5Hash = (String) request.getSession().getAttribute("md5Hash");
if (md5Hash == null) {
String secret = SECRETS[new Random().nextInt(SECRETS.length)];
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(secret.getBytes());
byte[] digest = md.digest();
md5Hash = DatatypeConverter.printHexBinary(digest).toUpperCase();
request.getSession().setAttribute("md5Hash", md5Hash);
request.getSession().setAttribute("md5Secret", secret);
}
@RequestMapping(path="/crypto/hashing/sha256",produces=MediaType.TEXT_HTML_VALUE)
@ResponseBody
public String getSha256(HttpServletRequest request) throws NoSuchAlgorithmException {
String sha256 = (String) request.getSession().getAttribute("sha256");
if (sha256 == null) {
String secret = SECRETS[new Random().nextInt(SECRETS.length)];
sha256 = getHash(secret, "SHA-256");
request.getSession().setAttribute("sha256Hash", sha256);
request.getSession().setAttribute("sha256Secret", secret);
}
return sha256;
return md5Hash;
}
@RequestMapping(path = "/crypto/hashing/sha256", produces = MediaType.TEXT_HTML_VALUE)
@ResponseBody
public String getSha256(HttpServletRequest request) throws NoSuchAlgorithmException {
String sha256 = (String) request.getSession().getAttribute("sha256");
if (sha256 == null) {
String secret = SECRETS[new Random().nextInt(SECRETS.length)];
sha256 = getHash(secret, "SHA-256");
request.getSession().setAttribute("sha256Hash", sha256);
request.getSession().setAttribute("sha256Secret", secret);
}
@PostMapping("/crypto/hashing")
@ResponseBody
public AttackResult completed(HttpServletRequest request, @RequestParam String answer_pwd1, @RequestParam String answer_pwd2) {
String md5Secret = (String) request.getSession().getAttribute("md5Secret");
String sha256Secret = (String) request.getSession().getAttribute("sha256Secret");
if (answer_pwd1!=null && answer_pwd2 !=null) {
if (answer_pwd1.equals(md5Secret)
&& answer_pwd2.equals(sha256Secret)) {
return success(this)
.feedback("crypto-hashing.success")
.build();
} else if (answer_pwd1.equals(md5Secret)
|| answer_pwd2.equals(sha256Secret)) {
return failed(this).feedback("crypto-hashing.oneok").build();
}
}
return failed(this).feedback("crypto-hashing.empty").build();
return sha256;
}
@PostMapping("/crypto/hashing")
@ResponseBody
public AttackResult completed(
HttpServletRequest request,
@RequestParam String answer_pwd1,
@RequestParam String answer_pwd2) {
String md5Secret = (String) request.getSession().getAttribute("md5Secret");
String sha256Secret = (String) request.getSession().getAttribute("sha256Secret");
if (answer_pwd1 != null && answer_pwd2 != null) {
if (answer_pwd1.equals(md5Secret) && answer_pwd2.equals(sha256Secret)) {
return success(this).feedback("crypto-hashing.success").build();
} else if (answer_pwd1.equals(md5Secret) || answer_pwd2.equals(sha256Secret)) {
return failed(this).feedback("crypto-hashing.oneok").build();
}
}
public static String getHash(String secret, String algorithm) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(algorithm);
md.update(secret.getBytes());
byte[] digest = md.digest();
return DatatypeConverter
.printHexBinary(digest).toUpperCase();
}
return failed(this).feedback("crypto-hashing.empty").build();
}
public static String getHash(String secret, String algorithm) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(algorithm);
md.update(secret.getBytes());
byte[] digest = md.digest();
return DatatypeConverter.printHexBinary(digest).toUpperCase();
}
}

View File

@ -22,6 +22,7 @@
package org.owasp.webgoat.lessons.cryptography;
import java.security.NoSuchAlgorithmException;
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
import org.owasp.webgoat.container.assignments.AssignmentHints;
import org.owasp.webgoat.container.assignments.AttackResult;
@ -30,24 +31,29 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.security.NoSuchAlgorithmException;
@RestController
@AssignmentHints({"crypto-secure-defaults.hints.1", "crypto-secure-defaults.hints.2", "crypto-secure-defaults.hints.3"})
@AssignmentHints({
"crypto-secure-defaults.hints.1",
"crypto-secure-defaults.hints.2",
"crypto-secure-defaults.hints.3"
})
public class SecureDefaultsAssignment extends AssignmentEndpoint {
@PostMapping("/crypto/secure/defaults")
@ResponseBody
public AttackResult completed(@RequestParam String secretFileName, @RequestParam String secretText) throws NoSuchAlgorithmException {
if (secretFileName!=null && secretFileName.equals("default_secret")) {
if (secretText!=null && HashingAssignment.getHash(secretText, "SHA-256").equalsIgnoreCase("34de66e5caf2cb69ff2bebdc1f3091ecf6296852446c718e38ebfa60e4aa75d2")) {
return success(this)
.feedback("crypto-secure-defaults.success")
.build();
} else {
return failed(this).feedback("crypto-secure-defaults.messagenotok").build();
}
}
return failed(this).feedback("crypto-secure-defaults.notok").build();
@PostMapping("/crypto/secure/defaults")
@ResponseBody
public AttackResult completed(
@RequestParam String secretFileName, @RequestParam String secretText)
throws NoSuchAlgorithmException {
if (secretFileName != null && secretFileName.equals("default_secret")) {
if (secretText != null
&& HashingAssignment.getHash(secretText, "SHA-256")
.equalsIgnoreCase(
"34de66e5caf2cb69ff2bebdc1f3091ecf6296852446c718e38ebfa60e4aa75d2")) {
return success(this).feedback("crypto-secure-defaults.success").build();
} else {
return failed(this).feedback("crypto-secure-defaults.messagenotok").build();
}
}
return failed(this).feedback("crypto-secure-defaults.notok").build();
}
}

Some files were not shown because too many files have changed in this diff Show More