properties loaded from plugin

This commit is contained in:
nbaars
2015-01-10 10:12:08 +01:00
parent 3d8a345264
commit 3d6236242f
13 changed files with 165 additions and 128 deletions

View File

@ -5,98 +5,104 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.owasp.webgoat.plugins.PluginFileUtils.fileEndsWith;
import static org.owasp.webgoat.plugins.PluginFileUtils.hasParentDirectoryWithName;
public class Plugin {
private static final Logger logger = LoggerFactory.getLogger(Plugin.class);
private final Class<AbstractLesson> lesson;
private static final String NAME_LESSON_SOLUTION_DIRECTORY = "lessonSolutions";
private static final String NAME_LESSON_PLANS_DIRECTORY = "lessonPlans";
private static final String NAME_LESSON_I18N_DIRECTORY = "i18n";
private final Logger logger = LoggerFactory.getLogger(Plugin.class);
private final Path pluginDirectory;
private final Map<String, File> solutionLanguageFiles;
private final Map<String, File> lessonPlansLanguageFiles;
private final File lessonSourceFile;
private Class<AbstractLesson> lesson;
private Map<String, File> solutionLanguageFiles = new HashMap<>();
private Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
private File lessonSourceFile;
public static class PluginLoadingFailure extends RuntimeException {
public PluginLoadingFailure(String message) {
super(message);
}
}
public static class Builder {
private Path pluginDirectory;
private Class lesson;
private final List<String> loadedClasses = new ArrayList<String>();
private final Map<String, File> solutionLanguageFiles = new HashMap<>();
private final Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
private File javaSource;
public Builder loadClasses(Map<String, byte[]> classes) {
for (Map.Entry<String, byte[]> clazz : classes.entrySet() ) {
loadClass(clazz.getKey(), clazz.getValue());
}
return this;
}
public Builder loadClass(String name, byte[] classFile) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader, classFile);
try {
String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", "");
Class clazz = pluginClassLoader.loadClass(realClassName);
if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz;
}
loadedClasses.add(clazz.getName());
} catch (ClassNotFoundException e) {
logger.error("Unable to load class {}", name);
}
return this;
}
public Builder setBaseDirectory(Path pluginDirectory) {
this.pluginDirectory = pluginDirectory;
return this;
}
public Plugin build() {
if ( lesson == null ) {
throw new PluginLoadingFailure(String.format("Lesson class not found, following classes were detected in the plugin: %s",
StringUtils.collectionToCommaDelimitedString(loadedClasses)));
}
return new Plugin(this.lesson, pluginDirectory, lessonPlansLanguageFiles, solutionLanguageFiles, javaSource);
}
public void loadFiles(List<Path> files) {
for (Path file : files) {
if (file.getFileName().toString().endsWith(".html") && file.getParent().getParent().getFileName().toString()
.endsWith("lessonSolutions")) {
solutionLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
if (file.getFileName().toString().endsWith(".html") && file.getParent().getParent().getFileName().toString()
.endsWith("lessonPlans")) {
lessonPlansLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
if ( file.getFileName().toString().endsWith(".java")) {
javaSource = file.toFile();
}
}
public PluginLoadingFailure(String message, Exception e) {
super(message, e);
}
}
public Plugin(Class<AbstractLesson> lesson, Path pluginDirectory, Map<String, File> lessonPlansLanguageFiles,
Map<String, File> solutionLanguageFiles, File lessonSourceFile) {
this.lesson = lesson;
public Plugin(Path pluginDirectory) {
this.pluginDirectory = pluginDirectory;
this.lessonPlansLanguageFiles = lessonPlansLanguageFiles;
this.solutionLanguageFiles = solutionLanguageFiles;
this.lessonSourceFile = lessonSourceFile;
}
public void loadClasses(Map<String, byte[]> classes) {
for (Map.Entry<String, byte[]> clazz : classes.entrySet()) {
loadClass(clazz.getKey(), clazz.getValue());
}
if (lesson == null) {
throw new PluginLoadingFailure(String
.format("Lesson class not found, following classes were detected in the plugin: %s",
StringUtils.collectionToCommaDelimitedString(classes.keySet())));
}
}
private void loadClass(String name, byte[] classFile) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader, classFile);
try {
String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", "");
Class clazz = pluginClassLoader.loadClass(realClassName);
if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz;
}
} catch (ClassNotFoundException e) {
logger.error("Unable to load class {}", name);
}
}
public void loadFiles(List<Path> files) {
for (Path file : files) {
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_SOLUTION_DIRECTORY)) {
solutionLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_PLANS_DIRECTORY)) {
lessonPlansLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
if (fileEndsWith(file, ".java")) {
lessonSourceFile = file.toFile();
}
if (fileEndsWith(file, ".properties") && hasParentDirectoryWithName(file, NAME_LESSON_I18N_DIRECTORY)) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Files.copy(file, bos);
Path propertiesPath = createPropertiesDirectory();
ResourceBundleClassLoader.setPropertiesPath(propertiesPath);
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(),
StandardOpenOption.CREATE, StandardOpenOption.APPEND);
} catch (IOException io) {
throw new PluginLoadingFailure("Property file detected, but unable to copy the properties", io);
}
}
}
}
private Path createPropertiesDirectory() throws IOException {
if (Files.exists(pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY))) {
return pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY);
} else {
return Files.createDirectory(pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY));
}
}
public Class<AbstractLesson> getLesson() {
@ -107,7 +113,9 @@ public class Plugin {
return this.solutionLanguageFiles;
}
public File getLessonSource() { return lessonSourceFile; }
public File getLessonSource() {
return lessonSourceFile;
}
public Map<String, File> getLessonPlans() {
return this.lessonPlansLanguageFiles;

View File

@ -0,0 +1,22 @@
package org.owasp.webgoat.plugins;
import java.nio.file.Path;
public class PluginFileUtils {
public static boolean fileEndsWith(Path p, String s) {
return p.getFileName().toString().endsWith(s);
}
public static boolean hasParentDirectoryWithName(Path p, String s) {
if (p == null || p.getParent() == null || p.getRoot().equals(p.getParent())) {
return false;
}
if (p.getParent().getFileName().toString().equals(s)) {
return true;
}
return hasParentDirectoryWithName(p.getParent(), s);
}
}

View File

@ -31,11 +31,10 @@ public class PluginsLoader implements Runnable {
try {
PluginExtractor extractor = new PluginExtractor(file);
extractor.extract();
Plugin.Builder builder = new Plugin.Builder();
builder.loadClasses(extractor.getClasses());
builder.loadFiles(extractor.getFiles());
builder.setBaseDirectory(extractor.getBaseDirectory());
plugins.add(builder.build());
Plugin plugin = new Plugin(extractor.getBaseDirectory());
plugin.loadClasses(extractor.getClasses());
plugin.loadFiles(extractor.getFiles());
plugins.add(plugin);
} catch (Plugin.PluginLoadingFailure e) {
logger.error("Unable to load plugin, continue reading others...");
}

View File

@ -0,0 +1,33 @@
package org.owasp.webgoat.plugins;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class ResourceBundleClassLoader {
private final static ResourceBundleClassLoader classLoader = new ResourceBundleClassLoader();
private Path propertiesPath;
private ResourceBundleClassLoader() {
}
public static void setPropertiesPath(Path path) {
classLoader.propertiesPath = path;
}
public static ClassLoader createPropertyFilesClassLoader(ClassLoader parentClassLoader) {
final List<URL> urls = new ArrayList<>();
try {
urls.add(classLoader.propertiesPath.toUri().toURL());
} catch (IOException e) {
throw new Plugin.PluginLoadingFailure("Unable to load the properties for the classloader", e);
}
return new URLClassLoader(urls.toArray(new URL[urls.size()]), Thread.currentThread().getContextClassLoader());
}
}

View File

@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
import javax.servlet.ServletContext;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
@ -313,7 +314,9 @@ public class Course {
logger.error("Plugins directory {} not found", path);
return;
}
List<Plugin> plugins = new PluginsLoader(Paths.get(path)).loadPlugins();
Path pluginDirectory = Paths.get(path);
webgoatContext.setPluginDirectory(pluginDirectory);
List<Plugin> plugins = new PluginsLoader(pluginDirectory).loadPlugins();
for (Plugin plugin : plugins) {
try {
Class<AbstractLesson> c = plugin.getLesson();
@ -330,7 +333,7 @@ public class Course {
for(Map.Entry<String, File> lessonPlan : plugin.getLessonPlans().entrySet()) {
lesson.setLessonPlanFileName(lessonPlan.getKey(), lessonPlan.getValue().toString());
}
lesson.setLessonSolutionFileName(plugin.getLessonPlans().get("en").toString());
lesson.setLessonSolutionFileName(plugin.getLessonSolutions().get("en").toString());
lesson.setSourceFileName(plugin.getLessonSource().toString());
} catch (Exception e) {
logger.error("Error in loadLessons: ", e);
@ -433,4 +436,5 @@ public class Course {
//loadResources();
}
}

View File

@ -1,9 +1,11 @@
package org.owasp.webgoat.session;
import javax.servlet.http.HttpServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServlet;
import java.nio.file.Path;
public class WebgoatContext {
final Logger logger = LoggerFactory.getLogger(WebgoatContext.class);
@ -80,6 +82,8 @@ public class WebgoatContext {
private String defaultLanguage;
private java.nio.file.Path pluginDirectory;
public WebgoatContext(HttpServlet servlet) {
this.servlet = servlet;
databaseConnectionString = getParameter(servlet, DATABASE_CONNECTION_STRING);
@ -213,4 +217,12 @@ public class WebgoatContext {
return defaultLanguage;
}
public Path getPluginDirectory() {
return pluginDirectory;
}
public void setPluginDirectory(Path pluginDirectory) {
this.pluginDirectory = pluginDirectory;
}
}

View File

@ -1,6 +1,7 @@
package org.owasp.webgoat.util;
import org.owasp.webgoat.plugins.ResourceBundleClassLoader;
import org.springframework.stereotype.Component;
import java.util.HashMap;
@ -38,7 +39,7 @@ import java.util.ResourceBundle;
@Component
public class LabelProvider
{
public final static String DEFAULT_LANGUAGE = "en";
public final static String DEFAULT_LANGUAGE = Locale.ENGLISH.getLanguage();
private final HashMap<Locale, ResourceBundle> labels = new HashMap<Locale, ResourceBundle>();
private final WebGoatResourceBundleController localeController = new WebGoatResourceBundleController();
@ -47,7 +48,8 @@ public class LabelProvider
{
if (!labels.containsKey(locale))
{
ResourceBundle resBundle = ResourceBundle.getBundle("WebGoatLabels", locale, localeController);
ClassLoader classLoader = ResourceBundleClassLoader.createPropertyFilesClassLoader(ResourceBundle.class.getClassLoader());
ResourceBundle resBundle = ResourceBundle.getBundle("WebGoatLabels", new Locale(DEFAULT_LANGUAGE), classLoader);
labels.put(locale, resBundle);
}
return labels.get(locale).getString(strName);