Add AuthenticationSuccessHandler support to AbstractPreAuthenticatedProcessingFilter

Fixes gh-3389
This commit is contained in:
Shazin Sadakath 2016-03-25 09:43:14 -05:00 committed by Rob Winch
parent 008b721a20
commit 1bc7060c93
2 changed files with 77 additions and 4 deletions

View File

@ -33,7 +33,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.WebAttributes; import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.*;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.web.filter.GenericFilterBean; import org.springframework.web.filter.GenericFilterBean;
@ -84,6 +84,8 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
private boolean continueFilterChainOnUnsuccessfulAuthentication = true; private boolean continueFilterChainOnUnsuccessfulAuthentication = true;
private boolean checkForPrincipalChanges; private boolean checkForPrincipalChanges;
private boolean invalidateSessionOnPrincipalChange = true; private boolean invalidateSessionOnPrincipalChange = true;
private AuthenticationSuccessHandler authenticationSuccessHandler = null;
private AuthenticationFailureHandler authenticationFailureHandler = null;
/** /**
* Check whether all required properties have been set. * Check whether all required properties have been set.
@ -156,7 +158,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
/** /**
* Do the actual authentication for a pre-authenticated user. * Do the actual authentication for a pre-authenticated user.
*/ */
private void doAuthenticate(HttpServletRequest request, HttpServletResponse response) { private void doAuthenticate(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
Authentication authResult; Authentication authResult;
Object principal = getPreAuthenticatedPrincipal(request); Object principal = getPreAuthenticatedPrincipal(request);
@ -229,7 +231,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
* manager into the secure context. * manager into the secure context.
*/ */
protected void successfulAuthentication(HttpServletRequest request, protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, Authentication authResult) { HttpServletResponse response, Authentication authResult) throws IOException, ServletException {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Authentication success: " + authResult); logger.debug("Authentication success: " + authResult);
} }
@ -239,6 +241,10 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent( eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
authResult, this.getClass())); authResult, this.getClass()));
} }
if(authenticationSuccessHandler != null) {
authenticationSuccessHandler.onAuthenticationSuccess(request, response, authResult);
}
} }
/** /**
@ -248,13 +254,17 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
* Caches the failure exception as a request attribute * Caches the failure exception as a request attribute
*/ */
protected void unsuccessfulAuthentication(HttpServletRequest request, protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response, AuthenticationException failed) { HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
SecurityContextHolder.clearContext(); SecurityContextHolder.clearContext();
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Cleared security context due to exception", failed); logger.debug("Cleared security context due to exception", failed);
} }
request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, failed); request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, failed);
if(authenticationFailureHandler != null) {
authenticationFailureHandler.onAuthenticationFailure(request, response, failed);
}
} }
/** /**
@ -324,6 +334,20 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
this.invalidateSessionOnPrincipalChange = invalidateSessionOnPrincipalChange; this.invalidateSessionOnPrincipalChange = invalidateSessionOnPrincipalChange;
} }
/**
* Sets the strategy used to handle a successful authentication.
*/
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler authenticationSuccessHandler) {
this.authenticationSuccessHandler = authenticationSuccessHandler;
}
/**
* Sets the strategy used to handle a failed authentication.
*/
public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
this.authenticationFailureHandler = authenticationFailureHandler;
}
/** /**
* Override to extract the principal information from the current request * Override to extract the principal information from the current request
*/ */

View File

@ -40,9 +40,13 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
/** /**
* *
@ -206,6 +210,51 @@ public class AbstractPreAuthenticatedProcessingFilterTests {
verify(am).authenticate(any(PreAuthenticatedAuthenticationToken.class)); verify(am).authenticate(any(PreAuthenticatedAuthenticationToken.class));
} }
@Test
public void callsAuthenticationSuccessHandlerOnSuccessfulAuthentication() throws Exception {
Object currentPrincipal = "currentUser";
TestingAuthenticationToken authRequest = new TestingAuthenticationToken(
currentPrincipal, "something", "ROLE_USER");
SecurityContextHolder.getContext().setAuthentication(authRequest);
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter();
filter.setAuthenticationSuccessHandler(new ForwardAuthenticationSuccessHandler("/forwardUrl"));
filter.setCheckForPrincipalChanges(true);
filter.principal = "newUser";
AuthenticationManager am = mock(AuthenticationManager.class);
filter.setAuthenticationManager(am);
filter.afterPropertiesSet();
filter.doFilter(request, response, chain);
verify(am).authenticate(any(PreAuthenticatedAuthenticationToken.class));
assertThat(response.getForwardedUrl()).isEqualTo("/forwardUrl");
}
@Test
public void callsAuthenticationFailureHandlerOnFailedAuthentication() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter();
filter.setAuthenticationFailureHandler(new ForwardAuthenticationFailureHandler("/forwardUrl"));
filter.setCheckForPrincipalChanges(true);
AuthenticationManager am = mock(AuthenticationManager.class);
when(am.authenticate(any(PreAuthenticatedAuthenticationToken.class))).thenThrow(new PreAuthenticatedCredentialsNotFoundException("invalid"));
filter.setAuthenticationManager(am);
filter.afterPropertiesSet();
filter.doFilter(request, response, chain);
verify(am).authenticate(any(PreAuthenticatedAuthenticationToken.class));
assertThat(response.getForwardedUrl()).isEqualTo("/forwardUrl");
assertThat(request.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)).isNotNull();
}
// SEC-2078 // SEC-2078
@Test @Test
public void requiresAuthenticationFalsePrincipalNotString() throws Exception { public void requiresAuthenticationFalsePrincipalNotString() throws Exception {