Fixed classloading issues when a lesson contains an inner class. The plugin classloader only expected the lesson to be loaded, now we keep track of all the classes loaded for each plugin. For each class found in the plugin a plugin classloader was created we need one classloader per plugin

Also needed to rewrite the findClass method to lookup the class in the list instead of loading the class from the byte array.
This commit is contained in:
Nanne Baars 2015-05-04 15:25:28 +02:00
parent 6e8d8562d6
commit 264824eb14
2 changed files with 47 additions and 24 deletions

View File

@ -50,8 +50,10 @@ public class Plugin {
} }
public void loadClasses(Map<String, byte[]> classes) { public void loadClasses(Map<String, byte[]> classes) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader);
for (Map.Entry<String, byte[]> clazz : classes.entrySet()) { for (Map.Entry<String, byte[]> clazz : classes.entrySet()) {
loadClass(clazz.getKey(), clazz.getValue()); loadClass(pluginClassLoader, clazz.getKey(), clazz.getValue());
} }
if (lesson == null) { if (lesson == null) {
throw new PluginLoadingFailure(String throw new PluginLoadingFailure(String
@ -60,18 +62,13 @@ public class Plugin {
} }
} }
private void loadClass(String name, byte[] classFile) { private void loadClass(PluginClassLoader pluginClassLoader, String name, byte[] classFile) {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
PluginClassLoader pluginClassLoader = new PluginClassLoader(contextClassLoader, name, classFile);
try {
String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", ""); String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", "");
Class clazz = pluginClassLoader.loadClass(realClassName);
Class clazz = pluginClassLoader.loadClass(realClassName, classFile);
if (AbstractLesson.class.isAssignableFrom(clazz)) { if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz; this.lesson = clazz;
} }
} catch (ClassNotFoundException e) {
logger.error("Unable to load class {}", name, e);
}
} }
public void loadFiles(List<Path> files, boolean reload) { public void loadFiles(List<Path> files, boolean reload) {
@ -97,7 +94,7 @@ public class Plugin {
Files.copy(file, bos); Files.copy(file, bos);
Path propertiesPath = createPropertiesDirectory(); Path propertiesPath = createPropertiesDirectory();
ResourceBundleClassLoader.setPropertiesPath(propertiesPath); ResourceBundleClassLoader.setPropertiesPath(propertiesPath);
if ( reload ) { if (reload) {
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, APPEND); Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, APPEND);
} else { } else {
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, TRUNCATE_EXISTING); Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, TRUNCATE_EXISTING);
@ -117,8 +114,14 @@ public class Plugin {
public void rewritePaths(Path pluginTarget) { public void rewritePaths(Path pluginTarget) {
try { try {
PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files", pluginTarget.getFileName().toString() + "/plugin/" + this.lesson.getSimpleName() + "/lessonSolutions/en/" + this.lesson.getSimpleName() + "_files", solutionLanguageFiles.values()); PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files",
PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files", pluginTarget.getFileName().toString() + "/plugin/" + this.lesson.getSimpleName() + "/lessonPlans/en/" + this.lesson.getSimpleName() + "_files", lessonPlansLanguageFiles.values()); pluginTarget.getFileName().toString() + "/plugin/" + this.lesson
.getSimpleName() + "/lessonSolutions/en/" + this.lesson.getSimpleName() + "_files",
solutionLanguageFiles.values());
PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files",
pluginTarget.getFileName().toString() + "/plugin/" + this.lesson
.getSimpleName() + "/lessonPlans/en/" + this.lesson.getSimpleName() + "_files",
lessonPlansLanguageFiles.values());
} catch (IOException e) { } catch (IOException e) {
throw new PluginLoadingFailure("Unable to rewrite the paths in the solutions", e); throw new PluginLoadingFailure("Unable to rewrite the paths in the solutions", e);
} }

View File

@ -1,22 +1,42 @@
package org.owasp.webgoat.plugins; package org.owasp.webgoat.plugins;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public class PluginClassLoader extends ClassLoader { public class PluginClassLoader extends ClassLoader {
private final List<Class<?>> classes = new ArrayList<>();
private final Logger logger = LoggerFactory.getLogger(Plugin.class); private final Logger logger = LoggerFactory.getLogger(Plugin.class);
private final byte[] classFile;
public PluginClassLoader(ClassLoader parent, String nameOfClass, byte[] classFile) { public Class<?> loadClass(String nameOfClass, byte[] classFile) {
super(parent); Class<?> clazz = defineClass(nameOfClass, classFile, 0, classFile.length);
logger.debug("Creating class loader for {}", nameOfClass); classes.add(clazz);
this.classFile = classFile; return clazz;
} }
public Class findClass(String name) { public PluginClassLoader(ClassLoader contextClassLoader) {
super(contextClassLoader);
}
public Class findClass(final String name) throws ClassNotFoundException {
logger.debug("Finding class " + name); logger.debug("Finding class " + name);
return defineClass(name, classFile, 0, classFile.length); Optional<Class<?>> foundClass = FluentIterable.from(classes)
.firstMatch(new Predicate<Class<?>>() {
@Override
public boolean apply(Class<?> clazz) {
return clazz.getName().equals(name);
}
});
if (foundClass.isPresent()) {
return foundClass.get();
}
throw new ClassNotFoundException("Class " + name + " not found");
} }
} }