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.
This commit is contained in:
parent
403f8da79a
commit
dcbdfc2026
|
@ -36,6 +36,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
|
||||||
import org.springframework.security.config.BeanIds;
|
import org.springframework.security.config.BeanIds;
|
||||||
import org.springframework.security.config.PostProcessedMockUserDetailsService;
|
import org.springframework.security.config.PostProcessedMockUserDetailsService;
|
||||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
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.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
import org.springframework.security.openid.OpenID4JavaConsumer;
|
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.ui.DefaultLoginPageGeneratingFilter;
|
||||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
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.context.SecurityContextPersistenceFilter;
|
||||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
||||||
|
@ -790,13 +792,17 @@ public class HttpSecurityBeanDefinitionParserTests {
|
||||||
// Register 2 sessions and then check a third
|
// Register 2 sessions and then check a third
|
||||||
// req.setSession(new MockHttpSession());
|
// req.setSession(new MockHttpSession());
|
||||||
// auth.setDetails(new WebAuthenticationDetails(req));
|
// 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());
|
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||||
assertNull(response.getRedirectedUrl());
|
assertNull(mockResponse.getRedirectedUrl());
|
||||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||||
assertNull(response.getRedirectedUrl());
|
assertNull(mockResponse.getRedirectedUrl());
|
||||||
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
||||||
assertEquals("/max-exceeded", response.getRedirectedUrl());
|
assertEquals("/max-exceeded", mockResponse.getRedirectedUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response) {
|
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
|
// saveContext() might already be called by the response wrapper
|
||||||
// if something in the chain called sendError() or sendRedirect(). This ensures we only call it
|
// if something in the chain called sendError() or sendRedirect(). This ensures we only call it
|
||||||
// once per request.
|
// 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
|
* 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.
|
* the security context has changed before saving it.
|
||||||
*/
|
*/
|
||||||
class SaveToSessionResponseWrapper extends SaveContextOnUpdateOrErrorResponseWrapper {
|
final class SaveToSessionResponseWrapper extends SaveContextOnUpdateOrErrorResponseWrapper {
|
||||||
|
|
||||||
private HttpServletRequest request;
|
private HttpServletRequest request;
|
||||||
private boolean httpSessionExistedAtStartOfRequest;
|
private boolean httpSessionExistedAtStartOfRequest;
|
||||||
|
@ -327,7 +327,7 @@ public class HttpSessionSecurityContextRepository implements SecurityContextRepo
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
void saveContext(SecurityContext context) {
|
protected void saveContext(SecurityContext context) {
|
||||||
// See SEC-776
|
// See SEC-776
|
||||||
if (authenticationTrustResolver.isAnonymous(context.getAuthentication())) {
|
if (authenticationTrustResolver.isAnonymous(context.getAuthentication())) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ public abstract class SaveContextOnUpdateOrErrorResponseWrapper extends HttpServ
|
||||||
*
|
*
|
||||||
* @param context the <tt>SecurityContext</tt> instance to store
|
* @param context the <tt>SecurityContext</tt> instance to store
|
||||||
*/
|
*/
|
||||||
abstract void saveContext(SecurityContext context);
|
protected abstract void saveContext(SecurityContext context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes sure the session is updated before calling the
|
* Makes sure the session is updated before calling the
|
||||||
|
|
|
@ -78,6 +78,9 @@ public class SessionManagementFilter extends GenericFilterBean {
|
||||||
|
|
||||||
return;
|
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 {
|
} else {
|
||||||
// No security context or authentication present. Check for a session timeout
|
// No security context or authentication present. Check for a session timeout
|
||||||
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
|
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
|
||||||
|
|
Loading…
Reference in New Issue