Endpoints provided by lessons now work
This commit is contained in:
parent
79102c6ddd
commit
4a19ddf40a
@ -210,6 +210,10 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.tomcat.embed</groupId>
|
<groupId>org.apache.tomcat.embed</groupId>
|
||||||
<artifactId>tomcat-embed-jasper</artifactId>
|
<artifactId>tomcat-embed-jasper</artifactId>
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package org.owasp.webgoat;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class Info {
|
|
||||||
|
|
||||||
public static class Information {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(name = "information")
|
|
||||||
public Information information() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,64 @@
|
|||||||
|
package org.owasp.webgoat;
|
||||||
|
|
||||||
|
import org.owasp.webgoat.lessons.LessonEndpointMapping;
|
||||||
|
import org.owasp.webgoat.plugins.PluginsLoader;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.ListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
|
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
|
||||||
|
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* <p/>
|
||||||
|
* Find all the defined endpoints in the lessons and register those endpoints in the Spring context so later on the
|
||||||
|
* Actuator will pick them up and expose them as real endpoints.
|
||||||
|
* <p/>
|
||||||
|
* We use the Actuator here so we don't have to do all the hard work ourselves (endpoint strategy pattern etc) so in a
|
||||||
|
* lesson you can just define a subclass of LessonEndpoint which this class will publish as an endpoint. So we can
|
||||||
|
* dynamically load endpoints from our plugins.
|
||||||
|
*/
|
||||||
|
public class LessonEndpointProvider {
|
||||||
|
|
||||||
|
private final String pluginBasePackage;
|
||||||
|
private final ApplicationContext parentContext;
|
||||||
|
private ListableBeanFactory context;
|
||||||
|
private DefaultListableBeanFactory providedBeans;
|
||||||
|
private BeanFactory beanFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public LessonEndpointProvider(String pluginBasePackage, ApplicationContext parentContext, BeanFactory beanFactory) {
|
||||||
|
this.pluginBasePackage = pluginBasePackage;
|
||||||
|
this.parentContext = parentContext;
|
||||||
|
this.providedBeans = new DefaultListableBeanFactory(this.parentContext.getParentBeanFactory());
|
||||||
|
this.beanFactory = beanFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerEndpoints() {
|
||||||
|
if (context == null) {
|
||||||
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||||
|
context.setParent(parentContext);
|
||||||
|
context.setClassLoader(PluginsLoader.classLoader);
|
||||||
|
|
||||||
|
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, false);
|
||||||
|
scanner.addIncludeFilter(new AnnotationTypeFilter(LessonEndpointMapping.class));
|
||||||
|
scanner.scan(pluginBasePackage);
|
||||||
|
context.refresh();
|
||||||
|
|
||||||
|
Map<String, MvcEndpoint> beansOfType = context.getBeansOfType(MvcEndpoint.class);
|
||||||
|
ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory;
|
||||||
|
beansOfType.forEach((k, v) -> {
|
||||||
|
configurableBeanFactory.registerSingleton(k, v);
|
||||||
|
});
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package org.owasp.webgoat;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import org.owasp.webgoat.session.WebSession;
|
||||||
|
import org.thymeleaf.TemplateProcessingParameters;
|
||||||
|
import org.thymeleaf.resourceresolver.IResourceResolver;
|
||||||
|
import org.thymeleaf.templateresolver.TemplateResolver;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LessonTemplateResolver extends TemplateResolver {
|
||||||
|
|
||||||
|
|
||||||
|
private final static String PREFIX = "lesson:";
|
||||||
|
private final File pluginTargetDirectory;
|
||||||
|
private final WebSession webSession;
|
||||||
|
|
||||||
|
|
||||||
|
public LessonTemplateResolver(File pluginTargetDirectory, WebSession webSession) {
|
||||||
|
this.pluginTargetDirectory = pluginTargetDirectory;
|
||||||
|
this.webSession = webSession;
|
||||||
|
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
|
||||||
|
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
|
||||||
|
String lessonName = webSession.getCurrentLesson().getClass().getSimpleName();
|
||||||
|
File lesson = new File(pluginTargetDirectory, "/plugin/" + lessonName + "/html/" + lessonName + ".html");
|
||||||
|
if (lesson != null) {
|
||||||
|
try {
|
||||||
|
return new ByteArrayInputStream(Files.toByteArray(lesson));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "lessonResourceResolver";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,21 @@
|
|||||||
package org.owasp.webgoat;
|
package org.owasp.webgoat;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import org.owasp.webgoat.session.LabelDebugger;
|
import org.owasp.webgoat.session.LabelDebugger;
|
||||||
import org.owasp.webgoat.session.WebSession;
|
import org.owasp.webgoat.session.WebSession;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.boot.context.embedded.ServletRegistrationBean;
|
import org.springframework.boot.context.embedded.ServletRegistrationBean;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||||
|
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;
|
||||||
|
import org.thymeleaf.spring4.SpringTemplateEngine;
|
||||||
|
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
|
||||||
|
import org.thymeleaf.templateresolver.TemplateResolver;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
@ -30,6 +36,33 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
|||||||
registry.addViewController("/start.mvc").setViewName("main_new");
|
registry.addViewController("/start.mvc").setViewName("main_new");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) {
|
||||||
|
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||||
|
resolver.setPrefix("classpath:/templates/");
|
||||||
|
resolver.setSuffix(".html");
|
||||||
|
resolver.setOrder(1);
|
||||||
|
resolver.setApplicationContext(applicationContext);
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LessonTemplateResolver lessonTemplateResolver(WebSession webSession) {
|
||||||
|
LessonTemplateResolver resolver = new LessonTemplateResolver(pluginTargetDirectory, webSession);
|
||||||
|
resolver.setOrder(2);
|
||||||
|
return resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SpringTemplateEngine thymeleafTemplateEngine(TemplateResolver springThymeleafTemplateResolver, LessonTemplateResolver lessonTemplateResolver) {
|
||||||
|
SpringTemplateEngine engine = new SpringTemplateEngine();
|
||||||
|
engine.addDialect(new SpringSecurityDialect());
|
||||||
|
engine.setTemplateResolvers(
|
||||||
|
Sets.newHashSet(springThymeleafTemplateResolver, lessonTemplateResolver));
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ServletRegistrationBean servletRegistrationBean(HammerHead hammerHead) {
|
public ServletRegistrationBean servletRegistrationBean(HammerHead hammerHead) {
|
||||||
return new ServletRegistrationBean(hammerHead, "/attack/*");
|
return new ServletRegistrationBean(hammerHead, "/attack/*");
|
||||||
|
@ -5,11 +5,13 @@ import org.owasp.webgoat.session.Course;
|
|||||||
import org.owasp.webgoat.session.WebSession;
|
import org.owasp.webgoat.session.WebSession;
|
||||||
import org.owasp.webgoat.session.WebgoatContext;
|
import org.owasp.webgoat.session.WebgoatContext;
|
||||||
import org.owasp.webgoat.session.WebgoatProperties;
|
import org.owasp.webgoat.session.WebgoatProperties;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||||
import org.springframework.boot.context.web.SpringBootServletInitializer;
|
import org.springframework.boot.context.web.SpringBootServletInitializer;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.PropertySource;
|
import org.springframework.context.annotation.PropertySource;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
@ -40,22 +42,27 @@ public class WebGoat extends SpringBootServletInitializer {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PluginsLoader pluginsLoader(@Qualifier("pluginTargetDirectory") File pluginTargetDirectory) {
|
public PluginsLoader pluginsLoader(@Qualifier("pluginTargetDirectory") File pluginTargetDirectory) {
|
||||||
System.out.println("Plugin target directory: " + pluginTargetDirectory.toString());
|
|
||||||
return new PluginsLoader(pluginTargetDirectory);
|
return new PluginsLoader(pluginTargetDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||||
public WebSession webSession(Course course, WebgoatContext webgoatContext, ServletContext context) {
|
public WebSession webSession(Course course, WebgoatContext webgoatContext, ServletContext context, ApplicationContext applicationContext ) {
|
||||||
return new WebSession(course, webgoatContext, context);
|
return new WebSession(course, webgoatContext, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Course course(PluginsLoader pluginsLoader, WebgoatContext webgoatContext, ServletContext context,
|
public LessonEndpointProvider lessonEndpointProvider(ApplicationContext applicationContext, BeanFactory factory) {
|
||||||
WebgoatProperties webgoatProperties) {
|
LessonEndpointProvider lessonEndpointProvider = new LessonEndpointProvider("org.owasp.webgoat", applicationContext, factory);
|
||||||
|
return lessonEndpointProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Course course(PluginsLoader pluginsLoader, WebgoatContext webgoatContext, ServletContext context, WebgoatProperties webgoatProperties, LessonEndpointProvider endpointProvider) {
|
||||||
Course course = new Course(webgoatProperties);
|
Course course = new Course(webgoatProperties);
|
||||||
course.loadCourses(webgoatContext, context, "/");
|
course.loadCourses(webgoatContext, context, "/");
|
||||||
course.loadLessonFromPlugin(pluginsLoader.loadPlugins());
|
course.loadLessonFromPlugin(pluginsLoader.loadPlugins());
|
||||||
|
endpointProvider.registerEndpoints();
|
||||||
return course;
|
return course;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,22 +5,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.webgoat.application;
|
package org.owasp.webgoat.application;
|
||||||
|
|
||||||
import org.owasp.webgoat.lessons.LessonServletMapping;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
|
||||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
|
||||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import javax.servlet.ServletContextEvent;
|
import javax.servlet.ServletContextEvent;
|
||||||
import javax.servlet.ServletContextListener;
|
import javax.servlet.ServletContextListener;
|
||||||
import javax.servlet.ServletRegistration;
|
|
||||||
import java.sql.Driver;
|
import java.sql.Driver;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web application lifecycle listener.
|
* Web application lifecycle listener.
|
||||||
@ -37,26 +31,6 @@ public class WebGoatServletListener implements ServletContextListener {
|
|||||||
public void contextInitialized(ServletContextEvent sce) {
|
public void contextInitialized(ServletContextEvent sce) {
|
||||||
ServletContext context = sce.getServletContext();
|
ServletContext context = sce.getServletContext();
|
||||||
context.log("WebGoat is starting");
|
context.log("WebGoat is starting");
|
||||||
context.log("Adding extra mappings for lessions");
|
|
||||||
loadServlets(sce);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadServlets(ServletContextEvent sce) {
|
|
||||||
final ServletContext servletContext = sce.getServletContext();
|
|
||||||
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
|
|
||||||
false);
|
|
||||||
provider.addIncludeFilter(new AnnotationTypeFilter(LessonServletMapping.class));
|
|
||||||
Set<BeanDefinition> candidateComponents = provider.findCandidateComponents("org.owasp.webgoat");
|
|
||||||
try {
|
|
||||||
for (BeanDefinition beanDefinition : candidateComponents) {
|
|
||||||
Class controllerClass = Class.forName(beanDefinition.getBeanClassName());
|
|
||||||
LessonServletMapping pathAnnotation = (LessonServletMapping) controllerClass.getAnnotation(LessonServletMapping.class);
|
|
||||||
final ServletRegistration.Dynamic dynamic = servletContext.addServlet(controllerClass.getSimpleName(), controllerClass);
|
|
||||||
dynamic.addMapping(pathAnnotation.path());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Error", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* ************************************************************************************************
|
||||||
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
|
* please see http://www.owasp.org/
|
||||||
|
* <p>
|
||||||
|
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||||
|
* <p>
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
* <p>
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
* <p>
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
* <p>
|
||||||
|
* Getting Source ==============
|
||||||
|
* <p>
|
||||||
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
|
* projects.
|
||||||
|
* <p>
|
||||||
|
*/
|
||||||
|
package org.owasp.webgoat.lessons;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||||
|
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* </p>
|
||||||
|
* Extend this class and implement the met
|
||||||
|
* </p>
|
||||||
|
* Note: each subclass should declare this annotation otherwise the WebGoat framework cannot find your endpoint.
|
||||||
|
*/
|
||||||
|
@LessonEndpointMapping
|
||||||
|
public abstract class LessonEndpoint implements MvcEndpoint {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("pluginTargetDirectory")
|
||||||
|
private File pluginDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory of the plugin directory in which the lessons resides, so if you want to access the lesson 'ClientSideFiltering' you will
|
||||||
|
* need to:
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* File lessonDirectory = new File(getPluginDirectory(), "ClientSideFiltering");
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* The directory structure of the lesson is exactly the same as the directory structure in the plugins project.
|
||||||
|
*
|
||||||
|
* @return the top level
|
||||||
|
*/
|
||||||
|
protected File getPluginDirectory() {
|
||||||
|
return new File(this.pluginDirectory, "plugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean isSensitive() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Class<? extends Endpoint> getEndpointType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,11 @@
|
|||||||
package org.owasp.webgoat.lessons;
|
package org.owasp.webgoat.lessons;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*************************************************************************************************
|
*************************************************************************************************
|
||||||
@ -28,14 +32,13 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
* projects.
|
* projects.
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
* @author Nanne Baars
|
* @author WebGoat
|
||||||
* @since December 12, 2015
|
* @since December 12, 2015
|
||||||
* @version $Id: $Id
|
* @version $Id: $Id
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface LessonServletMapping {
|
public @interface LessonEndpointMapping { }
|
||||||
|
|
||||||
String path();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -3,10 +3,12 @@ package org.owasp.webgoat.plugins;
|
|||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
|
import org.owasp.webgoat.lessons.LessonEndpointMapping;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -27,13 +29,14 @@ public class Plugin {
|
|||||||
|
|
||||||
private static final String NAME_LESSON_SOLUTION_DIRECTORY = "lessonSolutions";
|
private static final String NAME_LESSON_SOLUTION_DIRECTORY = "lessonSolutions";
|
||||||
private static final String NAME_LESSON_PLANS_DIRECTORY = "lessonPlans";
|
private static final String NAME_LESSON_PLANS_DIRECTORY = "lessonPlans";
|
||||||
private final PluginClassLoader classLoader;
|
public static PluginClassLoader classLoader;
|
||||||
|
|
||||||
private Class<AbstractLesson> lesson;
|
private Class<AbstractLesson> lesson;
|
||||||
private Map<String, File> solutionLanguageFiles = new HashMap<>();
|
private Map<String, File> solutionLanguageFiles = new HashMap<>();
|
||||||
private Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
|
private Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
|
||||||
private List<File> pluginFiles = Lists.newArrayList();
|
private List<File> pluginFiles = Lists.newArrayList();
|
||||||
private File lessonSourceFile;
|
private File lessonSourceFile;
|
||||||
|
private List<Class> lessonEndpoints = Lists.newArrayList();
|
||||||
|
|
||||||
public Plugin(PluginClassLoader classLoader) {
|
public Plugin(PluginClassLoader classLoader) {
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
@ -47,6 +50,22 @@ public class Plugin {
|
|||||||
public void findLesson(List<String> classes) {
|
public void findLesson(List<String> classes) {
|
||||||
for (String clazzName : classes) {
|
for (String clazzName : classes) {
|
||||||
findLesson(clazzName);
|
findLesson(clazzName);
|
||||||
|
findLessonEndpoints(clazzName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findLessonEndpoints(String name) {
|
||||||
|
String realClassName = StringUtils.trimLeadingCharacter(name, '/').replaceAll("/", ".").replaceAll(".class", "");
|
||||||
|
try {
|
||||||
|
Class endpointClass = classLoader.loadClass(realClassName);
|
||||||
|
Annotation annotation = endpointClass.getAnnotation(LessonEndpointMapping.class);
|
||||||
|
if (annotation != null ) {
|
||||||
|
this.lessonEndpoints.add(endpointClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
//ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +104,10 @@ public class Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Class> getLessonEndpoints() {
|
||||||
|
return lessonEndpoints;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>rewritePaths.</p>
|
* <p>rewritePaths.</p>
|
||||||
*
|
*
|
||||||
|
@ -64,20 +64,6 @@ public class PluginFileUtils {
|
|||||||
return hasParentDirectoryWithName(p.getParent(), s);
|
return hasParentDirectoryWithName(p.getParent(), s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>createDirsIfNotExists.</p>
|
|
||||||
*
|
|
||||||
* @param p a {@link java.nio.file.Path} object.
|
|
||||||
* @return a {@link java.nio.file.Path} object.
|
|
||||||
* @throws java.io.IOException if any.
|
|
||||||
*/
|
|
||||||
public static Path createDirsIfNotExists(Path p) throws IOException {
|
|
||||||
if (Files.notExists(p)) {
|
|
||||||
Files.createDirectories(p);
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>replaceInFiles.</p>
|
* <p>replaceInFiles.</p>
|
||||||
*
|
*
|
||||||
|
@ -44,6 +44,8 @@ public class PluginsLoader {
|
|||||||
private static final int BUFFER_SIZE = 32 * 1024;
|
private static final int BUFFER_SIZE = 32 * 1024;
|
||||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
private final File pluginTargetDirectory;
|
private final File pluginTargetDirectory;
|
||||||
|
public static PluginClassLoader classLoader = new PluginClassLoader(PluginClassLoader.class.getClassLoader());
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public PluginsLoader(File pluginTargetDirectory) {
|
public PluginsLoader(File pluginTargetDirectory) {
|
||||||
@ -153,8 +155,6 @@ public class PluginsLoader {
|
|||||||
|
|
||||||
private List<Callable<Plugin>> extractJars(List<URL> jars) {
|
private List<Callable<Plugin>> extractJars(List<URL> jars) {
|
||||||
List<Callable<Plugin>> extractorCallables = Lists.newArrayList();
|
List<Callable<Plugin>> extractorCallables = Lists.newArrayList();
|
||||||
ClassLoader parentClassLoader = PluginClassLoader.class.getClassLoader();
|
|
||||||
final PluginClassLoader classLoader = new PluginClassLoader(parentClassLoader);
|
|
||||||
|
|
||||||
for (final URL jar : jars) {
|
for (final URL jar : jars) {
|
||||||
classLoader.addURL(jar);
|
classLoader.addURL(jar);
|
||||||
|
@ -1,16 +1,10 @@
|
|||||||
#spring.mvc.view.prefix=/WEB-INF/jsp/
|
|
||||||
#spring.mvc.view.suffix=.jsp
|
|
||||||
#server.servlet-path=/*
|
|
||||||
#server.jsp-servlet.class-name=org.apache.jasper.servlet.JspServlet
|
|
||||||
#server.jsp-servlet.registered=true
|
|
||||||
|
|
||||||
server.error.include-stacktrace=always
|
server.error.include-stacktrace=always
|
||||||
server.session.timeout=600
|
server.session.timeout=600
|
||||||
server.contextPath=/WebGoat
|
server.contextPath=/WebGoat
|
||||||
server.port=8080
|
server.port=8080
|
||||||
|
|
||||||
|
|
||||||
logging.level.org.springframework=INFO
|
logging.level.org.springframework=DEBUG
|
||||||
logging.level.org.hibernate=ERROR
|
logging.level.org.hibernate=ERROR
|
||||||
spring.thymeleaf.cache=false
|
spring.thymeleaf.cache=false
|
||||||
security.enable-csrf=false
|
security.enable-csrf=false
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns:th="http://www.thymeleaf.org">
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Model is setup in the class StartLesson -->
|
||||||
<div id="lessonInstructions" th:utext="${instructions}"></div>
|
<div id="lessonInstructions" th:utext="${instructions}"></div>
|
||||||
<div id="message" class="info" th:utext="${message}"></div>
|
<div id="message" class="info" th:utext="${message}"></div>
|
||||||
<br/>
|
<br/>
|
||||||
<div th:utext="${lesson.content}"></div>
|
<div th:utext="${lesson.content}"></div>
|
||||||
|
<div th:replace="lesson:showLesson"></div>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user