diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index fac8ba9b6e..69bc3ab70c 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -681,8 +681,11 @@ public final class HttpSecurity extends * ) * .sessionManagement(sessionManagement -> * sessionManagement - * .maximumSessions(1) - * .expiredUrl("/login?expired") + * .sessionConcurrency(sessionConcurrency -> + * sessionConcurrency + * .maximumSessions(1) + * .expiredUrl("/login?expired") + * ) * ); * } * } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java index cb7c220558..ad8f4e033a 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java @@ -26,6 +26,7 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.event.GenericApplicationListenerAdapter; import org.springframework.context.event.SmartApplicationListener; import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; @@ -249,6 +250,19 @@ public final class SessionManagementConfigurer> return new SessionFixationConfigurer(); } + /** + * Allows configuring session fixation protection. + * + * @param sessionFixationCustomizer the {@link Customizer} to provide more options for + * the {@link SessionFixationConfigurer} + * @return the {@link SessionManagementConfigurer} for further customizations + */ + public SessionManagementConfigurer sessionFixation(Customizer sessionFixationCustomizer) + throws Exception { + sessionFixationCustomizer.customize(new SessionFixationConfigurer()); + return this; + } + /** * Controls the maximum number of sessions for a user. The default is to allow any * number of users. @@ -260,6 +274,20 @@ public final class SessionManagementConfigurer> return new ConcurrencyControlConfigurer(); } + /** + * Controls the maximum number of sessions for a user. The default is to allow any + * number of users. + * + * @param sessionConcurrencyCustomizer the {@link Customizer} to provide more options for + * the {@link ConcurrencyControlConfigurer} + * @return the {@link SessionManagementConfigurer} for further customizations + */ + public SessionManagementConfigurer sessionConcurrency(Customizer sessionConcurrencyCustomizer) + throws Exception { + sessionConcurrencyCustomizer.customize(new ConcurrencyControlConfigurer()); + return this; + } + /** * Invokes {@link #postProcess(Object)} and sets the * {@link SessionAuthenticationStrategy} for session fixation. @@ -338,6 +366,18 @@ public final class SessionManagementConfigurer> */ public final class ConcurrencyControlConfigurer { + /** + * Controls the maximum number of sessions for a user. The default is to allow any + * number of users. + * + * @param maximumSessions the maximum number of sessions for a user + * @return the {@link ConcurrencyControlConfigurer} for further customizations + */ + public ConcurrencyControlConfigurer maximumSessions(int maximumSessions) { + SessionManagementConfigurer.this.maximumSessions = maximumSessions; + return this; + } + /** * The URL to redirect to if a user tries to access a resource and their session * has been expired due to too many sessions for the current user. The default is diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java index b737422811..5eaa4d78a7 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurerTests.java @@ -202,6 +202,51 @@ public class SessionManagementConfigurerTests { } } + @Test + public void authenticateWhenNewSessionFixationProtectionInLambdaThenCreatesNewSession() throws Exception { + this.spring.register(SFPNewSessionInLambdaConfig.class).autowire(); + + MockHttpSession givenSession = new MockHttpSession(); + String givenSessionId = givenSession.getId(); + givenSession.setAttribute("name", "value"); + + MockHttpSession resultingSession = (MockHttpSession) + this.mvc.perform(get("/auth") + .session(givenSession) + .with(httpBasic("user", "password"))) + .andExpect(status().isNotFound()) + .andReturn().getRequest().getSession(false); + + assertThat(givenSessionId).isNotEqualTo(resultingSession.getId()); + assertThat(resultingSession.getAttribute("name")).isNull(); + } + + @EnableWebSecurity + static class SFPNewSessionInLambdaConfig extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + // @formatter:off + http + .sessionManagement(sessionManagement -> + sessionManagement + .sessionFixation(sessionFixation -> + sessionFixation.newSession() + ) + ) + .httpBasic(withDefaults()); + // @formatter:on + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + // @formatter:off + auth + .inMemoryAuthentication() + .withUser(PasswordEncodedUser.user()); + // @formatter:on + } + } + @Test public void loginWhenUserLoggedInAndMaxSessionsIsOneThenLoginPrevented() throws Exception { this.spring.register(ConcurrencyControlConfig.class).autowire(); @@ -289,8 +334,11 @@ public class SessionManagementConfigurerTests { .formLogin(withDefaults()) .sessionManagement(sessionManagement -> sessionManagement - .maximumSessions(1) - .maxSessionsPreventsLogin(true) + .sessionConcurrency(sessionConcurrency -> + sessionConcurrency + .maximumSessions(1) + .maxSessionsPreventsLogin(true) + ) ); // @formatter:on }