Fixed issue with loading messages in different language. As a standalone jar you can write properties back to messages.properties, this approach worked when you run with exploded classpath (target/classes etc). However failed when running inside Docker container.
This commit is contained in:
parent
d25700434e
commit
ae82df3fb4
@ -32,6 +32,7 @@ package org.owasp.webgoat;
|
|||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import org.owasp.webgoat.i18n.Messages;
|
import org.owasp.webgoat.i18n.Messages;
|
||||||
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
import org.owasp.webgoat.session.Course;
|
import org.owasp.webgoat.session.Course;
|
||||||
import org.owasp.webgoat.session.LabelDebugger;
|
import org.owasp.webgoat.session.LabelDebugger;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -117,8 +118,13 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Messages messageSource() {
|
public PluginMessages pluginMessages(Messages messages) {
|
||||||
Messages messages = new Messages(localeResolver());
|
return new PluginMessages(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Messages messageSource(LocaleResolver localeResolver) {
|
||||||
|
Messages messages = new Messages(localeResolver);
|
||||||
messages.setBasename("classpath:/i18n/messages");
|
messages.setBasename("classpath:/i18n/messages");
|
||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
|||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.catalina.Context;
|
import org.apache.catalina.Context;
|
||||||
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
import org.owasp.webgoat.plugins.PluginClassLoader;
|
import org.owasp.webgoat.plugins.PluginClassLoader;
|
||||||
import org.owasp.webgoat.plugins.PluginEndpointPublisher;
|
import org.owasp.webgoat.plugins.PluginEndpointPublisher;
|
||||||
import org.owasp.webgoat.plugins.PluginsExtractor;
|
import org.owasp.webgoat.plugins.PluginsExtractor;
|
||||||
@ -91,8 +92,8 @@ public class WebGoat extends SpringBootServletInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PluginsExtractor pluginsLoader(@Qualifier("pluginTargetDirectory") File pluginTargetDirectory, PluginClassLoader classLoader) {
|
public PluginsExtractor pluginsLoader(@Qualifier("pluginTargetDirectory") File pluginTargetDirectory, PluginClassLoader classLoader, PluginMessages messages) {
|
||||||
return new PluginsExtractor(pluginTargetDirectory, classLoader);
|
return new PluginsExtractor(pluginTargetDirectory, classLoader, messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
package org.owasp.webgoat.assignments;
|
package org.owasp.webgoat.assignments;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.owasp.webgoat.i18n.Messages;
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
import org.owasp.webgoat.session.UserSessionData;
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
import org.owasp.webgoat.session.UserTracker;
|
import org.owasp.webgoat.session.UserTracker;
|
||||||
import org.owasp.webgoat.session.WebSession;
|
import org.owasp.webgoat.session.WebSession;
|
||||||
@ -50,7 +50,7 @@ public abstract class AssignmentEndpoint extends Endpoint {
|
|||||||
private UserSessionData userSessionData;
|
private UserSessionData userSessionData;
|
||||||
@Getter
|
@Getter
|
||||||
@Autowired
|
@Autowired
|
||||||
private Messages messages;
|
private PluginMessages messages;
|
||||||
|
|
||||||
//// TODO: 11/13/2016 events better fit?
|
//// TODO: 11/13/2016 events better fit?
|
||||||
protected AttackResult trackProgress(AttackResult attackResult) {
|
protected AttackResult trackProgress(AttackResult attackResult) {
|
||||||
|
@ -27,7 +27,7 @@ package org.owasp.webgoat.assignments;
|
|||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.owasp.webgoat.i18n.Messages;
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class AttackResult {
|
public class AttackResult {
|
||||||
@ -35,13 +35,13 @@ public class AttackResult {
|
|||||||
public static class AttackResultBuilder {
|
public static class AttackResultBuilder {
|
||||||
|
|
||||||
private boolean lessonCompleted;
|
private boolean lessonCompleted;
|
||||||
private Messages messages;
|
private PluginMessages messages;
|
||||||
private Object[] feedbackArgs;
|
private Object[] feedbackArgs;
|
||||||
private String feedbackResourceBundleKey;
|
private String feedbackResourceBundleKey;
|
||||||
private String output;
|
private String output;
|
||||||
private Object[] outputArgs;
|
private Object[] outputArgs;
|
||||||
|
|
||||||
public AttackResultBuilder(Messages messages) {
|
public AttackResultBuilder(PluginMessages messages) {
|
||||||
this.messages = messages;
|
this.messages = messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ public class AttackResult {
|
|||||||
private String output;
|
private String output;
|
||||||
|
|
||||||
|
|
||||||
public static AttackResultBuilder builder(Messages messages) {
|
public static AttackResultBuilder builder(PluginMessages messages) {
|
||||||
return new AttackResultBuilder(messages);
|
return new AttackResultBuilder(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ public class Messages extends ReloadableResourceBundleMessageSource {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all messages for presented Locale.
|
* Gets all messages for presented Locale.
|
||||||
|
*
|
||||||
* @return all messages
|
* @return all messages
|
||||||
*/
|
*/
|
||||||
public Properties getMessages() {
|
public Properties getMessages() {
|
||||||
@ -64,4 +65,6 @@ public class Messages extends ReloadableResourceBundleMessageSource {
|
|||||||
return localeResolver.resolveLocale(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());
|
return localeResolver.resolveLocale(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||||
|
* please see http://www.owasp.org/
|
||||||
|
* <p>
|
||||||
|
* Copyright (c) 2002 - 2017 Bruce Mayhew
|
||||||
|
* <p>
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
* <p>
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||||
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
* <p>
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program; if
|
||||||
|
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
* <p>
|
||||||
|
* Getting Source ==============
|
||||||
|
* <p>
|
||||||
|
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||||
|
* projects.
|
||||||
|
* <p>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.owasp.webgoat.i18n;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.core.io.UrlResource;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message resource bundle for plugins. The files is created after startup during the init of the plugins so we
|
||||||
|
* need to load this file through a ResourceLoader instead of location on the classpath.
|
||||||
|
*
|
||||||
|
* @author nbaars
|
||||||
|
* @date 2/4/17
|
||||||
|
*/
|
||||||
|
public class PluginMessages extends ReloadableResourceBundleMessageSource {
|
||||||
|
|
||||||
|
private Messages messages;
|
||||||
|
|
||||||
|
public PluginMessages(Messages messages) {
|
||||||
|
this.messages = messages;
|
||||||
|
this.setParentMessageSource(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Properties getMessages() {
|
||||||
|
return getMergedProperties(messages.resolveLocale()).getProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage(String code, Object... args) {
|
||||||
|
return getMessage(code, args, messages.resolveLocale());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage(String code, String defaultValue, Object... args) {
|
||||||
|
return super.getMessage(code, args, defaultValue, messages.resolveLocale());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPluginMessageBundles(final File i18nPluginDirectory) {
|
||||||
|
this.setBasename("WebGoatLabels");
|
||||||
|
this.setResourceLoader(new ResourceLoader() {
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public Resource getResource(String location) {
|
||||||
|
return new UrlResource(new File(i18nPluginDirectory, location).toURI());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClassLoader getClassLoader() {
|
||||||
|
return Thread.currentThread().getContextClassLoader();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -24,49 +24,49 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.webgoat.plugins;
|
package org.owasp.webgoat.plugins;
|
||||||
|
|
||||||
import com.google.common.primitives.Bytes;
|
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.nio.file.Files;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.stream.Stream;
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import static com.google.common.io.Files.createParentDirs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the main message.properties with the plugins WebGoatLabels
|
* Merges the main message.properties with the plugins WebGoatLabels
|
||||||
*/
|
*/
|
||||||
public class MessagePropertiesMerger {
|
public class MessagePropertyMerger {
|
||||||
|
|
||||||
private final File targetDirectory;
|
private final File targetDirectory;
|
||||||
|
|
||||||
public MessagePropertiesMerger(File targetDirectory) {
|
public MessagePropertyMerger(File targetDirectory) {
|
||||||
this.targetDirectory = targetDirectory;
|
this.targetDirectory = targetDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void mergeAllLanguage() {
|
public void merge(ZipFile zipFile, ZipEntry zipEntry) {
|
||||||
try(Stream<Path> paths = Files.walk(new File(targetDirectory, "plugin/i18n/").toPath())) {
|
|
||||||
paths.filter(Files::isRegularFile).forEach(filePath -> merge(filePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public void merge(Path propertyFile) {
|
|
||||||
Properties messageProperties = new Properties();
|
Properties messageProperties = new Properties();
|
||||||
String messagePropertyFileName = propertyFile.getFileName().toString().replace("WebGoatLabels", "messages");
|
try (InputStream zis = zipFile.getInputStream(zipEntry)) {
|
||||||
messageProperties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("i18n/" + messagePropertyFileName));
|
messageProperties.load(zis);
|
||||||
preparePropertyFile(propertyFile);
|
|
||||||
messageProperties.load(new FileInputStream(propertyFile.toFile()));
|
|
||||||
messageProperties.store(new FileOutputStream(new File(Thread.currentThread().getContextClassLoader().getResource("i18n/" + messagePropertyFileName).toURI())), "WebGoat message properties");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
Properties messagesFromHome = new Properties();
|
||||||
private void preparePropertyFile(Path propertyFile) {
|
File pluginMessageFiles = new File(targetDirectory, zipEntry.getName());
|
||||||
byte[] lines = Files.readAllBytes(propertyFile);
|
if (pluginMessageFiles.exists()) {
|
||||||
lines = Bytes.concat(lines, System.lineSeparator().getBytes());
|
try (FileInputStream fis = new FileInputStream(pluginMessageFiles)) {
|
||||||
Files.write(propertyFile, lines);
|
messagesFromHome.load(fis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messageProperties.putAll(messagesFromHome);
|
||||||
|
|
||||||
|
createParentDirs(pluginMessageFiles);
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(pluginMessageFiles)) {
|
||||||
|
messageProperties.store(fos, "Plugin message properties");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -71,6 +71,9 @@ public class PluginExtractor {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
if (zipEntry.getName().endsWith(".properties")) {
|
if (zipEntry.getName().endsWith(".properties")) {
|
||||||
final File targetFile = new File(targetDirectory, zipEntry.getName());
|
final File targetFile = new File(targetDirectory, zipEntry.getName());
|
||||||
|
if ("WebGoatLabels.properties".equals(targetFile.getName())) {
|
||||||
|
new MessagePropertyMerger(targetDirectory).merge(zipFile, zipEntry);
|
||||||
|
}
|
||||||
copyFile(zipFile, zipEntry, targetFile, true);
|
copyFile(zipFile, zipEntry, targetFile, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -99,6 +102,7 @@ public class PluginExtractor {
|
|||||||
return targetFile;
|
return targetFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Getter for the field <code>classes</code>.</p>
|
* <p>Getter for the field <code>classes</code>.</p>
|
||||||
*
|
*
|
||||||
|
@ -3,6 +3,7 @@ package org.owasp.webgoat.plugins;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -28,10 +29,12 @@ public class PluginsExtractor {
|
|||||||
private static final int BUFFER_SIZE = 32 * 1024;
|
private static final int BUFFER_SIZE = 32 * 1024;
|
||||||
private final File pluginTargetDirectory;
|
private final File pluginTargetDirectory;
|
||||||
private final PluginClassLoader classLoader;
|
private final PluginClassLoader classLoader;
|
||||||
|
private final PluginMessages messages;
|
||||||
|
|
||||||
public PluginsExtractor(File pluginTargetDirectory, PluginClassLoader pluginClassLoader) {
|
public PluginsExtractor(File pluginTargetDirectory, PluginClassLoader pluginClassLoader, PluginMessages messages) {
|
||||||
this.classLoader = pluginClassLoader;
|
this.classLoader = pluginClassLoader;
|
||||||
this.pluginTargetDirectory = pluginTargetDirectory;
|
this.pluginTargetDirectory = pluginTargetDirectory;
|
||||||
|
this.messages = messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,7 +140,7 @@ public class PluginsExtractor {
|
|||||||
plugin.getOriginationJar());
|
plugin.getOriginationJar());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
new MessagePropertiesMerger(pluginTargetDirectory).mergeAllLanguage();
|
messages.addPluginMessageBundles(new File(pluginTargetDirectory, "plugin/i18n"));
|
||||||
return plugins;
|
return plugins;
|
||||||
} finally {
|
} finally {
|
||||||
executorService.shutdown();
|
executorService.shutdown();
|
||||||
|
@ -31,6 +31,7 @@ package org.owasp.webgoat.service;
|
|||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.owasp.webgoat.i18n.Messages;
|
import org.owasp.webgoat.i18n.Messages;
|
||||||
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@ -60,6 +61,7 @@ public class LabelService {
|
|||||||
public static final String URL_LABELS_MVC = "/service/labels.mvc";
|
public static final String URL_LABELS_MVC = "/service/labels.mvc";
|
||||||
private LocaleResolver localeResolver;
|
private LocaleResolver localeResolver;
|
||||||
private Messages messages;
|
private Messages messages;
|
||||||
|
private PluginMessages pluginMessages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use Springs session locale resolver which also gives us the option to change the local later on. For
|
* We use Springs session locale resolver which also gives us the option to change the local later on. For
|
||||||
@ -82,6 +84,9 @@ public class LabelService {
|
|||||||
((SessionLocaleResolver)localeResolver).setDefaultLocale(locale);
|
((SessionLocaleResolver)localeResolver).setDefaultLocale(locale);
|
||||||
log.debug("Language provided: {} leads to Locale: {}", lang, locale);
|
log.debug("Language provided: {} leads to Locale: {}", lang, locale);
|
||||||
}
|
}
|
||||||
return new ResponseEntity<>(messages.getMessages(), HttpStatus.OK);
|
Properties allProperties = new Properties();
|
||||||
|
allProperties.putAll(messages.getMessages());
|
||||||
|
allProperties.putAll(pluginMessages.getMessages());
|
||||||
|
return new ResponseEntity<>(allProperties, HttpStatus.OK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
<!--<i class="fa fa-users"></i>-->
|
<!--<i class="fa fa-users"></i>-->
|
||||||
<!--</button>-->
|
<!--</button>-->
|
||||||
</div>
|
</div>
|
||||||
<button type="button" id="about-button" class="btn btn-default right_nav_button" title="#{about}"
|
<button type="button" id="about-button" class="btn btn-default right_nav_button" th:title="#{about}"
|
||||||
data-toggle="modal" data-target="#about-modal">
|
data-toggle="modal" data-target="#about-modal">
|
||||||
<i class="fa fa-info"></i>
|
<i class="fa fa-info"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -27,6 +27,7 @@ package org.owasp.webgoat.assignments;
|
|||||||
|
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.owasp.webgoat.i18n.Messages;
|
import org.owasp.webgoat.i18n.Messages;
|
||||||
|
import org.owasp.webgoat.i18n.PluginMessages;
|
||||||
import org.owasp.webgoat.session.UserSessionData;
|
import org.owasp.webgoat.session.UserSessionData;
|
||||||
import org.owasp.webgoat.session.UserTracker;
|
import org.owasp.webgoat.session.UserTracker;
|
||||||
import org.owasp.webgoat.session.WebSession;
|
import org.owasp.webgoat.session.WebSession;
|
||||||
@ -60,13 +61,14 @@ public class AssignmentEndpointTest {
|
|||||||
return Locale.ENGLISH;
|
return Locale.ENGLISH;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
protected PluginMessages pluginMessages = new PluginMessages(messages);
|
||||||
|
|
||||||
public void init(AssignmentEndpoint a) {
|
public void init(AssignmentEndpoint a) {
|
||||||
messages.setBasenames("classpath:/i18n/messages", "classpath:/plugin/i18n/WebGoatLabels");
|
messages.setBasenames("classpath:/i18n/messages", "classpath:/plugin/i18n/WebGoatLabels");
|
||||||
ReflectionTestUtils.setField(a, "userTracker", userTracker);
|
ReflectionTestUtils.setField(a, "userTracker", userTracker);
|
||||||
ReflectionTestUtils.setField(a, "userSessionData", userSessionData);
|
ReflectionTestUtils.setField(a, "userSessionData", userSessionData);
|
||||||
ReflectionTestUtils.setField(a, "webSession", webSession);
|
ReflectionTestUtils.setField(a, "webSession", webSession);
|
||||||
ReflectionTestUtils.setField(a, "messages", messages);
|
ReflectionTestUtils.setField(a, "messages", pluginMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user