1
0
mirror of synced 2026-08-04 17:27:13 +00:00

SEC-2574: JavaConfig default SessionRegistry processes SessionDestroyedEvents

This commit is contained in:
Rob Winch
2014-11-19 16:48:19 -06:00
parent 4dcc89fab0
commit 5810681b06
5 changed files with 172 additions and 5 deletions
@@ -40,6 +40,7 @@ import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.context.DelegatingApplicationListener;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
@@ -72,6 +73,11 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
private ClassLoader beanClassLoader;
@Bean
public DelegatingApplicationListener delegatingApplicationListener() {
return new DelegatingApplicationListener();
}
@Bean
@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {
@@ -22,9 +22,13 @@ import java.util.List;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.GenericApplicationListenerAdapter;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.context.DelegatingApplicationListener;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
@@ -87,7 +91,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private InvalidSessionStrategy invalidSessionStrategy;
private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<SessionAuthenticationStrategy>();
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
private SessionRegistry sessionRegistry;
private Integer maximumSessions;
private String expiredUrl;
private boolean maxSessionsPreventsLogin;
@@ -367,14 +371,14 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
http.setSharedObject(RequestCache.class, new NullRequestCache());
}
}
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy());
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy(http));
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
@Override
public void configure(H http) throws Exception {
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository, getSessionAuthenticationStrategy());
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository, getSessionAuthenticationStrategy(http));
if(sessionAuthenticationErrorUrl != null) {
sessionManagementFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(sessionAuthenticationErrorUrl));
}
@@ -389,7 +393,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
http.addFilter(sessionManagementFilter);
if(isConcurrentSessionControlEnabled()) {
ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry, expiredUrl);
ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(getSessionRegistry(http), expiredUrl);
concurrentSessionFilter = postProcess(concurrentSessionFilter);
http.addFilter(concurrentSessionFilter);
}
@@ -444,12 +448,13 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
*
* @return the {@link SessionAuthenticationStrategy} to use
*/
private SessionAuthenticationStrategy getSessionAuthenticationStrategy() {
private SessionAuthenticationStrategy getSessionAuthenticationStrategy(H http) {
if(sessionAuthenticationStrategy != null) {
return sessionAuthenticationStrategy;
}
List<SessionAuthenticationStrategy> delegateStrategies = sessionAuthenticationStrategies;
if(isConcurrentSessionControlEnabled()) {
SessionRegistry sessionRegistry = getSessionRegistry(http);
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
concurrentSessionControlStrategy.setMaximumSessions(maximumSessions);
concurrentSessionControlStrategy.setExceptionIfMaximumExceeded(maxSessionsPreventsLogin);
@@ -466,6 +471,18 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return sessionAuthenticationStrategy;
}
private SessionRegistry getSessionRegistry(H http) {
if(sessionRegistry == null) {
SessionRegistryImpl sessionRegistry = new SessionRegistryImpl();
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
DelegatingApplicationListener delegating = context.getBean(DelegatingApplicationListener.class);
SmartApplicationListener smartListener = new GenericApplicationListenerAdapter(sessionRegistry);
delegating.addListener(smartListener);
this.sessionRegistry = sessionRegistry;
}
return sessionRegistry;
}
/**
* Returns true if the number of concurrent sessions per user should be restricted.
* @return
@@ -29,6 +29,7 @@ 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.WebSecurityConfigurerAdapter
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.core.session.SessionDestroyedEvent
import org.springframework.security.web.access.ExceptionTranslationFilter
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy
@@ -38,6 +39,7 @@ import org.springframework.security.web.context.SecurityContextPersistenceFilter
import org.springframework.security.web.context.SecurityContextRepository
import org.springframework.security.web.savedrequest.RequestCache
import org.springframework.security.web.session.ConcurrentSessionFilter
import org.springframework.security.web.session.HttpSessionDestroyedEvent;
import org.springframework.security.web.session.SessionManagementFilter
/**
@@ -154,12 +156,14 @@ class SessionManagementConfigurerTests extends BaseSpringSpec {
def 'session fixation and enable concurrency control'() {
setup: "context where session fixation is disabled and concurrency control is enabled"
loadConfig(ConcurrencyControlConfig)
def authenticatedSession
when: "authenticate successfully"
request.servletPath = "/login"
request.method = "POST"
request.setParameter("username", "user");
request.setParameter("password","password")
springSecurityFilterChain.doFilter(request, response, chain)
authenticatedSession = request.session
then: "authentication is sucessful"
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/"
@@ -173,6 +177,17 @@ class SessionManagementConfigurerTests extends BaseSpringSpec {
then:
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == '/login?error'
when: 'SEC-2574: When Session Expires and authentication attempted'
context.publishEvent(new HttpSessionDestroyedEvent(authenticatedSession))
super.setup()
request.servletPath = "/login"
request.method = "POST"
request.setParameter("username", "user");
request.setParameter("password","password")
springSecurityFilterChain.doFilter(request, response, chain)
then: "authentication is successful"
response.status == HttpServletResponse.SC_MOVED_TEMPORARILY
response.redirectedUrl == "/"
}
@EnableWebSecurity