Loading classes from the plugin archive
(cherry picked from commit 2adf04c)
This commit is contained in:
parent
4f6ba2711f
commit
720040d1f8
61
src/main/java/org/owasp/webgoat/plugins/Plugin.java
Normal file
61
src/main/java/org/owasp/webgoat/plugins/Plugin.java
Normal file
@ -0,0 +1,61 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class Plugin {
|
||||
|
||||
private final Class<AbstractLesson> lesson;
|
||||
private final String lessonPlanHtml;
|
||||
private final String lessonSolutionHtml;
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private Path pluginDirectory;
|
||||
private Class lesson;
|
||||
|
||||
public Builder loadClass(String name, byte[] classFile) {
|
||||
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader, classFile);
|
||||
try {
|
||||
String realClassName = name.replace("/lesson_plans/", "").replaceAll("/", ".").replaceAll(".class", "");
|
||||
Class clazz = pluginClassLoader.loadClass(realClassName);
|
||||
if (AbstractLesson.class.isAssignableFrom(clazz)) {
|
||||
this.lesson = clazz;
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBaseDirectory(Path pluginDirectory) {
|
||||
this.pluginDirectory = pluginDirectory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Plugin build() {
|
||||
return new Plugin(this.lesson, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public Plugin(Class<AbstractLesson> lesson, String lessonPlanHtml, String lessonSolutionHtml) {
|
||||
this.lesson = lesson;
|
||||
this.lessonPlanHtml = lessonPlanHtml;
|
||||
this.lessonSolutionHtml = lessonSolutionHtml;
|
||||
}
|
||||
|
||||
|
||||
public String getLessonPlanHtml() {
|
||||
return lessonPlanHtml;
|
||||
}
|
||||
|
||||
public Class<AbstractLesson> getLesson() {
|
||||
return lesson;
|
||||
}
|
||||
|
||||
public String getLessonSolutionHtml() {
|
||||
return lessonSolutionHtml;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
public class PluginClassLoader extends ClassLoader {
|
||||
|
||||
private final byte[] classFile;
|
||||
|
||||
public PluginClassLoader(ClassLoader parent, byte[] classFile) {
|
||||
super(parent);
|
||||
this.classFile = classFile;
|
||||
}
|
||||
|
||||
public Class findClass(String name) {
|
||||
return defineClass(name, classFile, 0, classFile.length);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
79
src/main/java/org/owasp/webgoat/plugins/PluginExtractor.java
Normal file
79
src/main/java/org/owasp/webgoat/plugins/PluginExtractor.java
Normal file
@ -0,0 +1,79 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Extract the zip file and place the files in a temp directory
|
||||
*/
|
||||
public class PluginExtractor {
|
||||
|
||||
private static final String DIRECTORY = "plugins";
|
||||
private final Path pluginArchive;
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public PluginExtractor(Path pluginArchive) {
|
||||
this.pluginArchive = pluginArchive;
|
||||
}
|
||||
|
||||
|
||||
public Plugin extract() {
|
||||
final Plugin.Builder pluginBuilder = new Plugin.Builder();
|
||||
FileSystem zip = null;
|
||||
try {
|
||||
zip = createZipFileSystem();
|
||||
final Path root = zip.getPath("/");
|
||||
final Path tempDirectory = Files.createTempDirectory(DIRECTORY);
|
||||
pluginBuilder.setBaseDirectory(tempDirectory);
|
||||
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (file.toString().endsWith(".class")) {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
Files.copy(file, bos);
|
||||
pluginBuilder.loadClass(file.toString(), bos.toByteArray());
|
||||
}
|
||||
Files.copy(file, tempDirectory, StandardCopyOption.REPLACE_EXISTING);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
return pluginBuilder.build();
|
||||
} catch (IOException io) {
|
||||
logger.error(String.format("Unable to extract: %s", pluginArchive.getFileName()), io);
|
||||
} finally {
|
||||
closeZipFileSystem(zip);
|
||||
}
|
||||
|
||||
return pluginBuilder.build();
|
||||
}
|
||||
|
||||
private FileSystem createZipFileSystem() throws IOException {
|
||||
final URI uri = URI.create("jar:file:" + pluginArchive.toUri().getPath());
|
||||
return FileSystems.newFileSystem(uri, new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
private void closeZipFileSystem(FileSystem zip) {
|
||||
if (zip != null) {
|
||||
try {
|
||||
zip.close();
|
||||
} catch (IOException e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
39
src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java
Normal file
39
src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java
Normal file
@ -0,0 +1,39 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PluginsLoader {
|
||||
|
||||
private final Path path;
|
||||
|
||||
public PluginsLoader(Path path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public List<Plugin> loadPlugins() {
|
||||
final List<Plugin> plugins = new ArrayList<Plugin>();
|
||||
try {
|
||||
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
plugins.add(new PluginExtractor(file).extract());
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -2,6 +2,13 @@ package org.owasp.webgoat.session;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@ -9,41 +16,45 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.LinkedList;
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.owasp.webgoat.HammerHead;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.plugins.Plugin;
|
||||
import org.owasp.webgoat.plugins.PluginExtractor;
|
||||
import org.owasp.webgoat.plugins.PluginsLoader;
|
||||
import org.owasp.webgoat.util.WebGoatI18N;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
*
|
||||
*
|
||||
* <p/>
|
||||
* <p/>
|
||||
* This file is part of WebGoat, an Open Web Application Security Project
|
||||
* utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* <p/>
|
||||
* Copyright (c) 2002 - 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/>
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
@ -73,7 +84,7 @@ public class Course {
|
||||
|
||||
/**
|
||||
* Take an absolute file and return the filename.
|
||||
*
|
||||
* <p/>
|
||||
* Ex. /etc/password becomes password
|
||||
*
|
||||
* @param s
|
||||
@ -95,7 +106,7 @@ public class Course {
|
||||
|
||||
/**
|
||||
* Take a class name and return the equivalent file name
|
||||
*
|
||||
* <p/>
|
||||
* Ex. org.owasp.webgoat becomes org/owasp/webgoat.java
|
||||
*
|
||||
* @param className
|
||||
@ -114,7 +125,7 @@ public class Course {
|
||||
* Takes a file name and builds the class file name
|
||||
*
|
||||
* @param fileName Description of the Parameter
|
||||
* @param path Description of the Parameter
|
||||
* @param path Description of the Parameter
|
||||
* @return Description of the Return Value
|
||||
*/
|
||||
private static String getClassFile(String fileName, String path) {
|
||||
@ -237,7 +248,7 @@ public class Course {
|
||||
* Gets the lessons attribute of the Course object
|
||||
*
|
||||
* @param category Description of the Parameter
|
||||
* @param role Description of the Parameter
|
||||
* @param role Description of the Parameter
|
||||
* @return The lessons value
|
||||
*/
|
||||
private List<AbstractLesson> getLessons(Category category, List roles) {
|
||||
@ -302,6 +313,34 @@ public class Course {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLessionFromPlugin(ServletContext context) {
|
||||
logger.debug("Loading plugins into cache");
|
||||
String path = context.getRealPath("plugin_lessons");
|
||||
if (path == null) {
|
||||
logger.error("Plugins directory {} not found", path);
|
||||
return;
|
||||
}
|
||||
List<Plugin> plugins = new PluginsLoader(Paths.get(path)).loadPlugins();
|
||||
for (Plugin plugin : plugins) {
|
||||
try {
|
||||
Class<AbstractLesson> c = plugin.getLesson();
|
||||
Object o = c.newInstance();
|
||||
|
||||
AbstractLesson lesson = (AbstractLesson) o;
|
||||
lesson.setWebgoatContext(webgoatContext);
|
||||
|
||||
lesson.update(properties);
|
||||
|
||||
if (lesson.getHidden() == false) {
|
||||
lessons.add(lesson);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error in loadLessons: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate all the lesson objects into a cache
|
||||
*
|
||||
@ -361,18 +400,18 @@ public class Course {
|
||||
lesson.setSourceFileName(absoluteFile);
|
||||
}
|
||||
|
||||
if (absoluteFile.startsWith("/lesson_plans") && absoluteFile.endsWith(".html")
|
||||
&& className.endsWith(fileName)) {
|
||||
logger.info("setting lesson plan file " + absoluteFile + " for lesson "
|
||||
+ lesson.getClass().getName());
|
||||
if (absoluteFile.startsWith("/lesson_plans") && absoluteFile.endsWith(".html") && className
|
||||
.endsWith(fileName)) {
|
||||
logger.info(
|
||||
"setting lesson plan file " + absoluteFile + " for lesson " + lesson.getClass().getName());
|
||||
logger.info("fileName: " + fileName + " == className: " + className);
|
||||
String language = getLanguageFromFileName("/lesson_plans", absoluteFile);
|
||||
lesson.setLessonPlanFileName(language, absoluteFile);
|
||||
}
|
||||
if (absoluteFile.startsWith("/lesson_solutions") && absoluteFile.endsWith(".html")
|
||||
&& className.endsWith(fileName)) {
|
||||
logger.info("setting lesson solution file " + absoluteFile + " for lesson "
|
||||
+ lesson.getClass().getName());
|
||||
if (absoluteFile.startsWith("/lesson_solutions") && absoluteFile.endsWith(".html") && className
|
||||
.endsWith(fileName)) {
|
||||
logger.info(
|
||||
"setting lesson solution file " + absoluteFile + " for lesson " + lesson.getClass().getName());
|
||||
logger.info("fileName: " + fileName + " == className: " + className);
|
||||
lesson.setLessonSolutionFileName(absoluteFile);
|
||||
}
|
||||
@ -384,8 +423,8 @@ public class Course {
|
||||
* Description of the Method
|
||||
*
|
||||
* @param webgoatContext
|
||||
* @param path Description of the Parameter
|
||||
* @param context Description of the Parameter
|
||||
* @param path Description of the Parameter
|
||||
* @param context Description of the Parameter
|
||||
*/
|
||||
public void loadCourses(WebgoatContext webgoatContext, ServletContext context, String path) {
|
||||
logger.info("Loading courses: " + path);
|
||||
@ -393,5 +432,6 @@ public class Course {
|
||||
loadFiles(context, path);
|
||||
loadLessons(path);
|
||||
loadResources();
|
||||
loadLessionFromPlugin(context);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user