diff --git a/webgoat-container/.gitignore b/webgoat-container/.gitignore
index 11d73197f..6503556df 100644
--- a/webgoat-container/.gitignore
+++ b/webgoat-container/.gitignore
@@ -4,4 +4,5 @@ target/
/src/main/webapp/plugin_lessons/*.jar
/src/main/webapp/plugin_extracted/*
dependency-reduced-pom.xml
-src/main/webapp/users/guest.org.owasp.webgoat.lessons.BackDoors.props
\ No newline at end of file
+src/main/webapp/users/guest.org.owasp.webgoat.lessons.BackDoors.props
+/src/main/webapp/WEB-INF/lib/*.jar
\ No newline at end of file
diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/Plugin.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/Plugin.java
index 5c57e9139..7cd012d05 100644
--- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/Plugin.java
+++ b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/Plugin.java
@@ -2,12 +2,12 @@ package org.owasp.webgoat.plugins;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
+import org.apache.catalina.loader.WebappClassLoader;
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;
@@ -43,10 +43,10 @@ public class Plugin {
private void findLesson(String name) {
String realClassName = StringUtils.trimLeadingCharacter(name, '/').replaceAll("/", ".").replaceAll(".class", "");
//TODO should be passed in (refactor)
- URLClassLoader cl = (URLClassLoader) Thread.currentThread().getContextClassLoader();
+ WebappClassLoader cl = (WebappClassLoader) Thread.currentThread().getContextClassLoader();
try {
- Class clazz = cl.loadClass(realClassName);
+ Class clazz = cl.loadClass(realClassName, true);
if (AbstractLesson.class.isAssignableFrom(clazz)) {
this.lesson = clazz;
diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginBackgroundLoader.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginBackgroundLoader.java
deleted file mode 100644
index ce0fb0f1e..000000000
--- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginBackgroundLoader.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.owasp.webgoat.plugins;
-
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.annotation.WebListener;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
-@WebListener
-/**
- *
PluginBackgroundLoader class.
- *
- * @version $Id: $Id
- */
-public class PluginBackgroundLoader implements ServletContextListener {
-
- private ScheduledExecutorService scheduler;
-
- /** {@inheritDoc} */
- @Override
- 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)), 10, 5, TimeUnit.MINUTES);
- }
-
- /** {@inheritDoc} */
- @Override
- public void contextDestroyed(ServletContextEvent event) {
- scheduler.shutdownNow();
- }
-}
diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java
index bca1a18a9..c14bf7817 100644
--- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java
+++ b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginsLoader.java
@@ -1,9 +1,8 @@
package org.owasp.webgoat.plugins;
import com.google.common.collect.Lists;
+import org.apache.catalina.loader.WebappClassLoader;
import org.apache.commons.io.FileUtils;
-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;
@@ -11,10 +10,10 @@ 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.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
@@ -30,12 +29,12 @@ import java.util.concurrent.Executors;
*
* @version $Id: $Id
*/
-public class PluginsLoader implements Runnable {
+public class PluginsLoader {
private static final String WEBGOAT_PLUGIN_EXTENSION = "jar";
+ private static boolean alreadyLoaded = false;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final Path pluginSource;
- private final PluginClassLoaderRepository repository;
private Path pluginTarget;
/**
@@ -44,26 +43,48 @@ public class PluginsLoader implements Runnable {
* @param pluginSource a {@link java.nio.file.Path} object.
* @param pluginTarget a {@link java.nio.file.Path} object.
*/
- public PluginsLoader(PluginClassLoaderRepository repository, Path pluginSource, Path pluginTarget) {
+ public PluginsLoader(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");
+ }
+
+ /**
+ * Copy jars to the lib directory
+ */
+ public void copyJars() {
+ try {
+ if (!alreadyLoaded) {
+ WebappClassLoader cl = (WebappClassLoader) Thread.currentThread().getContextClassLoader();
+ cl.setAntiJARLocking(true);
+
+ List jars = listJars();
+
+ Path webInfLib = pluginTarget.getParent().resolve(cl.getJarPath().replaceFirst("\\/", ""));
+ for (URL jar : jars) {
+ Path sourceJarFile = Paths.get(jar.toURI());
+ FileUtils.copyFileToDirectory(sourceJarFile.toFile(), webInfLib.toFile());
+ }
+ alreadyLoaded = true;
+ }
+ } catch (Exception e) {
+ logger.error("Copying plugins failed", e);
+ }
}
/**
* loadPlugins.
*
- * @param reload a boolean.
* @return a {@link java.util.List} object.
*/
- public List loadPlugins(final boolean reload) {
+ public List loadPlugins() {
+ copyJars();
List plugins = Lists.newArrayList();
try {
PluginFileUtils.createDirsIfNotExists(pluginTarget);
cleanupExtractedPluginsDirectory();
List jars = listJars();
- initClassLoader(jars);
+
plugins = processPlugins(jars);
} catch (Exception e) {
logger.error("Loading plugins failed", e);
@@ -71,12 +92,6 @@ public class PluginsLoader implements Runnable {
return plugins;
}
- private void initClassLoader(List 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());
@@ -131,10 +146,4 @@ public class PluginsLoader implements Runnable {
}
return extractorCallables;
}
-
- /** {@inheritDoc} */
- @Override
- public void run() {
- loadPlugins(true);
- }
}
diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/classloader/PluginClassLoaderFactory.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/classloader/PluginClassLoaderFactory.java
deleted file mode 100644
index cd20a0215..000000000
--- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/classloader/PluginClassLoaderFactory.java
+++ /dev/null
@@ -1,31 +0,0 @@
-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 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;
- }
-}
diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/classloader/PluginClassLoaderRepository.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/classloader/PluginClassLoaderRepository.java
deleted file mode 100644
index 994aea0b5..000000000
--- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/classloader/PluginClassLoaderRepository.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.owasp.webgoat.plugins.classloader;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.net.URLClassLoader;
-
-/**
- * Holds the classloaders for the plugins. For now all the plugins are loaded by the same
- * classloader. This class can be extended to contain a classloader per plugin.
- */
-public class PluginClassLoaderRepository {
-
- private static final Logger logger = LoggerFactory.getLogger(PluginClassLoaderRepository.class);
- private URLClassLoader currentPluginLoader;
-
- /**
- * @return the plugin classloader
- */
- public URLClassLoader get() {
- return currentPluginLoader;
- }
-
- public void replaceClassLoader(URLClassLoader classLoader) {
- if (this.currentPluginLoader != null) {
- try {
- this.currentPluginLoader.close();
- } catch (IOException e) {
- logger.warn("Unable to close the current classloader", e);
- }
- }
- this.currentPluginLoader = classLoader;
- }
-}
diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/service/PluginReloadService.java b/webgoat-container/src/main/java/org/owasp/webgoat/service/PluginReloadService.java
index 9415446cc..83ece5a64 100644
--- a/webgoat-container/src/main/java/org/owasp/webgoat/service/PluginReloadService.java
+++ b/webgoat-container/src/main/java/org/owasp/webgoat/service/PluginReloadService.java
@@ -30,6 +30,7 @@
*/
package org.owasp.webgoat.service;
+import org.owasp.webgoat.plugins.PluginsLoader;
import org.owasp.webgoat.session.WebSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,6 +41,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
+import java.nio.file.Paths;
/**
* PluginReloadService class.
@@ -61,6 +63,11 @@ public class PluginReloadService extends BaseService {
public @ResponseBody
ResponseEntity reloadPlugins(HttpSession session) {
WebSession webSession = (WebSession) session.getAttribute(WebSession.SESSION);
+ logger.debug("Loading plugins into cache");
+ String pluginPath = session.getServletContext().getRealPath("plugin_lessons");
+ String targetPath = session.getServletContext().getRealPath("plugin_extracted");
+ new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)).copyJars();
+
webSession.getCourse().loadLessonFromPlugin(session.getServletContext());
return new ResponseEntity("Plugins reload refresh the WebGoat page!",HttpStatus.OK);
}
diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/session/Course.java b/webgoat-container/src/main/java/org/owasp/webgoat/session/Course.java
index d4cc0ed2b..936cfdcb5 100644
--- a/webgoat-container/src/main/java/org/owasp/webgoat/session/Course.java
+++ b/webgoat-container/src/main/java/org/owasp/webgoat/session/Course.java
@@ -5,7 +5,6 @@ import org.owasp.webgoat.lessons.AbstractLesson;
import org.owasp.webgoat.lessons.Category;
import org.owasp.webgoat.plugins.Plugin;
import org.owasp.webgoat.plugins.PluginsLoader;
-import org.owasp.webgoat.plugins.classloader.PluginClassLoaderRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,7 +65,6 @@ public class Course {
final Logger logger = LoggerFactory.getLogger(Course.class);
- private final PluginClassLoaderRepository repository = new PluginClassLoaderRepository();
private final List lessons = new LinkedList();
private final static String PROPERTIES_FILENAME = HammerHead.propertiesPath;
@@ -337,7 +335,7 @@ public class Course {
return;
}
lessons.clear();
- List plugins = new PluginsLoader(repository, Paths.get(pluginPath), Paths.get(targetPath)).loadPlugins(true);
+ List plugins = new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)).loadPlugins();
for (Plugin plugin : plugins) {
try {
AbstractLesson lesson = plugin.getLesson().get();
diff --git a/webgoat-container/src/main/webapp/WEB-INF/lib/placeholder.txt b/webgoat-container/src/main/webapp/WEB-INF/lib/placeholder.txt
new file mode 100644
index 000000000..e69de29bb