Allow configuration of session fixation and concurrency through nested builder

Issue: gh-5557
This commit is contained in:
Eleftheria Stein 2019-07-12 13:53:55 -04:00
parent 4b2539df10
commit 7961b819aa
3 changed files with 95 additions and 4 deletions

View File

@ -681,8 +681,11 @@ public final class HttpSecurity extends
* ) * )
* .sessionManagement(sessionManagement -> * .sessionManagement(sessionManagement ->
* sessionManagement * sessionManagement
* .maximumSessions(1) * .sessionConcurrency(sessionConcurrency ->
* .expiredUrl("/login?expired") * sessionConcurrency
* .maximumSessions(1)
* .expiredUrl("/login?expired")
* )
* ); * );
* } * }
* } * }

View File

@ -26,6 +26,7 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.event.GenericApplicationListenerAdapter; import org.springframework.context.event.GenericApplicationListenerAdapter;
import org.springframework.context.event.SmartApplicationListener; import org.springframework.context.event.SmartApplicationListener;
import org.springframework.security.authentication.AuthenticationTrustResolver; 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.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
@ -249,6 +250,19 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return new SessionFixationConfigurer(); 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<H> sessionFixation(Customizer<SessionFixationConfigurer> sessionFixationCustomizer)
throws Exception {
sessionFixationCustomizer.customize(new SessionFixationConfigurer());
return this;
}
/** /**
* Controls the maximum number of sessions for a user. The default is to allow any * Controls the maximum number of sessions for a user. The default is to allow any
* number of users. * number of users.
@ -260,6 +274,20 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return new ConcurrencyControlConfigurer(); 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<H> sessionConcurrency(Customizer<ConcurrencyControlConfigurer> sessionConcurrencyCustomizer)
throws Exception {
sessionConcurrencyCustomizer.customize(new ConcurrencyControlConfigurer());
return this;
}
/** /**
* Invokes {@link #postProcess(Object)} and sets the * Invokes {@link #postProcess(Object)} and sets the
* {@link SessionAuthenticationStrategy} for session fixation. * {@link SessionAuthenticationStrategy} for session fixation.
@ -338,6 +366,18 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
*/ */
public final class ConcurrencyControlConfigurer { 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 * 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 * has been expired due to too many sessions for the current user. The default is

View File

@ -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 @Test
public void loginWhenUserLoggedInAndMaxSessionsIsOneThenLoginPrevented() throws Exception { public void loginWhenUserLoggedInAndMaxSessionsIsOneThenLoginPrevented() throws Exception {
this.spring.register(ConcurrencyControlConfig.class).autowire(); this.spring.register(ConcurrencyControlConfig.class).autowire();
@ -289,8 +334,11 @@ public class SessionManagementConfigurerTests {
.formLogin(withDefaults()) .formLogin(withDefaults())
.sessionManagement(sessionManagement -> .sessionManagement(sessionManagement ->
sessionManagement sessionManagement
.maximumSessions(1) .sessionConcurrency(sessionConcurrency ->
.maxSessionsPreventsLogin(true) sessionConcurrency
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
)
); );
// @formatter:on // @formatter:on
} }