No more yml(2)
This commit is contained in:
parent
002276e65f
commit
5ac9a3b69d
@ -1,66 +0,0 @@
|
|||||||
package org.owasp.webgoat;
|
|
||||||
|
|
||||||
import org.owasp.webgoat.lessons.LessonEndpointMapping;
|
|
||||||
import org.owasp.webgoat.plugins.PluginClassLoader;
|
|
||||||
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 final PluginClassLoader classLoader;
|
|
||||||
private ListableBeanFactory context;
|
|
||||||
private DefaultListableBeanFactory providedBeans;
|
|
||||||
private BeanFactory beanFactory;
|
|
||||||
|
|
||||||
|
|
||||||
public LessonEndpointProvider(String pluginBasePackage, ApplicationContext parentContext, BeanFactory beanFactory, PluginClassLoader cl) {
|
|
||||||
this.pluginBasePackage = pluginBasePackage;
|
|
||||||
this.parentContext = parentContext;
|
|
||||||
this.providedBeans = new DefaultListableBeanFactory(this.parentContext.getParentBeanFactory());
|
|
||||||
this.beanFactory = beanFactory;
|
|
||||||
this.classLoader = cl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerEndpoints() {
|
|
||||||
if (context == null) {
|
|
||||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
|
||||||
context.setParent(parentContext);
|
|
||||||
context.setClassLoader(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -30,6 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.webgoat;
|
package org.owasp.webgoat;
|
||||||
|
|
||||||
|
import org.owasp.webgoat.plugins.Plugin;
|
||||||
import org.owasp.webgoat.plugins.PluginClassLoader;
|
import org.owasp.webgoat.plugins.PluginClassLoader;
|
||||||
import org.owasp.webgoat.plugins.PluginsLoader;
|
import org.owasp.webgoat.plugins.PluginsLoader;
|
||||||
import org.owasp.webgoat.session.Course;
|
import org.owasp.webgoat.session.Course;
|
||||||
@ -37,8 +38,11 @@ import org.owasp.webgoat.session.UserTracker;
|
|||||||
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.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
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.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;
|
||||||
@ -48,9 +52,11 @@ 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;
|
||||||
import org.springframework.context.annotation.ScopedProxyMode;
|
import org.springframework.context.annotation.ScopedProxyMode;
|
||||||
|
import org.springframework.context.support.AbstractApplicationContext;
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@PropertySource("classpath:/webgoat.properties")
|
@PropertySource("classpath:/webgoat.properties")
|
||||||
@ -88,22 +94,29 @@ public class WebGoat extends SpringBootServletInitializer {
|
|||||||
return new WebSession(course, webgoatContext, context);
|
return new WebSession(course, webgoatContext, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public LessonEndpointProvider lessonEndpointProvider(ApplicationContext applicationContext, BeanFactory factory, PluginClassLoader cl) {
|
|
||||||
LessonEndpointProvider lessonEndpointProvider = new LessonEndpointProvider("org.owasp.webgoat", applicationContext, factory, cl);
|
|
||||||
return lessonEndpointProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Course course(PluginsLoader pluginsLoader, WebgoatContext webgoatContext, ServletContext context, WebgoatProperties webgoatProperties,
|
public Course course(PluginsLoader pluginsLoader, WebgoatContext webgoatContext, ServletContext context, WebgoatProperties webgoatProperties,
|
||||||
LessonEndpointProvider endpointProvider) {
|
ApplicationContext applicationContext) {
|
||||||
Course course = new Course(webgoatProperties);
|
Course course = new Course(webgoatProperties);
|
||||||
course.loadCourses(webgoatContext, context, "/");
|
course.loadCourses(webgoatContext, context, "/");
|
||||||
course.loadLessonFromPlugin(pluginsLoader.loadPlugins());
|
List<Plugin> plugins = pluginsLoader.loadPlugins();
|
||||||
endpointProvider.registerEndpoints();
|
course.loadLessonFromPlugin(plugins);
|
||||||
|
plugins.forEach(p -> publishEndpointsWithSpring(p, (AbstractApplicationContext)applicationContext));
|
||||||
return course;
|
return course;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void publishEndpointsWithSpring(Plugin plugin, AbstractApplicationContext applicationContext) {
|
||||||
|
plugin.getLessonEndpoints().forEach(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) {
|
||||||
|
logger.warn("Failed to register " + e.getSimpleName() + " as endpoint with Spring, skipping...");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public UserTracker userTracker() {
|
public UserTracker userTracker() {
|
||||||
UserTracker userTracker = UserTracker.instance();
|
UserTracker userTracker = UserTracker.instance();
|
||||||
|
@ -39,11 +39,11 @@ public class AttackResult {
|
|||||||
return AttackResult.success("Congratulations");
|
return AttackResult.success("Congratulations");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AttackResult success(String output) {
|
public static AttackResult success(String feedback) {
|
||||||
AttackResult attackResult = new AttackResult();
|
AttackResult attackResult = new AttackResult();
|
||||||
attackResult.lessonCompleted = true;
|
attackResult.lessonCompleted = true;
|
||||||
attackResult.feedback = "Congratulations";
|
attackResult.feedback = feedback;
|
||||||
attackResult.output = output;
|
attackResult.output = "";
|
||||||
return attackResult;
|
return attackResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
package org.owasp.webgoat.plugins;
|
package org.owasp.webgoat.plugins;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
|
||||||
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.apache.commons.io.FileUtils;
|
|
||||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||||
|
import org.owasp.webgoat.lessons.LessonEndpoint;
|
||||||
import org.owasp.webgoat.lessons.NewLesson;
|
import org.owasp.webgoat.lessons.NewLesson;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -35,6 +31,7 @@ public class Plugin {
|
|||||||
private Class<AbstractLesson> lesson;
|
private Class<AbstractLesson> lesson;
|
||||||
private YmlBasedLesson ymlBasedLesson; //TODO REMOVE!
|
private YmlBasedLesson ymlBasedLesson; //TODO REMOVE!
|
||||||
private Class<NewLesson> newLesson;
|
private Class<NewLesson> newLesson;
|
||||||
|
private List<Class<LessonEndpoint>> lessonEndpoints = Lists.newArrayList();
|
||||||
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();
|
||||||
@ -44,6 +41,10 @@ public class Plugin {
|
|||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Class<LessonEndpoint>> getLessonEndpoints() {
|
||||||
|
return this.lessonEndpoints;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>findLesson.</p>
|
* <p>findLesson.</p>
|
||||||
*
|
*
|
||||||
@ -71,28 +72,20 @@ public class Plugin {
|
|||||||
} catch (ClassNotFoundException ce) {
|
} catch (ClassNotFoundException ce) {
|
||||||
throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce);
|
throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO remove
|
|
||||||
readYmlLessonConfiguration();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readYmlLessonConfiguration() {
|
public void findEndpoints(List<String> classes) {
|
||||||
java.util.Optional<File> ymlFile = this.pluginFiles.stream().filter(f -> f.getName().endsWith(".yml")).findFirst();
|
for (String clazzName : classes) {
|
||||||
if (ymlFile.isPresent()) {
|
String realClassName = StringUtils.trimLeadingCharacter(clazzName, '/').replaceAll("/", ".").replaceAll(".class", "");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String ymlStr = FileUtils.readFileToString(ymlFile.get());
|
Class clazz = classLoader.loadClass(realClassName);
|
||||||
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
|
|
||||||
Map<String, Object> ymlAsMap = mapper.readValue(ymlStr, new TypeReference<Map<String, Object>>() {
|
if (LessonEndpoint.class.isAssignableFrom(clazz)) {
|
||||||
});
|
this.lessonEndpoints.add(clazz);
|
||||||
Map<String, Object> lessonYml = (Map<String, Object>) ymlAsMap.get("lesson");
|
}
|
||||||
final String category = (String) lessonYml.get("category");
|
} catch (ClassNotFoundException ce) {
|
||||||
final List<String> hints = (List<String>) lessonYml.get("hints");
|
throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce);
|
||||||
final String title = (String) lessonYml.get("title");
|
|
||||||
final String html = (String) lessonYml.get("id");
|
|
||||||
this.ymlBasedLesson = new YmlBasedLesson(category, hints, title, html);
|
|
||||||
this.lesson = null;
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new PluginLoadingFailure("Unable to read yml file", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,41 +111,6 @@ public class Plugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>rewritePaths.</p>
|
|
||||||
*
|
|
||||||
* @param pluginTarget a {@link java.nio.file.Path} object.
|
|
||||||
*/
|
|
||||||
public void rewritePaths(Path pluginTarget) {
|
|
||||||
// try {
|
|
||||||
// replaceInFiles(this.lesson.getSimpleName() + "_files",
|
|
||||||
// "plugin_lessons/plugin/" + this.lesson
|
|
||||||
// .getSimpleName() + "/lessonSolutions/en/" + this.lesson.getSimpleName() + "_files",
|
|
||||||
// solutionLanguageFiles.values());
|
|
||||||
// replaceInFiles(this.lesson.getSimpleName() + "_files",
|
|
||||||
// "plugin_lessons/plugin/" + this.lesson
|
|
||||||
// .getSimpleName() + "/lessonPlans/en/" + this.lesson.getSimpleName() + "_files",
|
|
||||||
// lessonPlansLanguageFiles.values());
|
|
||||||
//
|
|
||||||
// String[] replacements = {"jsp", "js"};
|
|
||||||
// for (String replacement : replacements) {
|
|
||||||
// String s = String.format("plugin/%s/%s/", this.lesson.getSimpleName(), replacement);
|
|
||||||
// String r = String.format("plugin_lessons/plugin/s/%s/", this.lesson.getSimpleName(), replacement);
|
|
||||||
// replaceInFiles(s, r, pluginFiles);
|
|
||||||
// replaceInFiles(s, r, Arrays.asList(lessonSourceFile));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// //CSS with url('/plugin/images') should not begin with / otherwise image cannot be found
|
|
||||||
// String s = String.format("/plugin/%s/images/", this.lesson.getSimpleName());
|
|
||||||
// String r = String
|
|
||||||
// .format("plugin_lessons/plugin/%s/images/", this.lesson.getSimpleName());
|
|
||||||
// replaceInFiles(s, r, pluginFiles);
|
|
||||||
// replaceInFiles(s, r, Arrays.asList(lessonSourceFile));
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// throw new PluginLoadingFailure("Unable to rewrite the paths in the solutions", e);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lesson is optional, it is also possible that the supplied jar contains only helper classes.
|
* Lesson is optional, it is also possible that the supplied jar contains only helper classes.
|
||||||
* Lesson could be a new lesson (adoc based) or still ECS based.
|
* Lesson could be a new lesson (adoc based) or still ECS based.
|
||||||
|
@ -54,9 +54,7 @@ public class PluginExtractor {
|
|||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
plugin.findLesson(this.classes);
|
plugin.findLesson(this.classes);
|
||||||
if (plugin.getLesson().isPresent()) {
|
plugin.findEndpoints(this.classes);
|
||||||
plugin.rewritePaths(targetDirectory.toPath());
|
|
||||||
}
|
|
||||||
zipFile.close();
|
zipFile.close();
|
||||||
}
|
}
|
||||||
return plugin;
|
return plugin;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user