Skip to content

Commit

Permalink
Fixed classloading issue when using a jsp in a lesson
Browse files Browse the repository at this point in the history
  • Loading branch information
nbaars committed Jun 19, 2015
1 parent c24f556 commit c71d774
Show file tree
Hide file tree
Showing 23 changed files with 233 additions and 227 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,10 @@ src/main/main.iml
*.LOCAL.*.jsp
*.REMOTE.*.jsp
src/main/webapp/plugin_extracted/*
src/main/webapp/users/*.jar
src/main/webapp/plugin_lessons/*.jar
src/main/webapp/users/*.props
classes/*

/*.iml
.extract/*
3 changes: 3 additions & 0 deletions catalina.policy
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
grant {
permission java.security.AllPermission;
};
2 changes: 2 additions & 0 deletions context.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<context><Loader loaderClass = "gr.nevma.cccl.CompilingClassLoader"/>
</context>
4 changes: 4 additions & 0 deletions context.xmlold
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Context antiJARLocking="true" reloadable="true" antiResourceLocking="true">
<!-- <Loader className= "org.owasp.webgoat.plugins.JspCompilerClassLoader" delegate="true" /> -->
<JarScanner scanAllDirectories="true"/>
</Context>
67 changes: 35 additions & 32 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@
<encoding>ISO-8859-1</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>create-jar</id>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
Expand All @@ -64,38 +77,6 @@
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>copy</goal>
</goals>
<phase>package</phase>
<configuration>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<type>jar</type>
<classifier>classes</classifier>
<outputDirectory>${project.build.directory}</outputDirectory>
<destFileName>webgoat-container-${project.version}.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
Expand Down Expand Up @@ -125,7 +106,24 @@
<url>http://localhost:8080/manager</url>
<path>/WebGoat</path>
<attachArtifactClassifier>exec</attachArtifactClassifier>
<contextReloadable>true</contextReloadable>
<useSeparateTomcatClassLoader>true</useSeparateTomcatClassLoader>
<contextFile>${project.basedir}/src/main/webapp/WEB-INF/context.xml</contextFile>
<extraDependencies>
<extraDependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-classloader</artifactId>
<version>${project.version}</version>
</extraDependency>
</extraDependencies>
</configuration>
<dependencies>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-container</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>tomcat-run</id>
Expand All @@ -140,6 +138,11 @@
</build>

<dependencies>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-classloader</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
Expand Down
28 changes: 14 additions & 14 deletions src/main/java/org/owasp/webgoat/HammerHead.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
package org.owasp.webgoat;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.WelcomeScreen;
import org.owasp.webgoat.lessons.admin.WelcomeAdminScreen;
Expand All @@ -24,6 +12,19 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
* *************************************************************************************************
*
Expand Down Expand Up @@ -192,8 +193,7 @@ public void doPost(HttpServletRequest request, HttpServletResponse response) thr
logger.debug("Screen: " + screen);
request.getRequestDispatcher(viewPage).forward(request, response);
} catch (Throwable t) {
logger.error("Error handling request", t);
screen = new ErrorScreen(mySession, t);
logger.error("Error handling request", t); screen = new ErrorScreen(mySession, t);
} finally {
try {
if (screen instanceof ErrorScreen) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
*/
package org.owasp.webgoat.application;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
* Web application lifecycle listener.
Expand Down
19 changes: 8 additions & 11 deletions src/main/java/org/owasp/webgoat/plugins/LegacyLoader.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
package org.owasp.webgoat.plugins;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.servlet.ServletContext;

