Skip to content

Commit

Permalink
Adding the ability to reload plugins directly from the interface inst…
Browse files Browse the repository at this point in the history
…ead of restarting Tomcat
  • Loading branch information
nbaars committed Sep 22, 2015
1 parent 901eff6 commit 8d2771c
Show file tree
Hide file tree
Showing 18 changed files with 176 additions and 159 deletions.
6 changes: 6 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,9 @@ cp webgoat-container/target/webgoat-container-7.0-SNAPSHOT-war-exec.jar <your_to
```

Browse to [http://localhost:8080/WebGoat](http://localhost:8080/WebGoat) and happy hacking !


## Reloading plugins

If you want to reload all the plugin visit the following url: `http://localhost:8080/WebGoat/service/reloadplugins.mvc`
After you receive a 200/OK the page can be reloaded.
1 change: 0 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@

<modules>
<module>webgoat-container</module>
<module>webgoat-classloader</module>
</modules>

<distributionManagement>
Expand Down
4 changes: 0 additions & 4 deletions webgoat-classloader/.gitignore

This file was deleted.

39 changes: 0 additions & 39 deletions webgoat-classloader/pom.xml

This file was deleted.

This file was deleted.

33 changes: 0 additions & 33 deletions webgoat-container/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@
<contextFile>${project.basedir}/src/main/webapp/WEB-INF/context.xml</contextFile>
</configuration>
<dependencies>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-classloader</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-container</artifactId>
Expand All @@ -57,15 +52,6 @@
<goal>exec-war-only</goal>
</goals>
<phase>package</phase>
<configuration>
<extraDependencies>
<extraDependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-classloader</artifactId>
<version>${project.version}</version>
</extraDependency>
</extraDependencies>
</configuration>
</execution>
<execution>
<id>tomcat-startup</id>
Expand Down Expand Up @@ -195,11 +181,6 @@
<contextFile>${project.basedir}/src/main/webapp/WEB-INF/context.xml</contextFile>
</configuration>
<dependencies>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-classloader</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-container</artifactId>
Expand All @@ -213,15 +194,6 @@
<goal>exec-war-only</goal>
</goals>
<phase>package</phase>
<configuration>
<extraDependencies>
<extraDependency>
<groupId>org.owasp.webgoat</groupId>
<artifactId>webgoat-classloader</artifactId>
<version>${project.version}</version>
</extraDependency>
</extraDependencies>
</configuration>
</execution>
</executions>
</plugin>
Expand All @@ -239,11 +211,6 @@
</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
Original file line number Diff line number Diff line change
Expand Up @@ -1032,4 +1032,5 @@ protected final File getLessonDirectory(WebSession w) {
return new File(w.getContext().getRealPath("/plugin_extracted/plugin/" + getLessonName() + "/"));
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

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.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
Expand Down Expand Up @@ -42,10 +42,11 @@ public void findLesson(List<String> classes) {

private void findLesson(String name) {
String realClassName = StringUtils.trimLeadingCharacter(name, '/').replaceAll("/", ".").replaceAll(".class", "");
PluginClassLoader cl = (PluginClassLoader) Thread.currentThread().getContextClassLoader();
//TODO should be passed in (refactor)
URLClassLoader cl = (URLClassLoader) Thread.currentThread().getContextClassLoader();

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

if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz;
Expand All @@ -55,7 +56,7 @@ private void findLesson(String name) {
}
}

public void loadFiles(Path file, boolean reload) {
public void loadFiles(Path file) {
if (fileEndsWith(file, ".html") && hasParentDirectoryWithName(file, NAME_LESSON_SOLUTION_DIRECTORY)) {
solutionLanguageFiles.put(file.getParent().getFileName().toString(), file.toFile());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.nio.file.Paths;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@WebListener
/**
Expand All @@ -25,7 +23,7 @@ public void contextInitialized(ServletContextEvent event) {
String targetPath = event.getServletContext().getRealPath("plugin_extracted");

scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)), 10, 5, TimeUnit.MINUTES);
//scheduler.scheduleAtFixedRate(new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)), 10, 5, TimeUnit.MINUTES);
}

/** {@inheritDoc} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private void processFile(Plugin plugin, ZipFile zipFile, ZipEntry zipEntry, File
throws IOException {
final File targetFile = new File(targetDirectory, zipEntry.getName());
copyFile(zipFile, zipEntry, targetFile, false);
plugin.loadFiles(targetFile.toPath(), true);
plugin.loadFiles(targetFile.toPath());
}

private boolean processPropertyFile(ZipFile zipFile, ZipEntry zipEntry, File targetDirectory)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package org.owasp.webgoat.plugins;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.apache.commons.io.FileUtils;
import org.owasp.webgoat.classloader.PluginClassLoader;
import org.owasp.webgoat.plugins.classloader.PluginClassLoaderFactory;
import org.owasp.webgoat.plugins.classloader.PluginClassLoaderRepository;
import org.owasp.webgoat.util.LabelProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;

import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
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.List;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
Expand All @@ -30,25 +32,22 @@
*/
public class PluginsLoader implements Runnable {

/** Constant <code>WEBGOAT_PLUGIN_EXTENSION="jar"</code> */
protected static final String WEBGOAT_PLUGIN_EXTENSION = "jar";
private static final String WEBGOAT_PLUGIN_EXTENSION = "jar";
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Path pluginSource;
private final PluginClassLoaderRepository repository;
private Path pluginTarget;


/**
* <p>Constructor for PluginsLoader.</p>
*
* @param pluginSource a {@link java.nio.file.Path} object.
* @param pluginTarget a {@link java.nio.file.Path} object.
*/
public PluginsLoader(Path pluginSource, Path pluginTarget) {
Preconditions.checkNotNull(pluginSource, "plugin source cannot be null");
Preconditions.checkNotNull(pluginTarget, "plugin target cannot be null");

this.pluginSource = pluginSource;
this.pluginTarget = pluginTarget;
public PluginsLoader(PluginClassLoaderRepository repository, Path pluginSource, Path pluginTarget) {
this.pluginSource = Objects.requireNonNull(pluginSource, "plugin source cannot be null");
this.pluginTarget = Objects.requireNonNull(pluginTarget, "plugin target cannot be null");
this.repository = Objects.requireNonNull(repository, "repository cannot be null");
}

/**
Expand All @@ -58,21 +57,26 @@ public PluginsLoader(Path pluginSource, Path pluginTarget) {
* @return a {@link java.util.List} object.
*/
public List<Plugin> loadPlugins(final boolean reload) {
final PluginClassLoader cl = (PluginClassLoader) Thread.currentThread().getContextClassLoader();
List<Plugin> plugins = Lists.newArrayList();

try {
PluginFileUtils.createDirsIfNotExists(pluginTarget);
cleanupExtractedPluginsDirectory();
List<URL> jars = listJars();
cl.addURL(jars);
plugins = processPlugins(jars, reload);
initClassLoader(jars);
plugins = processPlugins(jars);
} catch (Exception e) {
logger.error("Loading plugins failed", e);
}
return plugins;
}

private void initClassLoader(List<URL> jars) {
URLClassLoader classLoader = PluginClassLoaderFactory.createClassLoader(jars);
this.repository.replaceClassLoader(classLoader);
Thread.currentThread().setContextClassLoader(classLoader);
}

private void cleanupExtractedPluginsDirectory() {
Path i18nDirectory = pluginTarget.resolve("plugin/i18n/");
FileUtils.deleteQuietly(i18nDirectory.toFile());
Expand All @@ -93,7 +97,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
return jars;
}

private List<Plugin> processPlugins(List<URL> jars, boolean reload) throws Exception {
private List<Plugin> processPlugins(List<URL> jars) throws Exception {
final List<Plugin> plugins = Lists.newArrayList();
final ExecutorService executorService = Executors.newFixedThreadPool(10);
final CompletionService<Plugin> completionService = new ExecutorCompletionService<>(executorService);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.owasp.webgoat.plugins.classloader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;

/**
* Create a classloader for the plugins
*/
public class PluginClassLoaderFactory {

private static final Logger logger = LoggerFactory.getLogger(PluginClassLoaderFactory.class);

public static URLClassLoader createClassLoader(List<URL> urls) {
return new URLClassLoader(urls.toArray(new URL[urls.size()]), determineParentClassLoader());
}

private static ClassLoader determineParentClassLoader() {
ClassLoader parent = Thread.currentThread().getContextClassLoader();
try {
parent = Thread.currentThread().getContextClassLoader().getParent()
.loadClass("org.apache.jasper.runtime.JspContextWrapper").getClassLoader();
} catch (ClassNotFoundException e) {
logger.info("Tomcat JspContextWrapper not found, probably not running on Tomcat...");
}
return parent;
}
}
Loading

0 comments on commit 8d2771c

Please sign in to comment.