From dcbdfc2026eb394ee6b86478df93c6084b22ce62 Mon Sep 17 00:00:00 2001 From: Luke Taylor Date: Thu, 11 Feb 2010 17:47:22 +0000 Subject: [PATCH] SEC-1396: Implement eager saving of SecurityContext in SessionManagementFilter on authentication. The user is then seen as being authenticated to further (re-entrant) requests which occur before the existing request has completed. The saving logic is contained with the SecurityContextRepository implementation. --- .../HttpSecurityBeanDefinitionParserTests.java | 14 ++++++++++---- .../HttpSessionSecurityContextRepository.java | 6 +++--- .../SaveContextOnUpdateOrErrorResponseWrapper.java | 2 +- .../web/session/SessionManagementFilter.java | 3 +++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java index d989534bb5..8cfbc9e591 100644 --- a/config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java @@ -36,6 +36,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.config.BeanIds; import org.springframework.security.config.PostProcessedMockUserDetailsService; import org.springframework.security.config.util.InMemoryXmlApplicationContext; +import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.openid.OpenID4JavaConsumer; @@ -77,6 +78,7 @@ import org.springframework.security.web.authentication.rememberme.TokenBasedReme import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; +import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper; import org.springframework.security.web.context.SecurityContextPersistenceFilter; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.RequestCacheAwareFilter; @@ -790,13 +792,17 @@ public class HttpSecurityBeanDefinitionParserTests { // Register 2 sessions and then check a third // req.setSession(new MockHttpSession()); // auth.setDetails(new WebAuthenticationDetails(req)); - MockHttpServletResponse response = new MockHttpServletResponse(); + MockHttpServletResponse mockResponse = new MockHttpServletResponse(); + SaveContextOnUpdateOrErrorResponseWrapper response = new SaveContextOnUpdateOrErrorResponseWrapper(mockResponse, false) { + protected void saveContext(SecurityContext context) { + } + }; seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain()); - assertNull(response.getRedirectedUrl()); + assertNull(mockResponse.getRedirectedUrl()); seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain()); - assertNull(response.getRedirectedUrl()); + assertNull(mockResponse.getRedirectedUrl()); seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain()); - assertEquals("/max-exceeded", response.getRedirectedUrl()); + assertEquals("/max-exceeded", mockResponse.getRedirectedUrl()); } @Test diff --git a/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java b/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java index 41f1c83a42..2f4f5d0d56 100644 --- a/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java +++ b/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java @@ -98,7 +98,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo } public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) { - SaveToSessionResponseWrapper responseWrapper = (SaveToSessionResponseWrapper)response; + SaveContextOnUpdateOrErrorResponseWrapper responseWrapper = (SaveContextOnUpdateOrErrorResponseWrapper)response; // saveContext() might already be called by the response wrapper // if something in the chain called sendError() or sendRedirect(). This ensures we only call it // once per request. @@ -289,7 +289,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo * Stores the necessary state from the start of the request in order to make a decision about whether * the security context has changed before saving it. */ - class SaveToSessionResponseWrapper extends SaveContextOnUpdateOrErrorResponseWrapper { + final class SaveToSessionResponseWrapper extends SaveContextOnUpdateOrErrorResponseWrapper { private HttpServletRequest request; private boolean httpSessionExistedAtStartOfRequest; @@ -327,7 +327,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo * */ @Override - void saveContext(SecurityContext context) { + protected void saveContext(SecurityContext context) { // See SEC-776 if (authenticationTrustResolver.isAnonymous(context.getAuthentication())) { if (logger.isDebugEnabled()) { diff --git a/web/src/main/java/org/springframework/security/web/context/SaveContextOnUpdateOrErrorResponseWrapper.java b/web/src/main/java/org/springframework/security/web/context/SaveContextOnUpdateOrErrorResponseWrapper.java index 52f39ea4cc..c5c1670a70 100644 --- a/web/src/main/java/org/springframework/security/web/context/SaveContextOnUpdateOrErrorResponseWrapper.java +++ b/web/src/main/java/org/springframework/security/web/context/SaveContextOnUpdateOrErrorResponseWrapper.java @@ -42,7 +42,7 @@ public abstract class SaveContextOnUpdateOrErrorResponseWrapper extends HttpServ * * @param context the SecurityContext instance to store */ - abstract void saveContext(SecurityContext context); + protected abstract void saveContext(SecurityContext context); /** * Makes sure the session is updated before calling the diff --git a/web/src/main/java/org/springframework/security/web/session/SessionManagementFilter.java b/web/src/main/java/org/springframework/security/web/session/SessionManagementFilter.java index 9c81fc62d4..e30830e39a 100644 --- a/web/src/main/java/org/springframework/security/web/session/SessionManagementFilter.java +++ b/web/src/main/java/org/springframework/security/web/session/SessionManagementFilter.java @@ -78,6 +78,9 @@ public class SessionManagementFilter extends GenericFilterBean { return; } + // Eagerly save the security context to make it available for any possible re-entrant + // requests which may occur before the current request completes. SEC-1396. + securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response); } else { // No security context or authentication present. Check for a session timeout if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {