mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-31 06:38:42 +00:00 
			
		
		
		
	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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user