Password reset link test condition more strict and move all WebWolf links to /WebWolf (#1645)
* better check on host and port for password reset and make context roots more flexible * spotless applied * removed hardcoded /WebGoat from js * removed hardcoded /WebGoat from js * fix spotless * fix scoreboard * upgrade WebWolf bootstrap version and icons and templates - part 1 * fixed more bootstrap 5 style issues and context path issues * organized WebSecurityConfig based on latest conventions and added basic support for oauth (more work needed) * spotless applied * added mock bean * requires updates to properties - commented for now * requires updates to properties - commented for now * oauth secrets through env values * user creation after oauth login * integration test against non default context paths * adjusted StartupMessage * add global model element username * conditionally show login oauth links * fixed WebWolf login --------- Co-authored-by: René Zubcevic <rene@Mac-mini-van-Rene.local>
This commit is contained in:
@ -32,10 +32,9 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.webgoat.webwolf.user.WebGoatUser;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -58,6 +57,9 @@ public class FileServer {
|
||||
@Value("${server.address}")
|
||||
private String server;
|
||||
|
||||
@Value("${server.servlet.context-path}")
|
||||
private String contextPath;
|
||||
|
||||
@Value("${server.port}")
|
||||
private int port;
|
||||
|
||||
@ -71,9 +73,11 @@ public class FileServer {
|
||||
}
|
||||
|
||||
@PostMapping(value = "/fileupload")
|
||||
public ModelAndView importFile(@RequestParam("file") MultipartFile myFile) throws IOException {
|
||||
var user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
var destinationDir = new File(fileLocation, user.getUsername());
|
||||
public ModelAndView importFile(
|
||||
@RequestParam("file") MultipartFile myFile, Authentication authentication)
|
||||
throws IOException {
|
||||
String username = authentication.getName();
|
||||
var destinationDir = new File(fileLocation, username);
|
||||
destinationDir.mkdirs();
|
||||
myFile.transferTo(new File(destinationDir, myFile.getOriginalFilename()));
|
||||
log.debug("File saved to {}", new File(destinationDir, myFile.getOriginalFilename()));
|
||||
@ -92,15 +96,13 @@ public class FileServer {
|
||||
}
|
||||
|
||||
@GetMapping(value = "/files")
|
||||
public ModelAndView getFiles(HttpServletRequest request) {
|
||||
WebGoatUser user =
|
||||
(WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
String username = user.getUsername();
|
||||
public ModelAndView getFiles(HttpServletRequest request, Authentication authentication) {
|
||||
String username = (null != authentication) ? authentication.getName() : "anonymous";
|
||||
File destinationDir = new File(fileLocation, username);
|
||||
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
modelAndView.setViewName("files");
|
||||
File changeIndicatorFile = new File(destinationDir, user.getUsername() + "_changed");
|
||||
File changeIndicatorFile = new File(destinationDir, username + "_changed");
|
||||
if (changeIndicatorFile.exists()) {
|
||||
modelAndView.addObject("uploadSuccess", request.getParameter("uploadSuccess"));
|
||||
}
|
||||
@ -117,7 +119,7 @@ public class FileServer {
|
||||
}
|
||||
|
||||
modelAndView.addObject("files", uploadedFiles);
|
||||
modelAndView.addObject("webwolf_url", "http://" + server + ":" + port);
|
||||
modelAndView.addObject("webwolf_url", "http://" + server + ":" + port + contextPath);
|
||||
return modelAndView;
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,10 @@ package org.owasp.webgoat.webwolf;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import org.owasp.webgoat.container.UserInterceptor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
@ -55,6 +57,12 @@ public class MvcConfiguration implements WebMvcConfigurer {
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/login").setViewName("webwolf-login");
|
||||
registry.addViewController("/home").setViewName("home");
|
||||
registry.addViewController("/").setViewName("home");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new UserInterceptor());
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
|
@ -22,6 +22,7 @@
|
||||
package org.owasp.webgoat.webwolf;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webgoat.container.AjaxAuthenticationEntryPoint;
|
||||
import org.owasp.webgoat.webwolf.user.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -46,16 +47,39 @@ public class WebSecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests(
|
||||
auth -> auth.requestMatchers(HttpMethod.POST, "/fileupload").authenticated());
|
||||
http.authorizeHttpRequests(
|
||||
auth ->
|
||||
auth.requestMatchers(HttpMethod.GET, "/files", "/mail", "/requests").authenticated());
|
||||
http.authorizeHttpRequests().anyRequest().permitAll();
|
||||
http.csrf().disable().formLogin().loginPage("/login").failureUrl("/login?error=true");
|
||||
http.formLogin().loginPage("/login").defaultSuccessUrl("/home", true).permitAll();
|
||||
http.logout().permitAll();
|
||||
return http.build();
|
||||
return http.authorizeHttpRequests(
|
||||
auth -> {
|
||||
auth.requestMatchers("/css/**", "/webjars/**", "/favicon.ico", "/js/**", "/images/**")
|
||||
.permitAll();
|
||||
auth.requestMatchers(
|
||||
HttpMethod.GET,
|
||||
"/fileupload/**",
|
||||
"/files/**",
|
||||
"/landing/**",
|
||||
"/PasswordReset/**")
|
||||
.permitAll();
|
||||
auth.requestMatchers(HttpMethod.POST, "/files", "/mail", "/requests").permitAll();
|
||||
auth.anyRequest().authenticated();
|
||||
})
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.formLogin(
|
||||
login ->
|
||||
login
|
||||
.loginPage("/login")
|
||||
.failureUrl("/login?error=true")
|
||||
.defaultSuccessUrl("/home", true)
|
||||
.usernameParameter("username")
|
||||
.passwordParameter("password")
|
||||
.permitAll())
|
||||
.oauth2Login(
|
||||
oidc -> {
|
||||
oidc.defaultSuccessUrl("/home");
|
||||
})
|
||||
.logout(logout -> logout.deleteCookies("WEBWOLFSESSION").invalidateHttpSession(true))
|
||||
.exceptionHandling(
|
||||
handling ->
|
||||
handling.authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
|
@ -25,8 +25,8 @@ package org.owasp.webgoat.webwolf.mailbox;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -42,16 +42,16 @@ public class MailboxController {
|
||||
private final MailboxRepository mailboxRepository;
|
||||
|
||||
@GetMapping("/mail")
|
||||
public ModelAndView mail() {
|
||||
UserDetails user =
|
||||
(UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
public ModelAndView mail(Authentication authentication, Model model) {
|
||||
String username = (null != authentication) ? authentication.getName() : "anonymous";
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
List<Email> emails = mailboxRepository.findByRecipientOrderByTimeDesc(user.getUsername());
|
||||
List<Email> emails = mailboxRepository.findByRecipientOrderByTimeDesc(username);
|
||||
if (emails != null && !emails.isEmpty()) {
|
||||
modelAndView.addObject("total", emails.size());
|
||||
modelAndView.addObject("emails", emails);
|
||||
}
|
||||
modelAndView.setViewName("mailbox");
|
||||
model.addAttribute("username", username);
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -64,12 +63,12 @@ public class Requests {
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ModelAndView get() {
|
||||
public ModelAndView get(Authentication authentication) {
|
||||
var model = new ModelAndView("requests");
|
||||
var user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
String username = (null != authentication) ? authentication.getName() : "anonymous";
|
||||
var traces =
|
||||
traceRepository.findAllTraces().stream()
|
||||
.filter(t -> allowedTrace(t, user))
|
||||
.filter(t -> allowedTrace(t, username))
|
||||
.map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t)))
|
||||
.collect(toList());
|
||||
model.addObject("traces", traces);
|
||||
@ -77,17 +76,16 @@ public class Requests {
|
||||
return model;
|
||||
}
|
||||
|
||||
private boolean allowedTrace(HttpExchange t, UserDetails user) {
|
||||
private boolean allowedTrace(HttpExchange t, String username) {
|
||||
HttpExchange.Request req = t.getRequest();
|
||||
boolean allowed = true;
|
||||
/* do not show certain traces to other users in a classroom setup */
|
||||
if (req.getUri().getPath().contains("/files")
|
||||
&& !req.getUri().getPath().contains(user.getUsername())) {
|
||||
if (req.getUri().getPath().contains("/files") && !req.getUri().getPath().contains(username)) {
|
||||
allowed = false;
|
||||
} else if (req.getUri().getPath().contains("/landing")
|
||||
&& req.getUri().getQuery() != null
|
||||
&& req.getUri().getQuery().contains("uniqueCode")
|
||||
&& !req.getUri().getQuery().contains(StringUtils.reverse(user.getUsername()))) {
|
||||
&& !req.getUri().getQuery().contains(StringUtils.reverse(username))) {
|
||||
allowed = false;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ package org.owasp.webgoat.webwolf.requests;
|
||||
import com.google.common.collect.EvictingQueue;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
|
||||
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
|
||||
|
||||
@ -36,7 +35,6 @@ import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
|
||||
* @author nbaars
|
||||
* @since 8/13/17.
|
||||
*/
|
||||
@Slf4j
|
||||
public class WebWolfTraceRepository implements HttpExchangeRepository {
|
||||
|
||||
private final EvictingQueue<HttpExchange> traces = EvictingQueue.create(10000);
|
||||
@ -46,7 +44,6 @@ public class WebWolfTraceRepository implements HttpExchangeRepository {
|
||||
"/home",
|
||||
"/files",
|
||||
"/images/",
|
||||
"/favicon.ico",
|
||||
"/js/",
|
||||
"/webjars/",
|
||||
"/requests",
|
||||
|
Reference in New Issue
Block a user