MOCK API -> csrf 제외

This commit is contained in:
현성필
2024-04-25 11:31:44 +09:00
parent 852e55ac24
commit eab712bad9
4 changed files with 73 additions and 8 deletions
@@ -2,6 +2,7 @@ package com.eactive.testmaster.api.controller;
import com.eactive.testmaster.api.entity.MockRoute; import com.eactive.testmaster.api.entity.MockRoute;
import com.eactive.testmaster.api.service.MockRouteService; import com.eactive.testmaster.api.service.MockRouteService;
import com.eactive.testmaster.config.CsrfExclusionService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -27,6 +28,9 @@ public class MockApiHandlerMapping {
@Autowired @Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping; private RequestMappingHandlerMapping requestMappingHandlerMapping;
@Autowired
private CsrfExclusionService csrfExclusionService;
@PostConstruct @PostConstruct
public void initialize() { public void initialize() {
mockRouteService.initAllRoutes(); mockRouteService.initAllRoutes();
@@ -43,6 +47,9 @@ public class MockApiHandlerMapping {
try { try {
requestMappingHandlerMapping.registerMapping(mappingInfo, mockApiController, MockApiController.class.getDeclaredMethod("handleRequest", HttpServletRequest.class)); requestMappingHandlerMapping.registerMapping(mappingInfo, mockApiController, MockApiController.class.getDeclaredMethod("handleRequest", HttpServletRequest.class));
if (mockRoute.getMethod().equalsIgnoreCase("POST") || mockRoute.getMethod().equalsIgnoreCase("PUT")) {
csrfExclusionService.addExcludedPath(mockRoute.getPathPattern());
}
logger.info("Registered mapping for {} {}", mockRoute.getMethod(), mockRoute.getPathPattern()); logger.info("Registered mapping for {} {}", mockRoute.getMethod(), mockRoute.getPathPattern());
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
logger.error("Error registering mapping", e); logger.error("Error registering mapping", e);
@@ -54,7 +61,9 @@ public class MockApiHandlerMapping {
.paths(mockRoute.getPathPattern()) .paths(mockRoute.getPathPattern())
.methods(RequestMethod.valueOf(mockRoute.getMethod())) .methods(RequestMethod.valueOf(mockRoute.getMethod()))
.build(); .build();
if (mockRoute.getMethod().equalsIgnoreCase("POST") || mockRoute.getMethod().equalsIgnoreCase("PUT")) {
csrfExclusionService.removeExcludedPath(mockRoute.getPathPattern());
}
requestMappingHandlerMapping.unregisterMapping(mappingInfo); requestMappingHandlerMapping.unregisterMapping(mappingInfo);
logger.info("Unregistered mapping for {} {}", mockRoute.getMethod(), mockRoute.getPathPattern()); logger.info("Unregistered mapping for {} {}", mockRoute.getMethod(), mockRoute.getPathPattern());
} }
@@ -0,0 +1,23 @@
package com.eactive.testmaster.config;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.stereotype.Service;
@Service
public class CsrfExclusionService {
private Set<String> excludedPaths = Collections.newSetFromMap(new ConcurrentHashMap<>());
public void addExcludedPath(String path) {
excludedPaths.add(path);
}
public void removeExcludedPath(String path) {
excludedPaths.remove(path);
}
public boolean shouldExclude(String path) {
return excludedPaths.contains(path);
}
}
@@ -2,6 +2,8 @@ package com.eactive.testmaster.config;
import com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter; import com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@@ -12,7 +14,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository; import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@@ -25,13 +30,14 @@ public class PortalConfigSecurity {
private final PortalAuthenticationManager portalAuthenticationManager; private final PortalAuthenticationManager portalAuthenticationManager;
@Autowired private final CsrfExclusionService csrfExclusionService;
public PortalConfigSecurity(PortalAuthenticationFailureHandler authenticationFailureHandler,
PortalAuthenticationSuccessHandler authenticationSuccessHandler, public PortalConfigSecurity(PortalAuthenticationFailureHandler authenticationFailureHandler, PortalAuthenticationSuccessHandler authenticationSuccessHandler, PortalAuthenticationManager portalAuthenticationManager,
PortalAuthenticationManager portalAuthenticationManager) { CsrfExclusionService csrfExclusionService) {
this.authenticationFailureHandler = authenticationFailureHandler; this.authenticationFailureHandler = authenticationFailureHandler;
this.authenticationSuccessHandler = authenticationSuccessHandler; this.authenticationSuccessHandler = authenticationSuccessHandler;
this.portalAuthenticationManager = portalAuthenticationManager; this.portalAuthenticationManager = portalAuthenticationManager;
this.csrfExclusionService = csrfExclusionService;
} }
@Bean @Bean
@@ -44,6 +50,29 @@ public class PortalConfigSecurity {
return registrationBean; return registrationBean;
} }
@Bean
public CsrfTokenRepository csrfTokenRepository(CsrfExclusionService csrfExclusionService) {
// HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
CookieCsrfTokenRepository repository = new CookieCsrfTokenRepository();
repository.setCookieHttpOnly(false);
return new CsrfTokenRepository() {
@Override
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
repository.saveToken(token, request, response);
}
@Override
public CsrfToken loadToken(HttpServletRequest request) {
return repository.loadToken(request);
}
@Override
public CsrfToken generateToken(HttpServletRequest request) {
return repository.generateToken(request);
}
};
}
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http http
@@ -59,8 +88,11 @@ public class PortalConfigSecurity {
.logoutRequestMatcher(new AntPathRequestMatcher("/actionLogout.do", "GET")) .logoutRequestMatcher(new AntPathRequestMatcher("/actionLogout.do", "GET"))
.logoutSuccessUrl("/")) .logoutSuccessUrl("/"))
.csrf(csrf -> csrf .csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .csrfTokenRepository(csrfTokenRepository(csrfExclusionService))
.ignoringAntMatchers("/h2-console/**") .ignoringRequestMatchers(request -> csrfExclusionService.shouldExclude(request.getServletPath()))
.ignoringAntMatchers("/h2-console/**")
// .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
).headers(headers -> headers.frameOptions().sameOrigin()) ).headers(headers -> headers.frameOptions().sameOrigin())
.sessionManagement(session -> session .sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
@@ -68,7 +100,6 @@ public class PortalConfigSecurity {
.changeSessionId() .changeSessionId()
); );
return http.build(); return http.build();
} }
} }
@@ -1,5 +1,6 @@
package com.eactive.testmaster.loadtest.controller; package com.eactive.testmaster.loadtest.controller;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
@@ -9,6 +10,7 @@ import org.springframework.web.bind.annotation.GetMapping;
public class LoadTestPageController { public class LoadTestPageController {
@GetMapping("/mgmt/load_tester.do") @GetMapping("/mgmt/load_tester.do")
@Secured("ROLE_API_TESTER")
public String testView(ModelMap model) { public String testView(ModelMap model) {
return "page/tester/loadTester"; return "page/tester/loadTester";
} }