Loading classes from the plugin archive

(cherry picked from commit 2adf04c)
This commit is contained in:
nbaars
2014-12-29 18:54:12 +01:00
parent 4f6ba2711f
commit 720040d1f8
5 changed files with 260 additions and 23 deletions

View 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;
}
}

View File

@ -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);
}
}

View 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
}
}
}
}

View 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;
}
}