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 b7e27b7c3..39cf58235 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 @@ -24,7 +24,6 @@ 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 Path pluginDirectory; private Class lesson; @@ -61,7 +60,15 @@ public class Plugin { this.lesson = clazz; } } catch (ClassNotFoundException ce) { - throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce); + throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", + ce); + } + } + + public void loadProperties(List properties) { + for (Path propertyFile : properties) { + LabelProvider.updatePluginResources(propertyFile); + LabelProvider.refresh(); } } @@ -76,35 +83,13 @@ public class Plugin { if (fileEndsWith(file, ".java")) { lessonSourceFile = file.toFile(); } - if (fileEndsWith(file, ".properties") && hasParentDirectoryWithName(file, NAME_LESSON_I18N_DIRECTORY)) { - copyProperties(reload, file); - } + if (fileEndsWith(file, ".css", ".jsp", ".js")) { pluginFiles.add(file.toFile()); } } } - private void copyProperties(boolean reload, Path file) { - try { - byte[] lines = Files.readAllBytes(file); - Path propertiesPath = createPropertiesDirectory(); - LabelProvider.updatePluginResources(propertiesPath); - PluginFileUtils.createDirsIfNotExists(file.getParent()); - Files.write(propertiesPath.resolve(file.getFileName()), lines); - } catch (IOException io) { - throw new PluginLoadingFailure("Property file detected, but unable to copy the properties", io); - } - } - - private Path createPropertiesDirectory() throws IOException { - if (Files.exists(pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY))) { - return pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY); - } else { - return Files.createDirectory(pluginDirectory.resolve(NAME_LESSON_I18N_DIRECTORY)); - } - } - public void rewritePaths(Path pluginTarget) { try { replaceInFiles(this.lesson.getSimpleName() + "_files", @@ -117,19 +102,20 @@ public class Plugin { lessonPlansLanguageFiles.values()); String[] replacements = {"jsp", "js"}; - for ( String replacement : replacements ) { + for (String replacement : replacements) { String s = String.format("plugin/%s/%s/", this.lesson.getSimpleName(), replacement); String r = String.format("%s/plugin/%s/%s/", pluginTarget.getFileName().toString(), this.lesson.getSimpleName(), replacement); - replaceInFiles(s,r, pluginFiles); - replaceInFiles(s,r, Arrays.asList(lessonSourceFile)); + replaceInFiles(s, r, pluginFiles); + replaceInFiles(s, r, Arrays.asList(lessonSourceFile)); } //CSS with url('/plugin/images') should not begin with / otherwise image cannot be found String s = String.format("/plugin/%s/images/", this.lesson.getSimpleName()); - String r = String.format("%s/plugin/%s/images/", pluginTarget.getFileName().toString(), this.lesson.getSimpleName()); - replaceInFiles(s,r, pluginFiles); - replaceInFiles(s,r, Arrays.asList(lessonSourceFile)); + String r = String + .format("%s/plugin/%s/images/", pluginTarget.getFileName().toString(), this.lesson.getSimpleName()); + replaceInFiles(s, r, pluginFiles); + replaceInFiles(s, r, Arrays.asList(lessonSourceFile)); } catch (IOException e) { diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginExtractor.java b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginExtractor.java index d175044b1..e955610e2 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginExtractor.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/plugins/PluginExtractor.java @@ -19,6 +19,8 @@ import java.util.List; import static java.lang.String.format; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static org.owasp.webgoat.plugins.PluginFileUtils.createDirsIfNotExists; +import static org.owasp.webgoat.plugins.PluginFileUtils.fileEndsWith; +import static org.owasp.webgoat.plugins.PluginFileUtils.hasParentDirectoryWithName; /** * Extract the jar file and place them in the system temp directory in the folder webgoat and collect the files @@ -26,9 +28,11 @@ import static org.owasp.webgoat.plugins.PluginFileUtils.createDirsIfNotExists; */ public class PluginExtractor { + private static final String NAME_LESSON_I18N_DIRECTORY = "i18n"; private final Path pluginArchive; private final List classes = Lists.newArrayList(); private final List files = new ArrayList<>(); + private final List properties = new ArrayList<>(); public PluginExtractor(Path pluginArchive) { this.pluginArchive = pluginArchive; @@ -43,7 +47,14 @@ public class PluginExtractor { if (file.toString().endsWith(".class")) { classes.add(file.toString()); } - files.add(Files.copy(file, createDirsIfNotExists(Paths.get(target.toString(), file.toString())), REPLACE_EXISTING)); + if (fileEndsWith(file, ".properties") && hasParentDirectoryWithName(file, + NAME_LESSON_I18N_DIRECTORY)) { + properties.add(Files + .copy(file, createDirsIfNotExists(Paths.get(target.toString(), file.toString())), + REPLACE_EXISTING)); + } + files.add(Files.copy(file, createDirsIfNotExists(Paths.get(target.toString(), file.toString())), + REPLACE_EXISTING)); return FileVisitResult.CONTINUE; } }); @@ -60,10 +71,12 @@ public class PluginExtractor { return this.files; } + public List getProperties() { + return this.properties; + } + private FileSystem createZipFileSystem() throws Exception { final URI uri = URI.create("jar:file:" + pluginArchive.toUri().getPath()); return FileSystems.newFileSystem(uri, new HashMap()); } - - } 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 1a02be5fd..5093b291d 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 @@ -84,6 +84,7 @@ public class PluginsLoader implements Runnable { if (plugin.getLesson().isPresent()) { PluginFileUtils.createDirsIfNotExists(pluginTarget); plugin.loadFiles(extractor.getFiles(), reload); + plugin.loadProperties(extractor.getProperties()); plugin.rewritePaths(pluginTarget); plugins.add(plugin); } diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/util/LabelProvider.java b/webgoat-container/src/main/java/org/owasp/webgoat/util/LabelProvider.java index 4c1192c52..f05580c48 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/util/LabelProvider.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/util/LabelProvider.java @@ -6,6 +6,7 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Component; +import org.springframework.util.DefaultPropertiesPersister; import javax.inject.Singleton; import java.net.MalformedURLException; @@ -58,6 +59,9 @@ public class LabelProvider { labels.setFallbackToSystemLocale(false); labels.setUseCodeAsDefaultMessage(true); pluginLabels.setParentMessageSource(labels); + pluginLabels.setPropertiesPersister(new DefaultPropertiesPersister() { + + }); } public static void updatePluginResources(final Path propertyFile) { diff --git a/webgoat-container/src/test/java/org/owasp/webgoat/plugins/WebGoatIT.java b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/WebGoatIT.java index bf97171f3..1849d61fd 100644 --- a/webgoat-container/src/test/java/org/owasp/webgoat/plugins/WebGoatIT.java +++ b/webgoat-container/src/test/java/org/owasp/webgoat/plugins/WebGoatIT.java @@ -1,7 +1,9 @@ package org.owasp.webgoat.plugins; import com.saucelabs.common.SauceOnDemandAuthentication; - +import com.saucelabs.common.SauceOnDemandSessionIdProvider; +import com.saucelabs.junit.ConcurrentParameterized; +import com.saucelabs.junit.SauceOnDemandTestWatcher; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -14,19 +16,14 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.remote.CapabilityType; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.RemoteWebDriver; - -import com.saucelabs.junit.ConcurrentParameterized; -import com.saucelabs.junit.SauceOnDemandTestWatcher; +import org.openqa.selenium.support.ui.ExpectedConditions; +import org.openqa.selenium.support.ui.WebDriverWait; import java.net.URL; import java.util.LinkedList; -import static org.junit.Assert.*; - -import com.saucelabs.common.SauceOnDemandSessionIdProvider; - -import org.openqa.selenium.support.ui.ExpectedConditions; -import org.openqa.selenium.support.ui.WebDriverWait; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** @@ -249,7 +246,7 @@ public class WebGoatIT implements SauceOnDemandSessionIdProvider { String pageSource = driver.getPageSource(); - assertTrue("Page source should contain lessons: Test 1", pageSource.contains("Bypass a Path Based Access Control Scheme")); + assertTrue("Page source should contain lessons: Test 1", pageSource.contains("Reflected XSS")); assertTrue("Page source should contain lessons: Test 2", pageSource.contains("Access Control Flaws")); assertTrue("Page source should contain lessons: Test 3", pageSource.contains("Improper Error Handling")); assertTrue("Page source should contain lessons: Test 34", pageSource.contains("Fail Open Authentication Scheme"));