- Introduced user registration
- Now using Spring Boot for classloading, this way local development does not need to restart the complete server - Fixed all kinds of dependencies on the names of the lessons necessary to keep in mind during the creation of a lesson. - Simplied loading of resources, by adding resource mappings in MvcConfig. - Refactored plugin loading, now only one class is left for loading the lessons.
This commit is contained in:
@ -34,25 +34,20 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.asciidoctor.Asciidoctor;
|
||||
import org.owasp.webgoat.i18n.Language;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.thymeleaf.TemplateProcessingParameters;
|
||||
import org.thymeleaf.resourceresolver.IResourceResolver;
|
||||
import org.thymeleaf.templateresolver.TemplateResolver;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static org.asciidoctor.Asciidoctor.Factory.create;
|
||||
|
||||
/**
|
||||
* Thymeleaf resolver for AsciiDoc used in the lesson, can be used as follows inside a lesson file:
|
||||
*
|
||||
* <p>
|
||||
* <code>
|
||||
* <div th:replace="doc:AccessControlMatrix_plan.adoc"></div>
|
||||
* <div th:replace="doc:AccessControlMatrix_plan.adoc"></div>
|
||||
* </code>
|
||||
*/
|
||||
public class AsciiDoctorTemplateResolver extends TemplateResolver {
|
||||
@ -80,34 +75,26 @@ public class AsciiDoctorTemplateResolver extends TemplateResolver {
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
|
||||
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(computeResourceName(resourceName));
|
||||
try {
|
||||
Optional<Path> adocFile = resolveAdocFile(resourceName);
|
||||
if (adocFile.isPresent()) {
|
||||
try (FileReader reader = new FileReader(adocFile.get().toFile())) {
|
||||
StringWriter writer = new StringWriter();
|
||||
asciidoctor.convert(reader, writer, createAttributes());
|
||||
return new ByteArrayInputStream(writer.getBuffer().toString().getBytes());
|
||||
}
|
||||
}
|
||||
return new ByteArrayInputStream(new byte[0]);
|
||||
StringWriter writer = new StringWriter();
|
||||
asciidoctor.convert(new InputStreamReader(is), writer, createAttributes());
|
||||
return new ByteArrayInputStream(writer.getBuffer().toString().getBytes());
|
||||
} catch (IOException e) {
|
||||
//no html yet
|
||||
return new ByteArrayInputStream(new byte[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Optional<Path> resolveAdocFile(String resourceName) throws IOException {
|
||||
Optional<Path> path = Optional.empty();
|
||||
if (language.getLocale() != null) {
|
||||
path = find(pluginTargetDirectory.toPath(), resourceName, language.getLocale().toString());
|
||||
}
|
||||
if (!path.isPresent()) {
|
||||
path = find(pluginTargetDirectory.toPath(), resourceName, null);
|
||||
}
|
||||
return path;
|
||||
/**
|
||||
* The resource name is for example HttpBasics_content1.adoc. This is always located in the following directory:
|
||||
* <code>plugin/HttpBasics/lessonPlans/en/HttpBasics_content1.adoc</code>
|
||||
*/
|
||||
private String computeResourceName(String resourceName) {
|
||||
return String.format("lessonPlans/%s/%s", language.getLocale().getLanguage(), resourceName);
|
||||
}
|
||||
|
||||
|
||||
private Map<String, Object> createAttributes() {
|
||||
Map<String, Object> attributes = Maps.newHashMap();
|
||||
attributes.put("source-highlighter", "coderay");
|
||||
@ -119,14 +106,6 @@ public class AsciiDoctorTemplateResolver extends TemplateResolver {
|
||||
return options;
|
||||
}
|
||||
|
||||
private Optional<Path> find(Path path, String resourceName, String language) throws IOException {
|
||||
Predicate<Path> languageFilter = p -> StringUtils.hasText(language) ? p.getParent().getFileName().toString().equals(language) : true;
|
||||
return Files.walk(path)
|
||||
.filter(Files::isRegularFile)
|
||||
.filter(p -> p.toString().endsWith(resourceName))
|
||||
.filter(languageFilter).findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "adocResourceResolver";
|
||||
|
@ -30,16 +30,19 @@
|
||||
*/
|
||||
package org.owasp.webgoat;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.thymeleaf.TemplateProcessingParameters;
|
||||
import org.thymeleaf.resourceresolver.IResourceResolver;
|
||||
import org.thymeleaf.templateresolver.TemplateResolver;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Dynamically resolve a lesson. In the html file this can be invoked as:
|
||||
@ -48,15 +51,18 @@ import java.io.InputStream;
|
||||
* <div th:case="true" th:replace="lesson:__${lesson.class.simpleName}__"></div>
|
||||
* </code>
|
||||
*
|
||||
* Thymeleaf will invoke this resolver based on the prefix and this implementqtion will resolve the html in the plugins directory
|
||||
* Thymeleaf will invoke this resolver based on the prefix and this implementation will resolve the html in the plugins directory
|
||||
*/
|
||||
public class LessonTemplateResolver extends TemplateResolver {
|
||||
|
||||
private final static String PREFIX = "lesson:";
|
||||
private final File pluginTargetDirectory;
|
||||
private ResourceLoader resourceLoader;
|
||||
private Map<String, byte[]> resources = Maps.newHashMap();
|
||||
|
||||
public LessonTemplateResolver(File pluginTargetDirectory) {
|
||||
public LessonTemplateResolver(File pluginTargetDirectory, ResourceLoader resourceLoader) {
|
||||
this.pluginTargetDirectory = pluginTargetDirectory;
|
||||
this.resourceLoader = resourceLoader;
|
||||
setResourceResolver(new LessonResourceResolver());
|
||||
setResolvablePatterns(Sets.newHashSet(PREFIX + "*"));
|
||||
}
|
||||
@ -70,17 +76,14 @@ public class LessonTemplateResolver extends TemplateResolver {
|
||||
private class LessonResourceResolver implements IResourceResolver {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) {
|
||||
File lesson = new File(pluginTargetDirectory, "/plugin/" + resourceName + "/html/" + resourceName + ".html");
|
||||
if (lesson != null) {
|
||||
try {
|
||||
return new ByteArrayInputStream(Files.toByteArray(lesson));
|
||||
} catch (IOException e) {
|
||||
//no html yet
|
||||
return new ByteArrayInputStream(new byte[0]);
|
||||
}
|
||||
byte[] resource = resources.get(resourceName);
|
||||
if (resource == null) {
|
||||
resource = ByteStreams.toByteArray(resourceLoader.getResource("classpath:/html/" + resourceName + ".html").getInputStream());
|
||||
resources.put(resourceName, resource);
|
||||
}
|
||||
return null;
|
||||
return new ByteArrayInputStream(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,32 +1,32 @@
|
||||
/**
|
||||
*************************************************************************************************
|
||||
*
|
||||
*
|
||||
* ************************************************************************************************
|
||||
* <p>
|
||||
* <p>
|
||||
* 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 - 20014 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.
|
||||
*
|
||||
* @author WebGoat
|
||||
* @since October 28, 2003
|
||||
* @version $Id: $Id
|
||||
* @since October 28, 2003
|
||||
*/
|
||||
package org.owasp.webgoat;
|
||||
|
||||
@ -39,8 +39,11 @@ import org.owasp.webgoat.session.LabelDebugger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
@ -70,6 +73,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
registry.addViewController("/start.mvc").setViewName("main_new");
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public TemplateResolver springThymeleafTemplateResolver(ApplicationContext applicationContext) {
|
||||
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
@ -82,8 +86,8 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LessonTemplateResolver lessonTemplateResolver() {
|
||||
LessonTemplateResolver resolver = new LessonTemplateResolver(pluginTargetDirectory);
|
||||
public LessonTemplateResolver lessonTemplateResolver(ResourceLoader resourceLoader) {
|
||||
LessonTemplateResolver resolver = new LessonTemplateResolver(pluginTargetDirectory, resourceLoader);
|
||||
resolver.setOrder(2);
|
||||
resolver.setCacheable(false);
|
||||
return resolver;
|
||||
@ -92,7 +96,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
@Bean
|
||||
public AsciiDoctorTemplateResolver asciiDoctorTemplateResolver(Language language) {
|
||||
AsciiDoctorTemplateResolver resolver = new AsciiDoctorTemplateResolver(pluginTargetDirectory, language);
|
||||
resolver.setCacheable(true);
|
||||
resolver.setCacheable(false);
|
||||
resolver.setOrder(3);
|
||||
return resolver;
|
||||
}
|
||||
@ -116,11 +120,18 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/plugin_lessons/**").addResourceLocations("file:///" + pluginTargetDirectory.toString() + "/");
|
||||
//registry.addResourceHandler("/images/**").addResourceLocations("classpath:/plugin/VulnerableComponents/images/");
|
||||
registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/");
|
||||
registry.addResourceHandler("/lesson_js/**").addResourceLocations("classpath:/js/");
|
||||
registry.addResourceHandler("/lesson_css/**").addResourceLocations("classpath:/css/");
|
||||
super.addResourceHandlers(registry);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PluginMessages pluginMessages(Messages messages, Language language) {
|
||||
return new PluginMessages(messages, language);
|
||||
PluginMessages pluginMessages = new PluginMessages(messages, language);
|
||||
pluginMessages.setBasenames("i18n/WebGoatLabels");
|
||||
return pluginMessages;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ -131,7 +142,7 @@ public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
@Bean
|
||||
public Messages messageSource(Language language) {
|
||||
Messages messages = new Messages(language);
|
||||
messages.setBasename("classpath:/i18n/messages");
|
||||
messages.setBasename("classpath:i18n/messages");
|
||||
return messages;
|
||||
}
|
||||
|
||||
|
@ -34,13 +34,9 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.catalina.Context;
|
||||
import org.owasp.webgoat.i18n.PluginMessages;
|
||||
import org.owasp.webgoat.plugins.PluginClassLoader;
|
||||
import org.owasp.webgoat.plugins.PluginEndpointPublisher;
|
||||
import org.owasp.webgoat.plugins.PluginsExtractor;
|
||||
import org.owasp.webgoat.plugins.PluginsLoader;
|
||||
import org.owasp.webgoat.session.*;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@ -86,16 +82,6 @@ public class WebGoat extends SpringBootServletInitializer {
|
||||
return new File(webgoatHome);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PluginClassLoader pluginClassLoader() {
|
||||
return new PluginClassLoader(PluginClassLoader.class.getClassLoader());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PluginsExtractor pluginsLoader(@Qualifier("pluginTargetDirectory") File pluginTargetDirectory, PluginClassLoader classLoader, PluginMessages messages) {
|
||||
return new PluginsExtractor(pluginTargetDirectory, classLoader, messages);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
|
||||
public WebSession webSession(WebgoatContext webgoatContext) {
|
||||
@ -114,8 +100,8 @@ public class WebGoat extends SpringBootServletInitializer {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Course course(PluginsExtractor extractor, PluginEndpointPublisher pluginEndpointPublisher) {
|
||||
return new PluginsLoader(extractor, pluginEndpointPublisher).loadPlugins();
|
||||
public Course course(PluginEndpointPublisher pluginEndpointPublisher) {
|
||||
return new PluginsLoader(pluginEndpointPublisher).loadPlugins();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
/**
|
||||
*************************************************************************************************
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
@ -25,11 +25,13 @@
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @since December 12, 2015
|
||||
* @version $Id: $Id
|
||||
* @since December 12, 2015
|
||||
*/
|
||||
package org.owasp.webgoat;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webgoat.users.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -45,16 +47,20 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
* Security configuration for WebGoat.
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final UserService userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry security = http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/css/**", "/images/**", "/js/**", "fonts/**", "/plugins/**").permitAll()
|
||||
.antMatchers("/css/**", "/images/**", "/js/**", "fonts/**", "/plugins/**", "/registration", "/register.mvc").permitAll()
|
||||
.antMatchers("/servlet/AdminServlet/**").hasAnyRole("WEBGOAT_ADMIN", "SERVER_ADMIN") //
|
||||
.antMatchers("/JavaSource/**").hasRole("SERVER_ADMIN") //
|
||||
.anyRequest().hasAnyRole("WEBGOAT_USER", "WEBGOAT_ADMIN", "SERVER_ADMIN");
|
||||
.anyRequest().authenticated();
|
||||
security.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
@ -79,15 +85,12 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
.withUser("guest").password("guest").roles("WEBGOAT_USER").and() //
|
||||
.withUser("webgoat").password("webgoat").roles("WEBGOAT_ADMIN").and() //
|
||||
.withUser("server").password("server").roles("SERVER_ADMIN");
|
||||
auth.userDetailsService(userDetailsService); //.passwordEncoder(bCryptPasswordEncoder());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public UserDetailsService userDetailsServiceBean() throws Exception {
|
||||
return super.userDetailsServiceBean();
|
||||
return userDetailsService;
|
||||
}
|
||||
}
|
@ -25,35 +25,10 @@
|
||||
|
||||
package org.owasp.webgoat.assignments;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public abstract class Endpoint implements MvcEndpoint {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("pluginTargetDirectory")
|
||||
private File pluginDirectory;
|
||||
|
||||
/**
|
||||
* The directory of the plugin directory in which the lessons resides, so if you want to access the lesson 'ClientSideFiltering' you will
|
||||
* need to:
|
||||
*
|
||||
* <code>
|
||||
* File lessonDirectory = new File(getPluginDirectory(), "ClientSideFiltering");
|
||||
* </code>
|
||||
*
|
||||
* The directory structure of the lesson is exactly the same as the directory structure in the plugins project.
|
||||
*
|
||||
* @return the top level
|
||||
*/
|
||||
protected File getPluginDirectory() {
|
||||
return new File(this.pluginDirectory, "plugin");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final boolean isSensitive() {
|
||||
return false;
|
||||
|
@ -55,7 +55,7 @@ public class Welcome {
|
||||
* @param request a {@link javax.servlet.http.HttpServletRequest} object.
|
||||
* @return a {@link org.springframework.web.servlet.ModelAndView} object.
|
||||
*/
|
||||
@RequestMapping(path = "welcome.mvc", method = RequestMethod.GET)
|
||||
@RequestMapping(path = {"welcome.mvc", "/"}, method = RequestMethod.GET)
|
||||
public ModelAndView welcome(HttpServletRequest request) {
|
||||
|
||||
// set the welcome attribute
|
||||
|
@ -27,29 +27,45 @@ 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.net.URL;
|
||||
import java.util.Enumeration;
|
||||
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.
|
||||
* Message resource bundle for plugins.
|
||||
*
|
||||
* @author nbaars
|
||||
* @date 2/4/17
|
||||
*/
|
||||
public class PluginMessages extends ReloadableResourceBundleMessageSource {
|
||||
private static final String PROPERTIES_SUFFIX = ".properties";
|
||||
|
||||
private Language language;
|
||||
|
||||
public PluginMessages(Messages messages, Language language) {
|
||||
this.language = language;
|
||||
this.setParentMessageSource(messages);
|
||||
this.setBasename("WebGoatLabels");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
protected PropertiesHolder refreshProperties(String filename, PropertiesHolder propHolder) {
|
||||
Properties properties = new Properties();
|
||||
long lastModified = System.currentTimeMillis();
|
||||
|
||||
Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(filename + PROPERTIES_SUFFIX);
|
||||
while (resources.hasMoreElements()) {
|
||||
URL resource = resources.nextElement();
|
||||
String sourcePath = resource.toURI().toString().replace(PROPERTIES_SUFFIX, "");
|
||||
PropertiesHolder holder = super.refreshProperties(sourcePath, propHolder);
|
||||
properties.putAll(holder.getProperties());
|
||||
}
|
||||
return new PropertiesHolder(properties, lastModified);
|
||||
}
|
||||
|
||||
|
||||
public Properties getMessages() {
|
||||
return getMergedProperties(language.getLocale()).getProperties();
|
||||
}
|
||||
@ -61,20 +77,4 @@ public class PluginMessages extends ReloadableResourceBundleMessageSource {
|
||||
public String getMessage(String code, String defaultValue, Object... args) {
|
||||
return super.getMessage(code, args, defaultValue, language.getLocale());
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* 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.plugins;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
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
|
||||
*/
|
||||
public class MessagePropertyMerger {
|
||||
|
||||
private final File targetDirectory;
|
||||
|
||||
public MessagePropertyMerger(File targetDirectory) {
|
||||
this.targetDirectory = targetDirectory;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void merge(ZipFile zipFile, ZipEntry zipEntry) {
|
||||
Properties messageProperties = new Properties();
|
||||
try (InputStream zis = zipFile.getInputStream(zipEntry)) {
|
||||
messageProperties.load(zis);
|
||||
}
|
||||
|
||||
Properties messagesFromHome = new Properties();
|
||||
File pluginMessageFiles = new File(targetDirectory, zipEntry.getName());
|
||||
if (pluginMessageFiles.exists()) {
|
||||
try (FileInputStream fis = new FileInputStream(pluginMessageFiles)) {
|
||||
messagesFromHome.load(fis);
|
||||
}
|
||||
}
|
||||
|
||||
messageProperties.putAll(messagesFromHome);
|
||||
|
||||
createParentDirs(pluginMessageFiles);
|
||||
try (FileOutputStream fos = new FileOutputStream(pluginMessageFiles)) {
|
||||
messageProperties.store(fos, "Plugin message properties");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.Endpoint;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.owasp.webgoat.plugins.PluginFileUtils.fileEndsWith;
|
||||
|
||||
/**
|
||||
* <p>Plugin class.</p>
|
||||
*
|
||||
* @author dm
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
public class Plugin {
|
||||
|
||||
@Getter
|
||||
private final String originationJar;
|
||||
private PluginClassLoader classLoader;
|
||||
private Class<NewLesson> newLesson;
|
||||
@Getter
|
||||
private List<Class<AssignmentEndpoint>> assignments = Lists.newArrayList();
|
||||
@Getter
|
||||
private List<Class<Endpoint>> endpoints = Lists.newArrayList();
|
||||
private List<File> pluginFiles = Lists.newArrayList();
|
||||
|
||||
public Plugin(PluginClassLoader classLoader, String originatingJar) {
|
||||
this.classLoader = classLoader;
|
||||
this.originationJar = originatingJar;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>findLesson.</p>
|
||||
*
|
||||
* @param classes a {@link java.util.List} object.
|
||||
*/
|
||||
public void findLesson(List<String> classes) {
|
||||
for (String clazzName : classes) {
|
||||
findLesson(clazzName);
|
||||
}
|
||||
}
|
||||
|
||||
private void findLesson(String name) {
|
||||
String realClassName = StringUtils.trimLeadingCharacter(name, '/').replaceAll("/", ".").replaceAll(".class", "");
|
||||
|
||||
try {
|
||||
Class clazz = classLoader.loadClass(realClassName);
|
||||
if (NewLesson.class.isAssignableFrom(clazz)) {
|
||||
this.newLesson = clazz;
|
||||
}
|
||||
} catch (ClassNotFoundException ce) {
|
||||
throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce);
|
||||
}
|
||||
}
|
||||
|
||||
public void findEndpoints(List<String> classes) {
|
||||
for (String clazzName : classes) {
|
||||
String realClassName = StringUtils.trimLeadingCharacter(clazzName, '/').replaceAll("/", ".").replaceAll(".class", "");
|
||||
|
||||
try {
|
||||
Class clazz = classLoader.loadClass(realClassName);
|
||||
|
||||
if (AssignmentEndpoint.class.isAssignableFrom(clazz)) {
|
||||
this.assignments.add(clazz);
|
||||
} else
|
||||
if (Endpoint.class.isAssignableFrom(clazz)) {
|
||||
this.endpoints.add(clazz);
|
||||
}
|
||||
} catch (ClassNotFoundException ce) {
|
||||
throw new PluginLoadingFailure("Class " + realClassName + " listed in jar but unable to load the class.", ce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>loadFiles.</p>
|
||||
*
|
||||
* @param file a {@link java.nio.file.Path} object.
|
||||
*/
|
||||
public void loadFiles(Path file) {
|
||||
if (fileEndsWith(file, ".css", ".jsp", ".js")) {
|
||||
pluginFiles.add(file.toFile());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lesson is optional, it is also possible that the supplied jar contains only helper classes.
|
||||
*
|
||||
* @return a {@link com.google.common.base.Optional} object.
|
||||
*/
|
||||
public Optional<AbstractLesson> getLesson() {
|
||||
try {
|
||||
if (newLesson != null) {
|
||||
AbstractLesson lesson = newLesson.newInstance();
|
||||
lesson.setAssignments(createAssignment(assignments));
|
||||
return Optional.of(lesson);
|
||||
}
|
||||
} catch (IllegalAccessException | InstantiationException e) {
|
||||
throw new PluginLoadingFailure("Unable to instantiate the lesson " + newLesson.getName(), e);
|
||||
}
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
|
||||
private List<Assignment> createAssignment(List<Class<AssignmentEndpoint>> endpoints) {
|
||||
return endpoints.stream().map(e -> new Assignment(e.getSimpleName(), getPath(e), getHints(e))).collect(toList());
|
||||
}
|
||||
|
||||
private String getPath(Class<AssignmentEndpoint> e) {
|
||||
return e.getAnnotationsByType(AssignmentPath.class)[0].value();
|
||||
}
|
||||
|
||||
private List<String> getHints(Class<AssignmentEndpoint> e) {
|
||||
if (e.isAnnotationPresent(AssignmentHints.class)) {
|
||||
return Lists.newArrayList(e.getAnnotationsByType(AssignmentHints.class)[0].value());
|
||||
}
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
public class PluginClassLoader extends URLClassLoader {
|
||||
|
||||
public PluginClassLoader(ClassLoader parent) {
|
||||
super(new URL[] {}, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(URL url) {
|
||||
super.addURL(url);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.assignments.Endpoint;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
@ -9,6 +10,8 @@ import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
@ -47,9 +50,8 @@ public class PluginEndpointPublisher {
|
||||
this.applicationContext = (AbstractApplicationContext) applicationContext;
|
||||
}
|
||||
|
||||
public void publish(Plugin plugin) {
|
||||
plugin.getAssignments().forEach(e -> publishEndpoint(e));
|
||||
plugin.getEndpoints().forEach(e -> publishEndpoint(e));
|
||||
public void publish(List<Class<Endpoint>> endpoints) {
|
||||
endpoints.forEach(e -> publishEndpoint(e));
|
||||
}
|
||||
|
||||
private void publishEndpoint(Class<? extends MvcEndpoint> e) {
|
||||
|
@ -1,123 +0,0 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.Files;
|
||||
import org.apache.commons.fileupload.util.Streams;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* Extract the jar file and place them in the system temp directory in the folder webgoat and collect the files
|
||||
* and classes.
|
||||
*
|
||||
* @author dm
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
public class PluginExtractor {
|
||||
|
||||
private final List<String> classes = Lists.newArrayList();
|
||||
private final List<Path> files = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* <p>extractJarFile.</p>
|
||||
*
|
||||
* @param archive a {@link java.io.File} object.
|
||||
* @param targetDirectory a {@link java.io.File} object.
|
||||
* @return a {@link org.owasp.webgoat.plugins.Plugin} object.
|
||||
* @throws java.io.IOException if any.
|
||||
*/
|
||||
public Plugin extractJarFile(final File archive, final File targetDirectory, PluginClassLoader cl) throws IOException {
|
||||
ZipFile zipFile = new ZipFile(archive);
|
||||
Plugin plugin = new Plugin(cl, zipFile.getName());
|
||||
try {
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
final ZipEntry zipEntry = entries.nextElement();
|
||||
if (shouldProcessFile(zipEntry)) {
|
||||
boolean processed = processClassFile(zipFile, zipEntry, targetDirectory);
|
||||
|
||||
if (!processed) {
|
||||
processed = processPropertyFile(zipFile, zipEntry, targetDirectory);
|
||||
}
|
||||
if (!processed) {
|
||||
processFile(plugin, zipFile, zipEntry, targetDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
plugin.findLesson(this.classes);
|
||||
plugin.findEndpoints(this.classes);
|
||||
zipFile.close();
|
||||
}
|
||||
return plugin;
|
||||
}
|
||||
|
||||
private void processFile(Plugin plugin, ZipFile zipFile, ZipEntry zipEntry, File targetDirectory)
|
||||
throws IOException {
|
||||
final File targetFile = new File(targetDirectory, zipEntry.getName());
|
||||
copyFile(zipFile, zipEntry, targetFile, false);
|
||||
plugin.loadFiles(targetFile.toPath());
|
||||
}
|
||||
|
||||
private boolean processPropertyFile(ZipFile zipFile, ZipEntry zipEntry, File targetDirectory)
|
||||
throws IOException {
|
||||
if (zipEntry.getName().endsWith(".properties")) {
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean processClassFile(ZipFile zipFile, ZipEntry zipEntry, File targetDirectory) throws IOException {
|
||||
if (zipEntry.getName().endsWith(".class")) {
|
||||
classes.add(zipEntry.getName());
|
||||
final File targetFile = new File(targetDirectory, zipEntry.getName());
|
||||
copyFile(zipFile, zipEntry, targetFile, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shouldProcessFile(ZipEntry zipEntry) {
|
||||
return !zipEntry.isDirectory() && !zipEntry.getName().startsWith("META-INF");
|
||||
}
|
||||
|
||||
private File copyFile(ZipFile zipFile, ZipEntry zipEntry, File targetFile, boolean append) throws IOException {
|
||||
Files.createParentDirs(targetFile);
|
||||
try (FileOutputStream fos = new FileOutputStream(targetFile, append)) {
|
||||
Streams.copy(zipFile.getInputStream(zipEntry), fos, true);
|
||||
}
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Getter for the field <code>classes</code>.</p>
|
||||
*
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
public List<String> getClasses() {
|
||||
return this.classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Getter for the field <code>files</code>.</p>
|
||||
*
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
public List<Path> getFiles() {
|
||||
return this.files;
|
||||
}
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* <p>PluginFileUtils class.</p>
|
||||
*
|
||||
* @version $Id: $Id
|
||||
* @author dm
|
||||
*/
|
||||
@UtilityClass
|
||||
public class PluginFileUtils {
|
||||
|
||||
/**
|
||||
* <p>fileEndsWith.</p>
|
||||
*
|
||||
* @param p a {@link java.nio.file.Path} object.
|
||||
* @param s a {@link java.lang.String} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean fileEndsWith(Path p, String s) {
|
||||
return p.getFileName().toString().endsWith(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>fileEndsWith.</p>
|
||||
*
|
||||
* @param p a {@link java.nio.file.Path} object.
|
||||
* @param suffixes a {@link java.lang.String} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean fileEndsWith(Path p, String... suffixes) {
|
||||
for (String suffix : suffixes) {
|
||||
if (fileEndsWith(p, suffix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>hasParentDirectoryWithName.</p>
|
||||
*
|
||||
* @param p a {@link java.nio.file.Path} object.
|
||||
* @param s a {@link java.lang.String} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean hasParentDirectoryWithName(Path p, String s) {
|
||||
if (p == null || p.getParent() == null || p.getParent().equals(p.getRoot())) {
|
||||
return false;
|
||||
}
|
||||
if (p.getParent().getFileName().toString().equals(s)) {
|
||||
return true;
|
||||
}
|
||||
return hasParentDirectoryWithName(p.getParent(), s);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>replaceInFiles.</p>
|
||||
*
|
||||
* @param replace a {@link java.lang.String} object.
|
||||
* @param with a {@link java.lang.String} object.
|
||||
* @param files a {@link java.util.Collection} object.
|
||||
* @throws java.io.IOException if any.
|
||||
*/
|
||||
public static void replaceInFiles(String replace, String with, Collection<File> files) throws IOException {
|
||||
Preconditions.checkNotNull(replace);
|
||||
Preconditions.checkNotNull(with);
|
||||
Preconditions.checkNotNull(files);
|
||||
|
||||
for (File file : files) {
|
||||
replaceInFile(replace, with, file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>replaceInFile.</p>
|
||||
*
|
||||
* @param replace a {@link java.lang.String} object.
|
||||
* @param with a {@link java.lang.String} object.
|
||||
* @param file a {@link java.nio.file.Path} object.
|
||||
* @throws java.io.IOException if any.
|
||||
*/
|
||||
public static void replaceInFile(String replace, String with, File file) throws IOException {
|
||||
Preconditions.checkNotNull(replace);
|
||||
Preconditions.checkNotNull(with);
|
||||
Preconditions.checkNotNull(file);
|
||||
|
||||
String fileAsString = "";
|
||||
try (FileInputStream fis = new FileInputStream(file);) {
|
||||
fileAsString = IOUtils.toString(fis, StandardCharsets.UTF_8.name());
|
||||
fileAsString = fileAsString.replaceAll(replace, with);
|
||||
}
|
||||
Files.write(file.toPath(), fileAsString.getBytes());
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.Endpoint;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Plugin resource
|
||||
*
|
||||
* @author nbaars
|
||||
* @since 3/4/17.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class PluginResource {
|
||||
|
||||
private final URL location;
|
||||
private final List<Class> classes;
|
||||
|
||||
public Optional<Class> getLesson() {
|
||||
return classes.stream().filter(c -> c.getSuperclass() == NewLesson.class).findFirst();
|
||||
}
|
||||
|
||||
public List<Class<Endpoint>> getEndpoints() {
|
||||
return classes.stream().
|
||||
filter(c -> c.getSuperclass() == AssignmentEndpoint.class || c.getSuperclass() == Endpoint.class).
|
||||
map(c -> (Class<Endpoint>)c).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Class<AssignmentEndpoint>> getAssignments() {
|
||||
return classes.stream().
|
||||
filter(c -> c.getSuperclass() == AssignmentEndpoint.class).
|
||||
map(c -> (Class<AssignmentEndpoint>)c).
|
||||
collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.webgoat.i18n.PluginMessages;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
/**
|
||||
* <p>PluginsLoader class.</p>
|
||||
*
|
||||
* @author dm
|
||||
* @version $Id: $Id
|
||||
*/
|
||||
@Slf4j
|
||||
public class PluginsExtractor {
|
||||
|
||||
private static final String WEBGOAT_PLUGIN_EXTENSION = "jar";
|
||||
private static final int BUFFER_SIZE = 32 * 1024;
|
||||
private final File pluginTargetDirectory;
|
||||
private final PluginClassLoader classLoader;
|
||||
private final PluginMessages messages;
|
||||
|
||||
public PluginsExtractor(File pluginTargetDirectory, PluginClassLoader pluginClassLoader, PluginMessages messages) {
|
||||
this.classLoader = pluginClassLoader;
|
||||
this.pluginTargetDirectory = pluginTargetDirectory;
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>loadPlugins.</p>
|
||||
*
|
||||
* @return a {@link java.util.List} object.
|
||||
*/
|
||||
public List<Plugin> loadPlugins() {
|
||||
List<Plugin> plugins = Lists.newArrayList();
|
||||
try {
|
||||
URL location = this.getClass().getProtectionDomain().getCodeSource().getLocation();
|
||||
log.trace("Determining whether we run as standalone jar or as directory...");
|
||||
if (ResourceUtils.isFileURL(location)) {
|
||||
log.trace("Running from directory, copying lessons from {}", location.toString());
|
||||
extractToTargetDirectoryFromExplodedDirectory(ResourceUtils.getFile(location));
|
||||
} else {
|
||||
log.trace("Running from standalone jar, extracting lessons from {}", location.toString());
|
||||
extractToTargetDirectoryFromJarFile(ResourceUtils.getFile(ResourceUtils.extractJarFileURL(location)));
|
||||
}
|
||||
List<URL> jars = listJars();
|
||||
plugins = processPlugins(jars);
|
||||
} catch (Exception e) {
|
||||
log.error("Loading plugins failed", e);
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
|
||||
private void extractToTargetDirectoryFromJarFile(File jarFile) throws IOException {
|
||||
ZipFile jar = new ZipFile(jarFile);
|
||||
Enumeration<? extends ZipEntry> entries = jar.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry zipEntry = entries.nextElement();
|
||||
if (zipEntry.getName().contains("plugin_lessons") && zipEntry.getName().endsWith(".jar")) {
|
||||
unpack(jar, zipEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void unpack(ZipFile jar, ZipEntry zipEntry) throws IOException {
|
||||
try (InputStream inputStream = jar.getInputStream(zipEntry)) {
|
||||
String name = zipEntry.getName();
|
||||
if (name.lastIndexOf("/") != -1) {
|
||||
name = name.substring(name.lastIndexOf("/") + 1);
|
||||
}
|
||||
try (OutputStream outputStream = new FileOutputStream(new File(pluginTargetDirectory, name))) {
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int bytesRead = -1;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
log.trace("Extracting {} to {}", jar.getName(), pluginTargetDirectory);
|
||||
}
|
||||
|
||||
private void extractToTargetDirectoryFromExplodedDirectory(File directory) throws IOException {
|
||||
Files.walkFileTree(directory.toPath(), new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
if (dir.endsWith("plugin_lessons")) {
|
||||
log.trace("Copying {} to {}", dir.toString(), pluginTargetDirectory);
|
||||
FileUtils.copyDirectory(dir.toFile(), pluginTargetDirectory);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<URL> listJars() throws Exception {
|
||||
final List<URL> jars = Lists.newArrayList();
|
||||
Files.walkFileTree(Paths.get(pluginTargetDirectory.toURI()), new SimpleFileVisitor<Path>() {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (PluginFileUtils.fileEndsWith(file, WEBGOAT_PLUGIN_EXTENSION)) {
|
||||
jars.add(file.toUri().toURL());
|
||||
log.trace("Found jar file at location: {}", file.toString());
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
return jars;
|
||||
}
|
||||
|
||||
private List<Plugin> processPlugins(List<URL> jars) throws Exception {
|
||||
final ExecutorService executorService = Executors.newFixedThreadPool(10);
|
||||
try {
|
||||
final List<Plugin> plugins = Lists.newArrayList();
|
||||
final CompletionService<Plugin> completionService = new ExecutorCompletionService<>(executorService);
|
||||
final List<Callable<Plugin>> callables = extractJars(jars);
|
||||
|
||||
callables.forEach(s -> completionService.submit(s));
|
||||
int n = callables.size();
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
Plugin plugin = completionService.take().get();
|
||||
if (plugin.getLesson().isPresent()) {
|
||||
log.trace("Plugin jar '{}' contains a lesson, loading into WebGoat...", plugin.getOriginationJar());
|
||||
plugins.add(plugin);
|
||||
} else {
|
||||
log.trace("Plugin jar: '{}' does not contain a lesson not processing as a plugin (can be a utility jar)",
|
||||
plugin.getOriginationJar());
|
||||
}
|
||||
}
|
||||
messages.addPluginMessageBundles(new File(pluginTargetDirectory, "plugin/i18n"));
|
||||
return plugins;
|
||||
} finally {
|
||||
executorService.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private List<Callable<Plugin>> extractJars(List<URL> jars) {
|
||||
List<Callable<Plugin>> extractorCallables = Lists.newArrayList();
|
||||
|
||||
for (final URL jar : jars) {
|
||||
classLoader.addURL(jar);
|
||||
extractorCallables.add(() -> {
|
||||
PluginExtractor extractor = new PluginExtractor();
|
||||
return extractor.extractJarFile(ResourceUtils.getFile(jar), pluginTargetDirectory, classLoader);
|
||||
});
|
||||
}
|
||||
return extractorCallables;
|
||||
}
|
||||
}
|
@ -1,13 +1,29 @@
|
||||
package org.owasp.webgoat.plugins;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
import org.owasp.webgoat.session.Course;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
@ -42,7 +58,6 @@ import java.util.List;
|
||||
@Slf4j
|
||||
public class PluginsLoader {
|
||||
|
||||
private final PluginsExtractor extractor;
|
||||
private final PluginEndpointPublisher pluginEndpointPublisher;
|
||||
|
||||
/**
|
||||
@ -50,11 +65,15 @@ public class PluginsLoader {
|
||||
*/
|
||||
public Course loadPlugins() {
|
||||
List<AbstractLesson> lessons = Lists.newArrayList();
|
||||
for (Plugin plugin : extractor.loadPlugins()) {
|
||||
for (PluginResource plugin : findPluginResources()) {
|
||||
try {
|
||||
NewLesson lesson = (NewLesson) plugin.getLesson().get();
|
||||
Class lessonClazz = plugin.getLesson()
|
||||
.orElseThrow(() -> new PluginLoadingFailure("Plugin resource does not contain lesson"));
|
||||
NewLesson lesson = (NewLesson) lessonClazz.newInstance();
|
||||
List<Class<AssignmentEndpoint>> assignments = plugin.getAssignments();
|
||||
lesson.setAssignments(createAssignment(assignments));
|
||||
lessons.add(lesson);
|
||||
pluginEndpointPublisher.publish(plugin);
|
||||
pluginEndpointPublisher.publish(plugin.getEndpoints());
|
||||
} catch (Exception e) {
|
||||
log.error("Error in loadLessons: ", e);
|
||||
}
|
||||
@ -67,4 +86,43 @@ public class PluginsLoader {
|
||||
return new Course(lessons);
|
||||
}
|
||||
|
||||
private List<Assignment> createAssignment(List<Class<AssignmentEndpoint>> endpoints) {
|
||||
return endpoints.stream().map(e -> new Assignment(e.getSimpleName(), getPath(e), getHints(e))).collect(toList());
|
||||
}
|
||||
|
||||
private String getPath(Class<AssignmentEndpoint> e) {
|
||||
return e.getAnnotationsByType(AssignmentPath.class)[0].value();
|
||||
}
|
||||
|
||||
private List<String> getHints(Class<AssignmentEndpoint> e) {
|
||||
if (e.isAnnotationPresent(AssignmentHints.class)) {
|
||||
return Lists.newArrayList(e.getAnnotationsByType(AssignmentHints.class)[0].value());
|
||||
}
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public List<PluginResource> findPluginResources() {
|
||||
final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
|
||||
provider.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile(".*")));
|
||||
final Set<BeanDefinition> classes = provider.findCandidateComponents("org.owasp.webgoat.plugin");
|
||||
Map<URL, List<Class>> pluginClasses = Maps.newHashMap();
|
||||
for (BeanDefinition bean : classes) {
|
||||
Class<?> clazz = Class.forName(bean.getBeanClassName());
|
||||
URL location = clazz.getProtectionDomain().getCodeSource().getLocation();
|
||||
List<Class> classFiles = pluginClasses.get(location);
|
||||
if (classFiles == null) {
|
||||
classFiles = Lists.newArrayList(clazz);
|
||||
} else {
|
||||
classFiles.add(clazz);
|
||||
}
|
||||
pluginClasses.put(location, classFiles);
|
||||
}
|
||||
return pluginClasses.entrySet().parallelStream()
|
||||
.map(e -> new PluginResource(e.getKey(), e.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,11 +6,12 @@ import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.lessons.Assignment;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.SerializationUtils;
|
||||
import org.springframework.core.serializer.DefaultDeserializer;
|
||||
import org.springframework.core.serializer.DefaultSerializer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -50,7 +51,6 @@ public class UserTracker {
|
||||
|
||||
private final String webgoatHome;
|
||||
private final String user;
|
||||
private Map<String, LessonTracker> storage = new HashMap<>();
|
||||
|
||||
public UserTracker(final String webgoatHome, final String user) {
|
||||
this.webgoatHome = webgoatHome;
|
||||
@ -64,53 +64,72 @@ public class UserTracker {
|
||||
* @return the optional lesson tracker
|
||||
*/
|
||||
public LessonTracker getLessonTracker(AbstractLesson lesson) {
|
||||
return getLessonTracker(load(), lesson);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lesson tracker for a specific lesson if available.
|
||||
*
|
||||
* @param lesson the lesson
|
||||
* @return the optional lesson tracker
|
||||
*/
|
||||
public LessonTracker getLessonTracker(Map<String, LessonTracker> storage, AbstractLesson lesson) {
|
||||
LessonTracker lessonTracker = storage.get(lesson.getTitle());
|
||||
if (lessonTracker == null) {
|
||||
lessonTracker = new LessonTracker(lesson);
|
||||
storage.put(lesson.getTitle(), lessonTracker);
|
||||
save(storage);
|
||||
}
|
||||
return lessonTracker;
|
||||
}
|
||||
|
||||
public void assignmentSolved(AbstractLesson lesson, String assignmentName) {
|
||||
LessonTracker lessonTracker = getLessonTracker(lesson);
|
||||
Map<String, LessonTracker> storage = load();
|
||||
LessonTracker lessonTracker = storage.get(lesson.getTitle());
|
||||
lessonTracker.incrementAttempts();
|
||||
lessonTracker.assignmentSolved(assignmentName);
|
||||
save();
|
||||
save(storage);
|
||||
}
|
||||
|
||||
public void assignmentFailed(AbstractLesson lesson) {
|
||||
LessonTracker lessonTracker = getLessonTracker(lesson);
|
||||
Map<String, LessonTracker> storage = load();
|
||||
LessonTracker lessonTracker = storage.get(lesson.getTitle());
|
||||
lessonTracker.incrementAttempts();
|
||||
save();
|
||||
save(storage);
|
||||
}
|
||||
|
||||
public void load() {
|
||||
public Map<String, LessonTracker> load() {
|
||||
File file = new File(webgoatHome, user + ".progress");
|
||||
if (file.exists() && file.isFile()) {
|
||||
try {
|
||||
this.storage = (Map<String, LessonTracker>) SerializationUtils.deserialize(FileCopyUtils.copyToByteArray(file));
|
||||
DefaultDeserializer deserializer = new DefaultDeserializer(Thread.currentThread().getContextClassLoader());
|
||||
return (Map<String, LessonTracker>) deserializer.deserialize(new FileInputStream(file));
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to read the progress file, creating a new one...");
|
||||
this.storage = Maps.newHashMap();
|
||||
|
||||
}
|
||||
}
|
||||
return Maps.newHashMap();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private void save() {
|
||||
private void save(Map<String, LessonTracker> storage) {
|
||||
File file = new File(webgoatHome, user + ".progress");
|
||||
FileCopyUtils.copy(SerializationUtils.serialize(this.storage), file);
|
||||
DefaultSerializer serializer = new DefaultSerializer();
|
||||
serializer.serialize(storage, new FileOutputStream(file));
|
||||
}
|
||||
|
||||
|
||||
public void reset(AbstractLesson al) {
|
||||
getLessonTracker(al).reset();
|
||||
save();
|
||||
Map<String, LessonTracker> storage = load();
|
||||
LessonTracker lessonTracker = getLessonTracker(storage, al);
|
||||
lessonTracker.reset();
|
||||
save(storage);
|
||||
}
|
||||
|
||||
public int numberOfLessonsSolved() {
|
||||
int numberOfLessonsSolved = 0;
|
||||
Map<String, LessonTracker> storage = load();
|
||||
for (LessonTracker lessonTracker : storage.values()) {
|
||||
if (lessonTracker.isLessonSolved()) {
|
||||
numberOfLessonsSolved = numberOfLessonsSolved + 1;
|
||||
@ -121,6 +140,7 @@ public class UserTracker {
|
||||
|
||||
public int numberOfAssignmentsSolved() {
|
||||
int numberOfAssignmentsSolved = 0;
|
||||
Map<String, LessonTracker> storage = load();
|
||||
for (LessonTracker lessonTracker : storage.values()) {
|
||||
Map<Assignment, Boolean> lessonOverview = lessonTracker.getLessonOverview();
|
||||
numberOfAssignmentsSolved = lessonOverview.values().stream().filter(b -> b).collect(Collectors.counting()).intValue();
|
||||
|
@ -0,0 +1,71 @@
|
||||
package org.owasp.webgoat.session;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Transient;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Getter
|
||||
@Entity
|
||||
public class WebGoatUser implements UserDetails {
|
||||
|
||||
public static final String ROLE_USER = "WEBGOAT_USER";
|
||||
public static final String ROLE_ADMIN = "WEBGOAT_ADMIN";
|
||||
|
||||
@Id
|
||||
private String username;
|
||||
private String password;
|
||||
private String role = ROLE_USER;
|
||||
@Transient
|
||||
private User user;
|
||||
|
||||
protected WebGoatUser() {
|
||||
}
|
||||
|
||||
public WebGoatUser(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
createUser();
|
||||
}
|
||||
|
||||
public void createUser() {
|
||||
this.user = new User(username, password, getAuthorities());
|
||||
}
|
||||
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return Collections.singleton(new SimpleGrantedAuthority(getRole()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return this.user.isAccountNonExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return this.user.isAccountNonLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return this.user.isCredentialsNonExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.user.isEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ package org.owasp.webgoat.session;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
@ -40,10 +39,9 @@ import java.sql.SQLException;
|
||||
@Slf4j
|
||||
public class WebSession {
|
||||
|
||||
private final User currentUser;
|
||||
private final WebGoatUser currentUser;
|
||||
private final WebgoatContext webgoatContext;
|
||||
private AbstractLesson currentLesson;
|
||||
private UserTracker userTracker;
|
||||
|
||||
/**
|
||||
* Constructor for the WebSession object
|
||||
@ -52,7 +50,7 @@ public class WebSession {
|
||||
*/
|
||||
public WebSession(WebgoatContext webgoatContext) {
|
||||
this.webgoatContext = webgoatContext;
|
||||
this.currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
this.currentUser = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,61 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.session.WebGoatUser;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Controller
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class RegistrationController {
|
||||
|
||||
private UserValidator userValidator;
|
||||
private UserService userService;
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@GetMapping("/registration")
|
||||
public String showForm(UserForm userForm) {
|
||||
return "registration";
|
||||
}
|
||||
|
||||
@PostMapping("/register.mvc")
|
||||
public String registration(@ModelAttribute("userForm") @Valid UserForm userForm, BindingResult bindingResult) {
|
||||
userValidator.validate(userForm, bindingResult);
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
return "registration";
|
||||
}
|
||||
userService.addUser(userForm.getUsername(), userForm.getPassword());
|
||||
autologin(userForm.getUsername(), userForm.getPassword());
|
||||
|
||||
return "redirect:/attack";
|
||||
}
|
||||
|
||||
private void autologin(String username, String password) {
|
||||
WebGoatUser user = userService.loadUserByUsername(username);
|
||||
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
|
||||
|
||||
authenticationManager.authenticate(usernamePasswordAuthenticationToken);
|
||||
|
||||
if (usernamePasswordAuthenticationToken.isAuthenticated()) {
|
||||
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
|
||||
log.debug("Login for {} successfully!", username);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class UserForm {
|
||||
|
||||
@NotNull
|
||||
@Size(min=6, max=10)
|
||||
private String username;
|
||||
@NotNull
|
||||
@Size(min=6, max=10)
|
||||
private String password;
|
||||
@NotNull
|
||||
@Size(min=6, max=10)
|
||||
private String matchingPassword;
|
||||
@NotNull
|
||||
private String agree;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import org.owasp.webgoat.session.WebGoatUser;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
public interface UserRepository extends CrudRepository<WebGoatUser, Long> {
|
||||
|
||||
WebGoatUser findByUsername(String username);
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webgoat.session.WebGoatUser;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class UserService implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
WebGoatUser webGoatUser = userRepository.findByUsername(username);
|
||||
webGoatUser.createUser();
|
||||
return webGoatUser;
|
||||
}
|
||||
|
||||
public void addUser(String username, String password) {
|
||||
userRepository.save(new WebGoatUser(username, password));
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.owasp.webgoat.users;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Component
|
||||
public class UserValidator implements Validator {
|
||||
|
||||
// @Autowired
|
||||
// private UserService userService;
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<?> aClass) {
|
||||
return UserForm.class.equals(aClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(Object o, Errors errors) {
|
||||
UserForm userForm = (UserForm) o;
|
||||
|
||||
// if (userService.findByUsername(userForm.getUsername()) != null) {
|
||||
// errors.rejectValue("username", "Duplicate.userForm.username");
|
||||
// }
|
||||
|
||||
if (!userForm.getMatchingPassword().equals(userForm.getPassword())) {
|
||||
errors.rejectValue("matchingPassword", "password.diff");
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user