JAVA-29312 Upgrade spring-security-web-mvc (#15687)

Co-authored-by: timis1 <noreplay@yahoo.com>
This commit is contained in:
timis1 2024-01-20 01:03:25 +02:00 committed by GitHub
parent 699cd6e8cd
commit 1724f67a39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 153 additions and 161 deletions

View File

@ -4,7 +4,7 @@
/target /target
/neoDb* /neoDb*
/data /data
/src/main/webapp/WEB-INF/classes /src/main/resources/templates/classes
*/META-INF/* */META-INF/*
# Packaged files # # Packaged files #

View File

@ -10,7 +10,8 @@
<parent> <parent>
<groupId>com.baeldung</groupId> <groupId>com.baeldung</groupId>
<artifactId>spring-security-modules</artifactId> <artifactId>parent-boot-3</artifactId>
<relativePath>../../parent-boot-3</relativePath>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
</parent> </parent>
@ -38,11 +39,6 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId> <artifactId>spring-boot-starter-tomcat</artifactId>
</dependency> </dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>runtime</scope>
</dependency>
<!-- ops --> <!-- ops -->
<dependency> <dependency>
<groupId>io.dropwizard.metrics</groupId> <groupId>io.dropwizard.metrics</groupId>
@ -55,9 +51,16 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>io.rest-assured</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>rest-assured</artifactId>
<version>${javax.version}</version> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
@ -67,7 +70,7 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <configuration>
<mainClass>com.baeldung.SpringSessionApplication</mainClass> <mainClass>com.baeldung.session.SpringSessionApplication</mainClass>
<layout>JAR</layout> <layout>JAR</layout>
</configuration> </configuration>
</plugin> </plugin>

View File

@ -1,36 +1,34 @@
package com.baeldung.clearsitedata; package com.baeldung.clearsitedata;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.CACHE; import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.CACHE;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.COOKIES; import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.COOKIES;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.STORAGE; import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.STORAGE;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler; import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter; import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableMethodSecurity
public class SpringSecurityConfig { public class SpringSecurityConfig {
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf() http.csrf(AbstractHttpConfigurer::disable)
.disable() .formLogin(httpSecurityFormLoginConfigurer ->
.formLogin() httpSecurityFormLoginConfigurer.loginPage("/login")
.loginPage("/login.html") .loginProcessingUrl("/perform_login")
.loginProcessingUrl("/perform_login") .defaultSuccessUrl("/homepage", true))
.defaultSuccessUrl("/homepage.html", true) .logout(httpSecurityLogoutConfigurer ->
.and() httpSecurityLogoutConfigurer.logoutUrl("/baeldung/logout")
.logout() .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES, STORAGE))));
.logoutUrl("/baeldung/logout")
.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(CACHE, COOKIES, STORAGE)));
return http.build(); return http.build();
} }
} }

View File

@ -3,9 +3,9 @@ package com.baeldung.security;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -61,9 +61,9 @@ public class MySimpleUrlAuthenticationSuccessHandler implements AuthenticationSu
} }
if (isUser) { if (isUser) {
return "/homepage.html"; return "/homepage";
} else if (isAdmin) { } else if (isAdmin) {
return "/console.html"; return "/console";
} else { } else {
throw new IllegalStateException(); throw new IllegalStateException();
} }

View File

@ -3,15 +3,15 @@ package com.baeldung.session.filter;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import javax.servlet.Filter; import jakarta.servlet.Filter;
import javax.servlet.FilterChain; import jakarta.servlet.FilterChain;
import javax.servlet.FilterConfig; import jakarta.servlet.FilterConfig;
import javax.servlet.ServletException; import jakarta.servlet.ServletException;
import javax.servlet.ServletRequest; import jakarta.servlet.ServletRequest;
import javax.servlet.ServletResponse; import jakarta.servlet.ServletResponse;
import javax.servlet.http.Cookie; import jakarta.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
public class SessionFilter implements Filter{ public class SessionFilter implements Filter{

View File

@ -3,6 +3,7 @@ package com.baeldung.session.security.config;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
@ -11,7 +12,9 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.session.HttpSessionEventPublisher; import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
import com.baeldung.security.MySimpleUrlAuthenticationSuccessHandler; import com.baeldung.security.MySimpleUrlAuthenticationSuccessHandler;
@ -35,37 +38,28 @@ public class SecSecurityConfig {
} }
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
http.csrf() http.csrf(AbstractHttpConfigurer::disable)
.disable() .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
.authorizeRequests() authorizationManagerRequestMatcherRegistry
.antMatchers("/anonymous*") .requestMatchers(mvc.pattern("/anonymous*")).anonymous()
.anonymous() .requestMatchers(mvc.pattern("/login*"), mvc.pattern("/invalidSession*"), mvc.pattern("/sessionExpired*"),
.antMatchers("/login*", "/invalidSession*", "/sessionExpired*", "/foo/**") mvc.pattern("/foo/**")).permitAll()
.permitAll() .anyRequest().authenticated())
.anyRequest() .formLogin(httpSecurityFormLoginConfigurer -> httpSecurityFormLoginConfigurer.loginPage("/login")
.authenticated() .loginProcessingUrl("/login")
.and() .successHandler(successHandler())
.formLogin() .failureUrl("/login?error=true"))
.loginPage("/login.html") .logout(httpSecurityLogoutConfigurer -> httpSecurityLogoutConfigurer.deleteCookies("JSESSIONID"))
.loginProcessingUrl("/login") .rememberMe(httpSecurityRememberMeConfigurer ->
.successHandler(successHandler()) httpSecurityRememberMeConfigurer.key("uniqueAndSecret")
.failureUrl("/login.html?error=true") .tokenValiditySeconds(86400))
.and() .sessionManagement(httpSecuritySessionManagementConfigurer ->
.logout() httpSecuritySessionManagementConfigurer.sessionFixation()
.deleteCookies("JSESSIONID") .migrateSession().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and() .invalidSessionUrl("/invalidSession")
.rememberMe() .maximumSessions(2)
.key("uniqueAndSecret") .expiredUrl("/sessionExpired"));
.tokenValiditySeconds(86400)
.and()
.sessionManagement()
.sessionFixation()
.migrateSession()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/invalidSession.html")
.maximumSessions(2)
.expiredUrl("/sessionExpired.html");
return http.build(); return http.build();
} }
@ -83,4 +77,8 @@ public class SecSecurityConfig {
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
} }
@Bean
MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
} }

View File

@ -1,6 +1,6 @@
package com.baeldung.session.web; package com.baeldung.session.web;
import javax.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;

View File

@ -1,6 +1,6 @@
package com.baeldung.session.web; package com.baeldung.session.web;
import javax.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;

View File

@ -1,14 +1,13 @@
package com.baeldung.session.web.config; package com.baeldung.session.web.config;
import javax.servlet.ServletContext; import jakarta.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.web.WebApplicationInitializer; import org.springframework.web.WebApplicationInitializer;
public class MainWebAppInitializer implements WebApplicationInitializer { public class MainWebAppInitializer implements WebApplicationInitializer {
@Override @Override
public void onStartup(ServletContext sc) throws ServletException { public void onStartup(ServletContext sc) {
sc.getSessionCookieConfig().setHttpOnly(true); sc.getSessionCookieConfig().setHttpOnly(true);
sc.getSessionCookieConfig().setSecure(true); sc.getSessionCookieConfig().setSecure(true);
} }

View File

@ -9,13 +9,13 @@ public class MvcConfig implements WebMvcConfigurer {
@Override @Override
public void addViewControllers(final ViewControllerRegistry registry) { public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/anonymous.html"); registry.addViewController("/anonymous").setViewName("view/anonymous");
registry.addViewController("/login.html"); registry.addViewController("/login").setViewName("view/login");
registry.addViewController("/homepage.html"); registry.addViewController("/homepage").setViewName("view/homepage");
registry.addViewController("/sessionExpired.html"); registry.addViewController("/sessionExpired").setViewName("view/sessionExpired");
registry.addViewController("/invalidSession.html"); registry.addViewController("/invalidSession").setViewName("view/invalidSession");
registry.addViewController("/console.html"); registry.addViewController("/console").setViewName("view/console");
} }
@ -27,7 +27,8 @@ public class MvcConfig implements WebMvcConfigurer {
// final InternalResourceViewResolver bean = new InternalResourceViewResolver(); // final InternalResourceViewResolver bean = new InternalResourceViewResolver();
// //
// bean.setViewClass(JstlView.class); // bean.setViewClass(JstlView.class);
// bean.setPrefix("/WEB-INF/view/"); // bean.setPrefix("/templates/view/");
// bean.setSuffix(".jsp"); // bean.setSuffix(".jsp");
// return bean;
// } // }
} }

View File

@ -2,8 +2,8 @@ package com.baeldung.web;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.http.HttpSessionEvent; import jakarta.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener; import jakarta.servlet.http.HttpSessionListener;
import com.baeldung.monitoring.MetricRegistrySingleton; import com.baeldung.monitoring.MetricRegistrySingleton;
import com.codahale.metrics.Counter; import com.codahale.metrics.Counter;

View File

@ -0,0 +1,9 @@
<html>
<head></head>
<body>
<h1>Anonymous page</h1>
<a href="/login"/>To Login</a>
</body>
</html>

View File

@ -0,0 +1,20 @@
<html xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head></head>
<body>
<h1>This is the landing page for the admin</h1>
<div sec:authorize="hasRole('ROLE_USER')">
This text is only visible to a user
<br/>
</div>
<div sec:authorize="hasRole('ROLE_ADMIN')">
This text is only visible to an admin
<br/>
</div>
<a href="/logout" />Logout</a>
</body>
</html>

View File

@ -0,0 +1,20 @@
<html xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head></head>
<body>
<h1>This is the homepage for the user</h1>
<div sec:authorize="hasRole('ROLE_USER')">
This text is only visible to a user
<br />
</div>
<div sec:authorize="hasRole('ROLE_ADMIN')">
This text is only visible to an admin
<br />
</div>
<a href="/logout" />Logout</a>
</body>
</html>

View File

@ -0,0 +1,9 @@
<html>
<head></head>
<body>
<h1>Invalid Session Page</h1>
<a href="/login"/>To Login</a>
</body>
</html>

View File

@ -0,0 +1,9 @@
<html>
<head></head>
<body>
<h1>Session Expired Page</h1>
<a href="/login" />To Login</a>
</body>
</html>

View File

@ -1,10 +0,0 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head></head>
<body>
<h1>Anonymous page</h1>
<a href="<c:url value="/login.html" />">To Login</a>
</body>
</html>

View File

@ -1,22 +0,0 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<html>
<head></head>
<body>
<h1>This is the landing page for the admin</h1>
<security:authorize access="hasRole('ROLE_USER')">
This text is only visible to a user
<br/>
</security:authorize>
<security:authorize access="hasRole('ROLE_ADMIN')">
This text is only visible to an admin
<br/>
</security:authorize>
<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>

View File

@ -1,22 +0,0 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%>
<html>
<head></head>
<body>
<h1>This is the homepage for the user</h1>
<security:authorize access="hasRole('ROLE_USER')">
This text is only visible to a user
<br />
</security:authorize>
<security:authorize access="hasRole('ROLE_ADMIN')">
This text is only visible to an admin
<br />
</security:authorize>
<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>

View File

@ -1,10 +0,0 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head></head>
<body>
<h1>Invalid Session Page</h1>
<a href="<c:url value="/login.html" />">To Login</a>
</body>
</html>

View File

@ -1,10 +0,0 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head></head>
<body>
<h1>Session Expired Page</h1>
<a href="<c:url value="/login.html" />">To Login</a>
</body>
</html>

View File

@ -13,7 +13,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import javax.servlet.Filter; import jakarta.servlet.Filter;
@ExtendWith(SpringExtension.class) @ExtendWith(SpringExtension.class)
@WebAppConfiguration @WebAppConfiguration

View File

@ -35,11 +35,11 @@ public class SessionConfigurationLiveTest {
Response resp3 = simpleResponseRequestUsingSessionNotFollowingRedirects(sessionFilter); Response resp3 = simpleResponseRequestUsingSessionNotFollowingRedirects(sessionFilter);
assertThat(resp3.getStatusCode()).isEqualTo(HttpStatus.FOUND.value()); assertThat(resp3.getStatusCode()).isEqualTo(HttpStatus.FOUND.value());
assertThat(resp3.getHeader("Location")).isEqualTo("http://localhost:8080/invalidSession.html"); assertThat(resp3.getHeader("Location")).isEqualTo("http://localhost:8080/invalidSession");
} }
@Test @Test
public void givenValidUser_whenLoginMoreThanMaxValidSession_thenRedirectedToExpiredSessionUri() throws Exception { public void givenValidUser_whenLoginMoreThanMaxValidSession_thenRedirectedToExpiredSessionUri() {
SessionFilter sessionFilter = new SessionFilter(); SessionFilter sessionFilter = new SessionFilter();
simpleSvcRequestLoggingIn(sessionFilter); simpleSvcRequestLoggingIn(sessionFilter);
simpleSvcRequestLoggingIn(); simpleSvcRequestLoggingIn();
@ -56,7 +56,7 @@ public class SessionConfigurationLiveTest {
.get(SESSION_SVC_URL); .get(SESSION_SVC_URL);
assertThat(resp4.getStatusCode()).isEqualTo(HttpStatus.FOUND.value()); assertThat(resp4.getStatusCode()).isEqualTo(HttpStatus.FOUND.value());
assertThat(resp4.getHeader("Location")).isEqualTo("http://localhost:8080/sessionExpired.html"); assertThat(resp4.getHeader("Location")).isEqualTo("http://localhost:8080/sessionExpired");
} }
private static void simpleSvcRequestLoggingIn() { private static void simpleSvcRequestLoggingIn() {