diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..573d2b4eb --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,19 @@ +This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + +Copyright (c) 2002 - 2019 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. \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7036fabab..9023349dc 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ org.springframework.boot spring-boot-starter-parent - 1.5.21.RELEASE + 2.1.8.RELEASE diff --git a/webgoat-container/pom.xml b/webgoat-container/pom.xml index cf324686b..3067eca8b 100644 --- a/webgoat-container/pom.xml +++ b/webgoat-container/pom.xml @@ -121,8 +121,7 @@ org.thymeleaf.extras - thymeleaf-extras-springsecurity4 - 2.1.2.RELEASE + thymeleaf-extras-springsecurity5 org.hsqldb diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/AsciiDoctorTemplateResolver.java b/webgoat-container/src/main/java/org/owasp/webgoat/AsciiDoctorTemplateResolver.java index e5a4c7da9..8fcaf5635 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/AsciiDoctorTemplateResolver.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/AsciiDoctorTemplateResolver.java @@ -39,12 +39,15 @@ import org.owasp.webgoat.asciidoc.WebGoatVersionMacro; import org.owasp.webgoat.asciidoc.WebWolfMacro; import org.owasp.webgoat.asciidoc.WebWolfRootMacro; import org.owasp.webgoat.i18n.Language; -import org.thymeleaf.TemplateProcessingParameters; -import org.thymeleaf.resourceresolver.IResourceResolver; -import org.thymeleaf.templateresolver.TemplateResolver; +import org.thymeleaf.IEngineConfiguration; +import org.thymeleaf.templateresolver.FileTemplateResolver; +import org.thymeleaf.templateresource.ITemplateResource; +import org.thymeleaf.templateresource.StringTemplateResource; -import java.io.*; -import java.nio.charset.StandardCharsets; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringWriter; import java.util.Map; import static org.asciidoctor.Asciidoctor.Factory.create; @@ -57,7 +60,7 @@ import static org.asciidoctor.Asciidoctor.Factory.create; * */ @Slf4j -public class AsciiDoctorTemplateResolver extends TemplateResolver { +public class AsciiDoctorTemplateResolver extends FileTemplateResolver { private static final Asciidoctor asciidoctor = create(); private static final String PREFIX = "doc:"; @@ -65,72 +68,56 @@ public class AsciiDoctorTemplateResolver extends TemplateResolver { public AsciiDoctorTemplateResolver(Language language) { this.language = language; - - setResourceResolver(new AdocResourceResolver()); setResolvablePatterns(Sets.newHashSet(PREFIX + "*")); } @Override - protected String computeResourceName(TemplateProcessingParameters params) { - String templateName = params.getTemplateName(); - return templateName.substring(PREFIX.length()); - } - - private class AdocResourceResolver implements IResourceResolver { - - @Override - public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) { - try (InputStream is = readInputStreamOrFallbackToEnglish(resourceName, language)) { - if (is == null) { - log.warn("Resource name: {} not found, did you add the adoc file?", resourceName); - return new ByteArrayInputStream(new byte[0]); - } else { - StringWriter writer = new StringWriter(); - JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry(); - extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class); - extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class); - extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class); - - asciidoctor.convert(new InputStreamReader(is), writer, createAttributes()); - return new ByteArrayInputStream(writer.getBuffer().toString().getBytes(StandardCharsets.UTF_8)); - } - } catch (IOException e) { - //no html yet - return new ByteArrayInputStream(new byte[0]); - } - } - - /** - * The resource name is for example HttpBasics_content1.adoc. This is always located in the following directory: - * plugin/HttpBasics/lessonPlans/en/HttpBasics_content1.adoc - */ - private String computeResourceName(String resourceName, String language) { - return String.format("lessonPlans/%s/%s", language, resourceName); - } - - private InputStream readInputStreamOrFallbackToEnglish(String resourceName, Language language) { - InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName, language.getLocale().getLanguage())); + protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map templateResolutionAttributes) { + var templateName = resourceName.substring(PREFIX.length()); + try (InputStream is = readInputStreamOrFallbackToEnglish(templateName, language)) { if (is == null) { - is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName, "en")); + log.warn("Resource name: {} not found, did you add the adoc file?", templateName); + return new StringTemplateResource(""); + } else { + StringWriter writer = new StringWriter(); + JavaExtensionRegistry extensionRegistry = asciidoctor.javaExtensionRegistry(); + extensionRegistry.inlineMacro("webWolfLink", WebWolfMacro.class); + extensionRegistry.inlineMacro("webWolfRootLink", WebWolfRootMacro.class); + extensionRegistry.inlineMacro("webGoatVersion", WebGoatVersionMacro.class); + + asciidoctor.convert(new InputStreamReader(is), writer, createAttributes()); + return new StringTemplateResource(writer.getBuffer().toString()); } - return is; - } - - private Map createAttributes() { - Map attributes = Maps.newHashMap(); - attributes.put("source-highlighter", "coderay"); - attributes.put("backend", "xhtml"); - - Map options = Maps.newHashMap(); - options.put("attributes", attributes); - - return options; - } - - @Override - public String getName() { - return "adocResourceResolver"; + } catch (IOException e) { + //no html yet + return new StringTemplateResource(""); } } + /** + * The resource name is for example HttpBasics_content1.adoc. This is always located in the following directory: + * plugin/HttpBasics/lessonPlans/en/HttpBasics_content1.adoc + */ + private String computeResourceName(String resourceName, String language) { + return String.format("lessonPlans/%s/%s", language, resourceName); + } + + private InputStream readInputStreamOrFallbackToEnglish(String resourceName, Language language) { + InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName, language.getLocale().getLanguage())); + if (is == null) { + is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName, "en")); + } + return is; + } + + private Map createAttributes() { + Map attributes = Maps.newHashMap(); + attributes.put("source-highlighter", "coderay"); + attributes.put("backend", "xhtml"); + + Map options = Maps.newHashMap(); + options.put("attributes", attributes); + + return options; + } } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/LessonTemplateResolver.java b/webgoat-container/src/main/java/org/owasp/webgoat/LessonTemplateResolver.java index 14e983a81..c035c58a3 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/LessonTemplateResolver.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/LessonTemplateResolver.java @@ -1,47 +1,46 @@ /** - ************************************************************************************************* - * - * + * ************************************************************************************************ + *

+ *

* This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ - * + *

* Copyright (c) 2002 - 20014 Bruce Mayhew - * + *

* This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + *

* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + *

* You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. - * + *

* Getting Source ============== - * + *

* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software * projects. * * @author WebGoat - * @since October 28, 2003 * @version $Id: $Id + * @since October 28, 2003 */ package org.owasp.webgoat; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.io.ByteStreams; -import lombok.SneakyThrows; import org.springframework.core.io.ResourceLoader; -import org.thymeleaf.TemplateProcessingParameters; -import org.thymeleaf.resourceresolver.IResourceResolver; -import org.thymeleaf.templateresolver.TemplateResolver; +import org.thymeleaf.IEngineConfiguration; +import org.thymeleaf.templateresolver.FileTemplateResolver; +import org.thymeleaf.templateresource.ITemplateResource; +import org.thymeleaf.templateresource.StringTemplateResource; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.InputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Map; /** @@ -53,42 +52,29 @@ import java.util.Map; * * Thymeleaf will invoke this resolver based on the prefix and this implementation will resolve the html in the plugins directory */ -public class LessonTemplateResolver extends TemplateResolver { +public class LessonTemplateResolver extends FileTemplateResolver { private final static String PREFIX = "lesson:"; - private final File pluginTargetDirectory; private ResourceLoader resourceLoader; private Map resources = Maps.newHashMap(); - public LessonTemplateResolver(File pluginTargetDirectory, ResourceLoader resourceLoader) { - this.pluginTargetDirectory = pluginTargetDirectory; + public LessonTemplateResolver(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; - setResourceResolver(new LessonResourceResolver()); setResolvablePatterns(Sets.newHashSet(PREFIX + "*")); } @Override - protected String computeResourceName(TemplateProcessingParameters params) { - String templateName = params.getTemplateName(); - return templateName.substring(PREFIX.length()); - } - - private class LessonResourceResolver implements IResourceResolver { - - @Override - @SneakyThrows - public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) { - byte[] resource = resources.get(resourceName); - if (resource == null) { - resource = ByteStreams.toByteArray(resourceLoader.getResource("classpath:/html/" + resourceName + ".html").getInputStream()); - resources.put(resourceName, resource); + protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate, String template, String resourceName, String characterEncoding, Map templateResolutionAttributes) { + var templateName = resourceName.substring(PREFIX.length());; + byte[] resource = resources.get(templateName); + if (resource == null) { + try { + resource = ByteStreams.toByteArray(resourceLoader.getResource("classpath:/html/" + templateName + ".html").getInputStream()); + } catch (IOException e) { + e.printStackTrace(); } - return new ByteArrayInputStream(resource); - } - - @Override - public String getName() { - return "lessonResourceResolver"; + resources.put(resourceName, resource); } + return new StringTemplateResource(new String(resource, StandardCharsets.UTF_8)); } -} +} \ No newline at end of file diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/MvcConfiguration.java b/webgoat-container/src/main/java/org/owasp/webgoat/MvcConfiguration.java index e26aa0b5e..0e2aac9f6 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/MvcConfiguration.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/MvcConfiguration.java @@ -30,41 +30,38 @@ */ package org.owasp.webgoat; -import com.google.common.collect.Sets; import org.owasp.webgoat.i18n.Language; import org.owasp.webgoat.i18n.Messages; import org.owasp.webgoat.i18n.PluginMessages; import org.owasp.webgoat.session.LabelDebugger; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ResourceLoader; import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.i18n.SessionLocaleResolver; -import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect; -import org.thymeleaf.spring4.SpringTemplateEngine; -import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver; -import org.thymeleaf.templateresolver.TemplateResolver; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.extras.springsecurity5.dialect.SpringSecurityDialect; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring5.view.ThymeleafViewResolver; +import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.templateresolver.ITemplateResolver; -import java.io.File; +import java.util.Set; /** * Configuration for Spring MVC */ @Configuration -public class MvcConfiguration extends WebMvcConfigurerAdapter { +public class MvcConfiguration implements WebMvcConfigurer { private static final String UTF8 = "UTF-8"; - @Autowired - @Qualifier("pluginTargetDirectory") - private File pluginTargetDirectory; - @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); @@ -74,13 +71,21 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter { //registry.addViewController("/list_users").setViewName("list_users"); } + @Bean + public ViewResolver viewResolver(SpringTemplateEngine thymeleafTemplateEngine) { + ThymeleafViewResolver resolver = new ThymeleafViewResolver(); + resolver.setTemplateEngine(thymeleafTemplateEngine); + resolver.setCharacterEncoding("UTF-8"); + return resolver; + } @Bean - public TemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) { + public ITemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) { SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); resolver.setPrefix("classpath:/templates/"); resolver.setSuffix(".html"); - resolver.setOrder(1); + resolver.setTemplateMode(TemplateMode.HTML); + resolver.setOrder(2); resolver.setCacheable(false); resolver.setCharacterEncoding(UTF8); resolver.setApplicationContext(applicationContext); @@ -89,8 +94,8 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter { @Bean public LessonTemplateResolver lessonTemplateResolver(ResourceLoader resourceLoader) { - LessonTemplateResolver resolver = new LessonTemplateResolver(pluginTargetDirectory, resourceLoader); - resolver.setOrder(2); + LessonTemplateResolver resolver = new LessonTemplateResolver(resourceLoader); + resolver.setOrder(0); resolver.setCacheable(false); resolver.setCharacterEncoding(UTF8); return resolver; @@ -100,19 +105,20 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter { public AsciiDoctorTemplateResolver asciiDoctorTemplateResolver(Language language) { AsciiDoctorTemplateResolver resolver = new AsciiDoctorTemplateResolver(language); resolver.setCacheable(false); - resolver.setOrder(3); + resolver.setOrder(1); resolver.setCharacterEncoding(UTF8); return resolver; } @Bean - public SpringTemplateEngine thymeleafTemplateEngine(TemplateResolver springThymeleafTemplateResolver, + public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver springThymeleafTemplateResolver, LessonTemplateResolver lessonTemplateResolver, AsciiDoctorTemplateResolver asciiDoctorTemplateResolver) { SpringTemplateEngine engine = new SpringTemplateEngine(); + engine.setEnableSpringELCompiler(true); engine.addDialect(new SpringSecurityDialect()); engine.setTemplateResolvers( - Sets.newHashSet(springThymeleafTemplateResolver, lessonTemplateResolver, asciiDoctorTemplateResolver)); + Set.of(lessonTemplateResolver, asciiDoctorTemplateResolver, springThymeleafTemplateResolver)); return engine; } @@ -123,12 +129,10 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter { */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.addResourceHandler("/plugin_lessons/**").addResourceLocations("file:///" + pluginTargetDirectory.toString() + "/"); registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/"); registry.addResourceHandler("/lesson_js/**").addResourceLocations("classpath:/js/"); registry.addResourceHandler("/lesson_css/**").addResourceLocations("classpath:/css/"); registry.addResourceHandler("/video/**").addResourceLocations("classpath:/video/"); - super.addResourceHandlers(registry); } @Bean diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/WebGoat.java b/webgoat-container/src/main/java/org/owasp/webgoat/WebGoat.java index 21838d192..dc0f8bb69 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/WebGoat.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/WebGoat.java @@ -30,15 +30,11 @@ */ package org.owasp.webgoat; -import org.owasp.webgoat.plugins.PluginEndpointPublisher; -import org.owasp.webgoat.plugins.PluginsLoader; -import org.owasp.webgoat.session.Course; import org.owasp.webgoat.session.UserSessionData; import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.session.WebgoatContext; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.ScopedProxyMode; @@ -66,16 +62,6 @@ public class WebGoat { return new UserSessionData("test", "data"); } - @Bean - public PluginEndpointPublisher pluginEndpointPublisher(ApplicationContext applicationContext) { - return new PluginEndpointPublisher(applicationContext); - } - - @Bean - public Course course(PluginEndpointPublisher pluginEndpointPublisher) { - return new PluginsLoader(pluginEndpointPublisher).loadPlugins(); - } - @Bean public RestTemplate restTemplate() { return new RestTemplate(); diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java b/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java index b8b526af8..07ea29f1e 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java @@ -35,6 +35,7 @@ import org.owasp.webgoat.users.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; @@ -42,6 +43,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; /** * Security configuration for WebGoat. @@ -90,4 +92,16 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { public UserDetailsService userDetailsServiceBean() throws Exception { return userDetailsService; } + + @Override + @Bean + protected AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } + + @SuppressWarnings("deprecation") + @Bean + public NoOpPasswordEncoder passwordEncoder() { + return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); + } } \ No newline at end of file diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentEndpoint.java b/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentEndpoint.java index 3b02b6129..15b9415c0 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentEndpoint.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentEndpoint.java @@ -27,33 +27,23 @@ package org.owasp.webgoat.assignments; import lombok.Getter; import org.owasp.webgoat.i18n.PluginMessages; import org.owasp.webgoat.session.UserSessionData; +import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.users.UserTracker; import org.owasp.webgoat.users.UserTrackerRepository; -import org.owasp.webgoat.session.WebSession; import org.springframework.beans.factory.annotation.Autowired; -/** - * Each lesson can define an endpoint which can support the lesson. So for example if you create a lesson which uses JavaScript and - * needs to call out to the server to fetch data you can define an endpoint in that lesson. WebGoat will pick up this endpoint and - * Spring will publish it. - *

- * Extend this class and implement the met - *

- * Note: each subclass should declare this annotation otherwise the WebGoat framework cannot find your endpoint. - */ -public abstract class AssignmentEndpoint extends Endpoint { +public abstract class AssignmentEndpoint { @Autowired private UserTrackerRepository userTrackerRepository; @Autowired - private WebSession webSession; + private WebSession webSession; @Autowired private UserSessionData userSessionData; @Getter @Autowired private PluginMessages messages; - //// TODO: 11/13/2016 events better fit? protected AttackResult trackProgress(AttackResult attackResult) { UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); if (userTracker == null) { @@ -67,26 +57,21 @@ public abstract class AssignmentEndpoint extends Endpoint { userTrackerRepository.save(userTracker); return attackResult; } - - protected WebSession getWebSession() { - return webSession; - } - protected UserSessionData getUserSessionData() { - return userSessionData; + protected WebSession getWebSession() { + return webSession; } - @Override - public final String getPath() { - return this.getClass().getAnnotationsByType(AssignmentPath.class)[0].value(); + protected UserSessionData getUserSessionData() { + return userSessionData; } /** * Convenience method for create a successful result: - * + *

* - Assignment is set to solved * - Feedback message is set to 'assignment.solved' - * + *

* Of course you can overwrite these values in a specific lesson * * @return a builder for creating a result from a lesson @@ -97,10 +82,10 @@ public abstract class AssignmentEndpoint extends Endpoint { /** * Convenience method for create a failed result: - * + *

* - Assignment is set to not solved * - Feedback message is set to 'assignment.not.solved' - * + *

* Of course you can overwrite these values in a specific lesson * * @return a builder for creating a result from a lesson diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentPath.java b/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentPath.java index 9147a1820..25336aa44 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentPath.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/assignments/AssignmentPath.java @@ -1,5 +1,9 @@ package org.owasp.webgoat.assignments; +import org.springframework.core.annotation.AliasFor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -10,7 +14,15 @@ import java.lang.annotation.Target; */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) +//@RequestMapping public @interface AssignmentPath { - String value(); + // @AliasFor(annotation = RequestMapping.class) + String[] path() default {}; + + // @AliasFor(annotation = RequestMapping.class) + RequestMethod[] method() default {}; + + // @AliasFor("path") + String value() default ""; } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/controller/StartLesson.java b/webgoat-container/src/main/java/org/owasp/webgoat/controller/StartLesson.java index 28d0524fb..06efc9c0f 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/controller/StartLesson.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/controller/StartLesson.java @@ -30,7 +30,7 @@ */ package org.owasp.webgoat.controller; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.session.Course; import org.owasp.webgoat.session.WebSession; import org.springframework.security.core.context.SecurityContext; @@ -79,8 +79,8 @@ public class StartLesson { //GrantedAuthority authority = context.getAuthentication().getAuthorities().iterator().next(); String path = request.getRequestURL().toString(); // we now got /a/b/c/AccessControlMatrix.lesson String lessonName = path.substring(path.lastIndexOf('/') + 1, path.indexOf(".lesson")); - List lessons = course.getLessons(); - Optional lesson = lessons.stream() + List lessons = course.getLessons(); + Optional lesson = lessons.stream() .filter(l -> l.getId().equals(lessonName)) .findFirst(); ws.setCurrentLesson(lesson.get()); diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Assignment.java b/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Assignment.java index d9b1f3470..fc44ab734 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Assignment.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Assignment.java @@ -52,11 +52,14 @@ public class Assignment { //Hibernate } - public Assignment(String name, String path) { - this(name, path, Lists.newArrayList()); + public Assignment(String name) { + this(name, name, Lists.newArrayList()); } public Assignment(String name, String path, List 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; diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Hint.java b/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Hint.java index 2f3363d9b..f2a1fa4b0 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Hint.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Hint.java @@ -26,8 +26,7 @@ */ package org.owasp.webgoat.lessons; -import lombok.Getter; -import lombok.Setter; +import lombok.Value; /** *

Hint class.

@@ -35,12 +34,9 @@ import lombok.Setter; * @author rlawson * @version $Id: $Id */ -@Getter -@Setter +@Value public class Hint { private String hint; - private String lesson; private String assignmentPath; - private int number; } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/lessons/AbstractLesson.java b/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Lesson.java similarity index 56% rename from webgoat-container/src/main/java/org/owasp/webgoat/lessons/AbstractLesson.java rename to webgoat-container/src/main/java/org/owasp/webgoat/lessons/Lesson.java index 16eca3f45..80828deb8 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/lessons/AbstractLesson.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/lessons/Lesson.java @@ -1,63 +1,45 @@ -package org.owasp.webgoat.lessons; - -import com.google.common.collect.Lists; -import lombok.Setter; -import org.owasp.webgoat.session.Screen; - -import java.util.List; - -/** - * ************************************************************************************************ - *

- *

- * This file is part of WebGoat, an Open Web Application Security Project utility. For details, - * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 20014 Bruce Mayhew - *

+/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 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. * - * @author Bruce Mayhew WebGoat - * @version $Id: $Id - * @since October 28, 2003 + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. */ -public abstract class AbstractLesson extends Screen implements Comparable { + +package org.owasp.webgoat.lessons; + +import lombok.Getter; +import lombok.Setter; +import lombok.Singular; + +import java.util.List; + +@Getter +@Setter +public abstract class Lesson { private static int count = 1; - private Integer id = null; - - private Integer ranking; - - @Setter private List assignments; - public List getAssignments() { - if (assignments == null) { - return Lists.newArrayList(); - } - return assignments; - } - /** * Constructor for the Lesson object */ - public AbstractLesson() { + public Lesson() { id = ++count; } @@ -72,34 +54,6 @@ public abstract class AbstractLesson extends Screen implements ComparableSetter for the field ranking.

- * - * @param ranking a {@link java.lang.Integer} object. - */ - public void setRanking(Integer ranking) { - this.ranking = ranking; - } - - - /** - * {@inheritDoc} - *

- * Description of the Method - */ - public int compareTo(Object obj) { - return this.getRanking().compareTo(((AbstractLesson) obj).getRanking()); - } - - /** - * {@inheritDoc} - *

- * Description of the Method - */ - public boolean equals(Object obj) { - return this.getScreenId() == ((AbstractLesson) obj).getScreenId(); - } - /** * Gets the category attribute of the Lesson object * @@ -109,13 +63,6 @@ public abstract class AbstractLesson extends Screen implements ComparablegetDefaultRanking.

- * - * @return a {@link java.lang.Integer} object. - */ - protected abstract Integer getDefaultRanking(); - /** *

getDefaultCategory.

* @@ -123,29 +70,6 @@ public abstract class AbstractLesson extends Screen implements ComparablegetDefaultHidden.

- * - * @return a boolean. - */ - protected abstract boolean getDefaultHidden(); - - /** - * Gets the hintCount attribute of the Lesson object - * - * @return The hintCount value - */ - public int getHintCount() { - return getHints().size(); - } - - /** - *

getHints.

- * - * @return a {@link java.util.List} object. - */ - public abstract List getHints(); - /** * Gets the title attribute of the HelloScreen object * @@ -153,28 +77,6 @@ public abstract class AbstractLesson extends Screen implements ComparableReturns the default "path" portion of a lesson's URL.

*

@@ -218,5 +120,4 @@ public abstract class AbstractLesson extends Screen implements ComparableWebGoat - * @since October 28, 2003 - * @version $Id: $Id - */ -package org.owasp.webgoat.lessons; - -//// TODO: 11/8/2016 remove -public abstract class LessonAdapter extends AbstractLesson { - - - /** - *

getDefaultHidden.

- * - * @return a boolean. - */ - protected boolean getDefaultHidden() { - return false; - } - - /** - * Initiates lesson restart functionality. Lessons should override this for - * lesson specific actions - */ - public void restartLesson() { - // Do Nothing - called when restart lesson is pressed. Each lesson can do something - } - - private final static Integer DEFAULT_RANKING = 1000; - - /** - *

getDefaultRanking.

- * - * @return a {@link java.lang.Integer} object. - */ - protected Integer getDefaultRanking() { - return DEFAULT_RANKING; - } - - /** - * provide a default submitMethod of lesson does not implement - * - * @return a {@link java.lang.String} object. - */ - public String getSubmitMethod() { - return "GET"; - } - - /** - * Fill in a descriptive title for this lesson. The title of the lesson. - * This will appear above the control area at the top of the page. This - * field will be rendered as html. - * - * @return The title value - */ - public String getTitle() { - return "Untitled Lesson " + getScreenId(); - } - - -} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/CourseConfiguration.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/CourseConfiguration.java new file mode 100644 index 000000000..36bdf1305 --- /dev/null +++ b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/CourseConfiguration.java @@ -0,0 +1,117 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 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.plugins; + +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ArrayUtils; +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.lessons.Lesson; +import org.owasp.webgoat.lessons.Assignment; +import org.owasp.webgoat.session.Course; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.GetMapping; +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.util.Arrays; +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.toList; + +@Slf4j +@Configuration +public class CourseConfiguration { + + private final List lessons; + private final List assignments; + private final Map> assignmentsByPackage; + + public CourseConfiguration(List lessons, List 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); + } + + private List 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 Lists.newArrayList(); + } + return endpoints.stream().map(e -> new Assignment(e.getClass().getSimpleName(), getPath(e.getClass()), getHints(e.getClass()))).collect(toList()); + } + + private String getPath(Class e) { + for (Method m : e.getMethods()) { + if (m.getReturnType() == AttackResult.class) { + var mapping = getMapping(m); + if (mapping == null) { + log.error("AttackResult method found without mapping in: {}", e.getSimpleName()); + } else { + return mapping; + } + } + } + return "none"; + } + + 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 ""; + } else { + return Arrays.stream(paths).filter(path -> !"".equals(path)).findFirst().orElseGet(() -> ""); + } + } + + private List getHints(Class e) { + if (e.isAnnotationPresent(AssignmentHints.class)) { + return Lists.newArrayList(e.getAnnotationsByType(AssignmentHints.class)[0].value()); + } + return Lists.newArrayList(); + } +} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginEndpointPublisher.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginEndpointPublisher.java deleted file mode 100644 index d3a2a333e..000000000 --- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginEndpointPublisher.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.owasp.webgoat.plugins; - -import lombok.extern.slf4j.Slf4j; -import org.owasp.webgoat.assignments.Endpoint; -import org.springframework.beans.factory.annotation.Autowire; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.AbstractApplicationContext; - -import java.util.List; - -/** - * ************************************************************************************************ - * This file is part of WebGoat, an Open Web Application Security Project utility. For details, - * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 20014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if - * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. - *

- * - * @author nbaars - * @version $Id: $Id - * @since October 16, 2016 - */ -@Slf4j -public class PluginEndpointPublisher { - - private AbstractApplicationContext applicationContext; - - public PluginEndpointPublisher(ApplicationContext applicationContext) { - this.applicationContext = (AbstractApplicationContext) applicationContext; - } - - public void publish(List> endpoints) { - endpoints.forEach(e -> publishEndpoint(e)); - } - - private void publishEndpoint(Class e) { - try { - BeanDefinition beanDefinition = new RootBeanDefinition(e, Autowire.BY_TYPE.value(), true); - DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); - beanFactory.registerBeanDefinition(beanDefinition.getBeanClassName(), beanDefinition); - } catch (Exception ex) { - log.error("Failed to register " + e.getSimpleName() + " as endpoint with Spring, skipping..."); - } - } -} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginResource.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginResource.java deleted file mode 100644 index 172b7b965..000000000 --- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginResource.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.owasp.webgoat.plugins; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.owasp.webgoat.assignments.AssignmentEndpoint; -import org.owasp.webgoat.assignments.Endpoint; -import org.owasp.webgoat.lessons.NewLesson; - -import java.net.URL; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Plugin resource - * - * @author nbaars - * @since 3/4/17. - */ -@AllArgsConstructor -@Getter -public class PluginResource { - - private final URL location; - private final List classes; - - public List getLessons() { - return classes.stream().filter(c -> c.getSuperclass() == NewLesson.class).collect(Collectors.toList()); - } - - public List> getEndpoints() { - return classes.stream(). - filter(c -> c.getSuperclass() == AssignmentEndpoint.class || c.getSuperclass() == Endpoint.class). - map(c -> (Class) c). - collect(Collectors.toList()); - } - - public List> getAssignments(Class lesson) { - return classes.stream(). - filter(c -> c.getSuperclass() == AssignmentEndpoint.class). - filter(c -> c.getPackage().equals(lesson.getPackage())). - map(c -> (Class) c). - collect(Collectors.toList()); - } - - -} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java deleted file mode 100644 index 28437e786..000000000 --- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.owasp.webgoat.plugins; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import lombok.AllArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; -import org.owasp.webgoat.assignments.AssignmentEndpoint; -import org.owasp.webgoat.assignments.AssignmentHints; -import org.owasp.webgoat.assignments.AssignmentPath; -import org.owasp.webgoat.lessons.AbstractLesson; -import org.owasp.webgoat.lessons.Assignment; -import org.owasp.webgoat.lessons.NewLesson; -import org.owasp.webgoat.session.Course; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.type.filter.RegexPatternTypeFilter; - -import java.net.URL; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static java.util.stream.Collectors.toList; - -/** - * ************************************************************************************************ - * This file is part of WebGoat, an Open Web Application Security Project utility. For details, - * please see http://www.owasp.org/ - *

- * Copyright (c) 2002 - 20014 Bruce Mayhew - *

- * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - *

- * You should have received a copy of the GNU General Public License along with this program; if - * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - *

- * Getting Source ============== - *

- * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software - * projects. - *

- * - * @author nbaars - * @version $Id: $Id - * @since November 25, 2016 - */ -@AllArgsConstructor -@Slf4j -public class PluginsLoader { - - private final PluginEndpointPublisher pluginEndpointPublisher; - - /** - *

createLessonsFromPlugins.

- */ - public Course loadPlugins() { - List lessons = Lists.newArrayList(); - for (PluginResource plugin : findPluginResources()) { - try { - plugin.getLessons().forEach(c -> { - NewLesson lesson = null; - try { - lesson = (NewLesson) c.newInstance(); - log.trace("Lesson loaded: {}", lesson.getId()); - } catch (Exception e) { - log.error("Error while loading:" + c, e); - } - List> assignments = plugin.getAssignments(c); - lesson.setAssignments(createAssignment(assignments)); - lessons.add(lesson); - pluginEndpointPublisher.publish(plugin.getEndpoints()); - }); - } catch (Exception e) { - log.error("Error in loadLessons: ", e); - } - } - if (lessons.isEmpty()) { - log.error("No lessons found if you downloaded an official release of WebGoat please take the time to"); - log.error("create a new issue at https://github.com/WebGoat/WebGoat/issues/new"); - log.error("For developers run 'mvn package' first from the root directory."); - } - return new Course(lessons); - } - - private List createAssignment(List> endpoints) { - return endpoints.stream().map(e -> new Assignment(e.getSimpleName(), getPath(e), getHints(e))).collect(toList()); - } - - private String getPath(Class e) { - return e.getAnnotationsByType(AssignmentPath.class)[0].value(); - } - - private List getHints(Class e) { - if (e.isAnnotationPresent(AssignmentHints.class)) { - return Lists.newArrayList(e.getAnnotationsByType(AssignmentHints.class)[0].value()); - } - return Lists.newArrayList(); - } - - - - @SneakyThrows - public List findPluginResources() { - final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); - provider.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile(".*"))); - final Set classes = provider.findCandidateComponents("org.owasp.webgoat.plugin"); - Map> pluginClasses = Maps.newHashMap(); - for (BeanDefinition bean : classes) { - Class clazz = Class.forName(bean.getBeanClassName()); - URL location = clazz.getProtectionDomain().getCodeSource().getLocation(); - List classFiles = pluginClasses.get(location); - if (classFiles == null) { - classFiles = Lists.newArrayList(clazz); - } else { - classFiles.add(clazz); - } - pluginClasses.put(location, classFiles); - } - return pluginClasses.entrySet().parallelStream() - .map(e -> new PluginResource(e.getKey(), e.getValue())) - .collect(Collectors.toList()); - } - -} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/service/HintService.java b/webgoat-container/src/main/java/org/owasp/webgoat/service/HintService.java index f6d290aed..b0743f865 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/service/HintService.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/service/HintService.java @@ -5,10 +5,9 @@ */ package org.owasp.webgoat.service; -import com.google.common.collect.Lists; -import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.Assignment; import org.owasp.webgoat.lessons.Hint; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.session.WebSession; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; @@ -41,42 +40,22 @@ public class HintService { */ @GetMapping(path = URL_HINTS_MVC, produces = "application/json") @ResponseBody - public List showHint() { - AbstractLesson l = webSession.getCurrentLesson(); - List hints = createLessonHints(l); - hints.addAll(createAssignmentHints(l)); - return hints; - + public List getHints() { + Lesson l = webSession.getCurrentLesson(); + return createAssignmentHints(l); } - private List createLessonHints(AbstractLesson l) { - if ( l != null ) { - return l.getHints().stream().map(h -> createHint(h, l.getName(), null)).collect(toList()); + private List createAssignmentHints(Lesson l) { + if (l != null) { + return l.getAssignments().stream() + .map(a -> createHint(a)) + .flatMap(hints -> hints.stream()) + .collect(toList()); } - return Lists.newArrayList(); + return List.of(); } - private List createAssignmentHints(AbstractLesson l) { - List hints = Lists.newArrayList(); - if ( l != null) { - List assignments = l.getAssignments(); - assignments.stream().forEach(a -> { a.getHints(); createHints(a, hints);}); - } - return hints; - } - - private void createHints(Assignment a, List hints) { - hints.addAll(a.getHints().stream().map(h -> createHint(h, null, a.getPath())).collect(toList())); - } - - private Hint createHint(String hintText, String lesson, String assignmentName) { - Hint hint = new Hint(); - hint.setHint(hintText); - if (lesson != null) { - hint.setLesson(lesson); - } else { - hint.setAssignmentPath(assignmentName); - } - return hint; + private List createHint(Assignment a) { + return a.getHints().stream().map(h -> new Hint(h, a.getPath())).collect(toList()); } } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonInfoService.java b/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonInfoService.java index 927868f3e..9396e0225 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonInfoService.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonInfoService.java @@ -1,7 +1,7 @@ package org.owasp.webgoat.service; import lombok.AllArgsConstructor; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.LessonInfoModel; import org.owasp.webgoat.session.WebSession; import org.springframework.web.bind.annotation.RequestMapping; @@ -29,7 +29,7 @@ public class LessonInfoService { @RequestMapping(path = "/service/lessoninfo.mvc", produces = "application/json") public @ResponseBody LessonInfoModel getLessonInfo() { - AbstractLesson lesson = webSession.getCurrentLesson(); + Lesson lesson = webSession.getCurrentLesson(); return new LessonInfoModel(lesson.getTitle(), false, false, false); } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonMenuService.java b/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonMenuService.java index 25b1e617e..62864d562 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonMenuService.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonMenuService.java @@ -29,7 +29,7 @@ package org.owasp.webgoat.service; import lombok.AllArgsConstructor; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Category; import org.owasp.webgoat.lessons.LessonMenuItem; import org.owasp.webgoat.lessons.LessonMenuItemType; @@ -43,7 +43,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -81,13 +80,12 @@ public class LessonMenuService { categoryItem.setName(category.getName()); categoryItem.setType(LessonMenuItemType.CATEGORY); // check for any lessons for this category - List lessons = course.getLessons(category); + List lessons = course.getLessons(category); lessons = lessons.stream().sorted(Comparator.comparing(l -> l.getTitle())).collect(Collectors.toList()); - for (AbstractLesson lesson : lessons) { + for (Lesson lesson : lessons) { LessonMenuItem lessonItem = new LessonMenuItem(); lessonItem.setName(lesson.getTitle()); lessonItem.setLink(lesson.getLink()); - lessonItem.setRanking(lesson.getRanking()); lessonItem.setType(LessonMenuItemType.LESSON); LessonTracker lessonTracker = userTracker.getLessonTracker(lesson); lessonItem.setComplete(lessonTracker.isLessonSolved()); diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonProgressService.java b/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonProgressService.java index 76e6187a5..52b02542e 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonProgressService.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonProgressService.java @@ -4,7 +4,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import lombok.AllArgsConstructor; import lombok.Getter; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Assignment; import org.owasp.webgoat.lessons.LessonInfoModel; import org.owasp.webgoat.session.WebSession; @@ -66,7 +66,7 @@ public class LessonProgressService { @ResponseBody public List lessonOverview() { UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); - AbstractLesson currentLesson = webSession.getCurrentLesson(); + Lesson currentLesson = webSession.getCurrentLesson(); List result = Lists.newArrayList(); if ( currentLesson != null ) { LessonTracker lessonTracker = userTracker.getLessonTracker(currentLesson); @@ -76,7 +76,7 @@ public class LessonProgressService { } private List toJson(Map map) { - ArrayList result = Lists.newArrayList(); + List result = new ArrayList(); for (Map.Entry entry : map.entrySet()) { result.add(new LessonOverview(entry.getKey(), entry.getValue())); } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonTitleService.java b/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonTitleService.java index c3d7a82b5..40d4e9459 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonTitleService.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/service/LessonTitleService.java @@ -1,6 +1,6 @@ package org.owasp.webgoat.service; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.session.WebSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @@ -31,7 +31,7 @@ public class LessonTitleService { public @ResponseBody String showPlan() { - AbstractLesson lesson = webSession.getCurrentLesson(); + Lesson lesson = webSession.getCurrentLesson(); return lesson != null ? lesson.getTitle() : ""; } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/service/ReportCardService.java b/webgoat-container/src/main/java/org/owasp/webgoat/service/ReportCardService.java index 0337467b1..c382e2947 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/service/ReportCardService.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/service/ReportCardService.java @@ -33,7 +33,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import org.owasp.webgoat.i18n.PluginMessages; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.session.Course; import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.users.LessonTracker; @@ -67,13 +67,13 @@ public class ReportCardService { @ResponseBody public ReportCard reportCard() { UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); - List lessons = course.getLessons(); + var lessons = course.getLessons(); ReportCard reportCard = new ReportCard(); reportCard.setTotalNumberOfLessons(course.getTotalOfLessons()); reportCard.setTotalNumberOfAssignments(course.getTotalOfAssignments()); reportCard.setNumberOfAssignmentsSolved(userTracker.numberOfAssignmentsSolved()); reportCard.setNumberOfLessonsSolved(userTracker.numberOfLessonsSolved()); - for (AbstractLesson lesson : lessons) { + for (Lesson lesson : lessons) { LessonTracker lessonTracker = userTracker.getLessonTracker(lesson); LessonStatistics lessonStatistics = new LessonStatistics(); lessonStatistics.setName(pluginMessages.getMessage(lesson.getTitle())); diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/service/RestartLessonService.java b/webgoat-container/src/main/java/org/owasp/webgoat/service/RestartLessonService.java index b207b4ce1..b2f503f48 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/service/RestartLessonService.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/service/RestartLessonService.java @@ -25,7 +25,7 @@ package org.owasp.webgoat.service; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.users.UserTracker; import org.owasp.webgoat.users.UserTrackerRepository; @@ -56,7 +56,7 @@ public class RestartLessonService { @RequestMapping(path = "/service/restartlesson.mvc", produces = "text/text") @ResponseStatus(value = HttpStatus.OK) public void restartLesson() { - AbstractLesson al = webSession.getCurrentLesson(); + Lesson al = webSession.getCurrentLesson(); log.debug("Restarting lesson: " + al); UserTracker userTracker = userTrackerRepository.findByUser(webSession.getUserName()); diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/session/Course.java b/webgoat-container/src/main/java/org/owasp/webgoat/session/Course.java index 1098f4a65..b4ede6ed3 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/session/Course.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/session/Course.java @@ -1,11 +1,9 @@ package org.owasp.webgoat.session; -import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Category; -import java.util.LinkedList; import java.util.List; import static java.util.stream.Collectors.toList; @@ -41,10 +39,13 @@ import static java.util.stream.Collectors.toList; * @since October 28, 2003 */ @Slf4j -@AllArgsConstructor public class Course { - private List lessons = new LinkedList<>(); + private List lessons; + + public Course(List lessons) { + this.lessons = lessons; + } /** * Gets the categories attribute of the Course object @@ -60,7 +61,7 @@ public class Course { * * @return The firstLesson value */ - public AbstractLesson getFirstLesson() { + 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); @@ -71,7 +72,7 @@ public class Course { * * @return a {@link java.util.List} object. */ - public List getLessons() { + public List getLessons() { return this.lessons; } @@ -81,11 +82,11 @@ public class Course { * @param category a {@link org.owasp.webgoat.lessons.Category} object. * @return a {@link java.util.List} object. */ - public List getLessons(Category category) { - return this.lessons.stream().filter(l -> l.getCategory() == category).sorted().collect(toList()); + public List getLessons(Category category) { + return this.lessons.stream().filter(l -> l.getCategory() == category).collect(toList()); } - public void setLessons(List lessons) { + public void setLessons(List lessons) { this.lessons = lessons; } @@ -94,9 +95,6 @@ public class Course { } public int getTotalOfAssignments() { - final int[] total = {0}; - this.lessons.stream().forEach(l -> total[0] = total[0] + l.getAssignments().size()); - return total[0]; + return this.lessons.stream().reduce(0, (total, lesson) -> lesson.getAssignments().size() + total, Integer::sum); } - } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/session/Screen.java b/webgoat-container/src/main/java/org/owasp/webgoat/session/Screen.java deleted file mode 100644 index fae5c7fe7..000000000 --- a/webgoat-container/src/main/java/org/owasp/webgoat/session/Screen.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.owasp.webgoat.session; - -/** - * ************************************************************************************************* - * - * - * This file is part of WebGoat, an Open Web Application Security Project - * utility. For details, please see http://www.owasp.org/ - * - * Copyright (c) 2002 - 20014 Bruce Mayhew - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Getting Source ============== - * - * Source for this application is maintained at - * https://github.com/WebGoat/WebGoat, a repository for free software projects. - * - * @author Jeff Williams Aspect - * Security - * @since October 28, 2003 - * @version $Id: $Id - */ -public abstract class Screen { - - /** - * Constructor for the Screen object - */ - public Screen() { - } - - - /** - * Fill in a descriptive title for this lesson - * - * @return The title value - */ - public abstract String getTitle(); - - -} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/session/WebSession.java b/webgoat-container/src/main/java/org/owasp/webgoat/session/WebSession.java index 33196575a..b1088b377 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/session/WebSession.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/session/WebSession.java @@ -1,7 +1,7 @@ package org.owasp.webgoat.session; import lombok.extern.slf4j.Slf4j; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.users.WebGoatUser; import org.springframework.security.core.context.SecurityContextHolder; @@ -42,7 +42,7 @@ public class WebSession { private final WebGoatUser currentUser; private final WebgoatContext webgoatContext; - private AbstractLesson currentLesson; + private Lesson currentLesson; /** * Constructor for the WebSession object @@ -79,16 +79,16 @@ public class WebSession { * * @param lesson current lesson */ - public void setCurrentLesson(AbstractLesson lesson) { + public void setCurrentLesson(Lesson lesson) { this.currentLesson = lesson; } /** *

getCurrentLesson.

* - * @return a {@link org.owasp.webgoat.lessons.AbstractLesson} object. + * @return a {@link Lesson} object. */ - public AbstractLesson getCurrentLesson() { + public Lesson getCurrentLesson() { return this.currentLesson; } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/users/LessonTracker.java b/webgoat-container/src/main/java/org/owasp/webgoat/users/LessonTracker.java index 7d1d5d859..639b32e02 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/users/LessonTracker.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/users/LessonTracker.java @@ -1,10 +1,9 @@ package org.owasp.webgoat.users; -import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.Getter; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Assignment; import javax.persistence.*; @@ -64,9 +63,9 @@ public class LessonTracker { //JPA } - public LessonTracker(AbstractLesson lesson) { + public LessonTracker(Lesson lesson) { lessonName = lesson.getId(); - allAssignments.addAll(lesson.getAssignments()); + allAssignments.addAll(lesson.getAssignments() == null ? List.of() : lesson.getAssignments()); } public Optional getAssignment(String name) { diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/users/UserTracker.java b/webgoat-container/src/main/java/org/owasp/webgoat/users/UserTracker.java index 1cc4920ea..675650e2a 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/users/UserTracker.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/users/UserTracker.java @@ -1,14 +1,12 @@ package org.owasp.webgoat.users; -import com.google.common.collect.Lists; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; -import org.owasp.webgoat.lessons.AbstractLesson; +import org.owasp.webgoat.lessons.Lesson; import org.owasp.webgoat.lessons.Assignment; import javax.persistence.*; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -69,7 +67,7 @@ public class UserTracker { * @param lesson the lesson * @return a lesson tracker created if not already present */ - public LessonTracker getLessonTracker(AbstractLesson lesson) { + public LessonTracker getLessonTracker(Lesson lesson) { Optional lessonTracker = lessonTrackers .stream().filter(l -> l.getLessonName().equals(lesson.getId())).findFirst(); if (!lessonTracker.isPresent()) { @@ -91,18 +89,18 @@ public class UserTracker { return lessonTrackers.stream().filter(l -> l.getLessonName().equals(id)).findFirst(); } - public void assignmentSolved(AbstractLesson lesson, String assignmentName) { + public void assignmentSolved(Lesson lesson, String assignmentName) { LessonTracker lessonTracker = getLessonTracker(lesson); lessonTracker.incrementAttempts(); lessonTracker.assignmentSolved(assignmentName); } - public void assignmentFailed(AbstractLesson lesson) { + public void assignmentFailed(Lesson lesson) { LessonTracker lessonTracker = getLessonTracker(lesson); lessonTracker.incrementAttempts(); } - public void reset(AbstractLesson al) { + public void reset(Lesson al) { LessonTracker lessonTracker = getLessonTracker(al); lessonTracker.reset(); } diff --git a/webgoat-container/src/main/resources/application-webgoat.properties b/webgoat-container/src/main/resources/application-webgoat.properties index c5665ba79..3eb7b0474 100644 --- a/webgoat-container/src/main/resources/application-webgoat.properties +++ b/webgoat-container/src/main/resources/application-webgoat.properties @@ -1,7 +1,7 @@ server.error.include-stacktrace=always server.error.path=/error.html server.session.timeout=600 -server.contextPath=/WebGoat +server.servlet.context-path=/WebGoat server.port=${WEBGOAT_PORT:8080} server.address=${WEBGOAT_HOST:127.0.0.1} @@ -18,6 +18,11 @@ spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.HSQLDialect spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver +logging.level.org.thymeleaf=DEBUG +logging.level.org.thymeleaf.TemplateEngine.CONFIG=TRACE +logging.level.org.thymeleaf.TemplateEngine.TIMER=TRACE +logging.level.org.thymeleaf.TemplateEngine.cache.TEMPLATE_CACHE=TRACE +logging.level.org.springframework.web=TRACE logging.level.org.springframework=INFO logging.level.org.springframework.boot.devtools=INFO logging.level.org.owasp=DEBUG @@ -26,7 +31,6 @@ logging.level.org.owasp.webgoat=TRACE # Needed for creating a vulnerable web application security.enable-csrf=false -spring.resources.cache-period=0 spring.thymeleaf.cache=false webgoat.start.hsqldb=true diff --git a/webgoat-container/src/main/resources/templates/main_new.html b/webgoat-container/src/main/resources/templates/main_new.html index eadb722c3..edde993ab 100644 --- a/webgoat-container/src/main/resources/templates/main_new.html +++ b/webgoat-container/src/main/resources/templates/main_new.html @@ -28,15 +28,15 @@ - - WebGoat @@ -67,8 +67,7 @@
  • Logout
  • -