import org.owasp.webgoat.HammerHead;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.session.WebgoatContext;
import org.owasp.webgoat.session.WebgoatProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletContext;
import java.io.File;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
* *************************************************************************************************
* <p/>
Expand Down Expand Up @@ -178,7 +175,7 @@ public List<AbstractLesson> loadLessons(WebgoatContext webgoatContext, ServletCo
for (String file : files) {
String className = getClassFile(file, path);

if (className != null && !className.endsWith("_i")) {
if (className != null && !className.endsWith("_i") && className.startsWith("org.owasp.webgoat.lessons.admin")) {
try {
Class c = Class.forName(className);
Object o = c.newInstance();
Expand Down
69 changes: 37 additions & 32 deletions src/main/java/org/owasp/webgoat/plugins/Plugin.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.owasp.webgoat.plugins;

import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import org.owasp.webgoat.classloader.PluginClassLoader;
import org.owasp.webgoat.lessons.AbstractLesson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
Expand All @@ -20,54 +19,48 @@
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static org.owasp.webgoat.plugins.PluginFileUtils.fileEndsWith;
import static org.owasp.webgoat.plugins.PluginFileUtils.hasParentDirectoryWithName;
import static org.owasp.webgoat.plugins.PluginFileUtils.replaceInFiles;

public class Plugin {

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 Class<AbstractLesson> lesson;
private Map<String, File> solutionLanguageFiles = new HashMap<>();
private Map<String, File> lessonPlansLanguageFiles = new HashMap<>();
private List<File> cssFiles = Lists.newArrayList();
private File lessonSourceFile;

public static class PluginLoadingFailure extends RuntimeException {

public PluginLoadingFailure(String message) {
super(message);
}

public PluginLoadingFailure(String message, Exception e) {
super(message, e);
}
public Plugin(Path pluginDirectory) {
this.pluginDirectory = pluginDirectory;
}

public Plugin(Path pluginDirectory) {
public Plugin(Path pluginDirectory, List<String> classes) {
this.pluginDirectory = pluginDirectory;
findLesson(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()) {
loadClass(pluginClassLoader, 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 findLesson(List<String> classes) {
for (String clazzName : classes) {
findLesson(clazzName);
}
}

private void loadClass(PluginClassLoader pluginClassLoader, String name, byte[] classFile) {
private void findLesson(String name) {
String realClassName = name.replaceFirst("/", "").replaceAll("/", ".").replaceAll(".class", "");
PluginClassLoader cl = (PluginClassLoader) Thread.currentThread().getContextClassLoader();

try {
Class clazz = cl.loadClass(realClassName, true);

Class clazz = pluginClassLoader.loadClass(realClassName, classFile);
if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz;
if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz;
}
} catch (ClassNotFoundException ce) {
throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce);
}
}

Expand All @@ -85,6 +78,9 @@ public void loadFiles(List<Path> files, boolean reload) {
if (fileEndsWith(file, ".properties") && hasParentDirectoryWithName(file, NAME_LESSON_I18N_DIRECTORY)) {
copyProperties(reload, file);
}
if (fileEndsWith(file, ".css")) {
cssFiles.add(file.toFile());
}
}
}

Expand All @@ -94,6 +90,7 @@ private void copyProperties(boolean reload, Path file) {
Files.copy(file, bos);
Path propertiesPath = createPropertiesDirectory();
ResourceBundleClassLoader.setPropertiesPath(propertiesPath);
PluginFileUtils.createDirsIfNotExists(file.getParent());
if (reload) {
Files.write(propertiesPath.resolve(file.getFileName()), bos.toByteArray(), CREATE, APPEND);
} else {
Expand All @@ -114,25 +111,33 @@ private Path createPropertiesDirectory() throws IOException {

public void rewritePaths(Path pluginTarget) {
try {
PluginFileUtils.replaceInFiles(this.lesson.getSimpleName() + "_files",
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",
replaceInFiles(this.lesson.getSimpleName() + "_files",
pluginTarget.getFileName().toString() + "/plugin/" + this.lesson
.getSimpleName() + "/lessonPlans/en/" + this.lesson.getSimpleName() + "_files",
lessonPlansLanguageFiles.values());
replaceInFiles("url\\(images", "url\\(" + pluginTarget.getFileName().toString() + "/plugin/" + this.lesson
.getSimpleName() + "/jsp/images", cssFiles);
} catch (IOException e) {
throw new PluginLoadingFailure("Unable to rewrite the paths in the solutions", e);
}
}

public AbstractLesson getLesson() {
/**
* Lesson is optional, it is also possible that the supplied jar contains only helper classes.
*/
public Optional<AbstractLesson> getLesson() {
try {
return lesson.newInstance();
if (lesson != null) {
return Optional.of(lesson.newInstance());
}
} catch (IllegalAccessException | InstantiationException e) {
throw new PluginLoadingFailure("Unable to instantiate the lesson " + lesson.getName(), e);
}
return Optional.absent();
}

public Optional<File> getLessonSolution(String language) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class PluginBackgroundLoader implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
String pluginPath = event.getServletContext().getRealPath("plugin_lessons");
String targetPath = event.getServletContext().getRealPath("plugin_extracted");

scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)), 0, 5, TimeUnit.MINUTES);
}
Expand Down
Loading

0 comments on commit c71d774

Please sign in to comment.