Add RequestMatcher to AbstractPreAuthenticatedProcessingFilter
Moved the existing auth check logic to the matcher. Issue: gh-5928
This commit is contained in:
parent
63607ee213
commit
62c7de03c3
|
@ -34,6 +34,7 @@ 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.*;
|
import org.springframework.security.web.authentication.*;
|
||||||
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.web.filter.GenericFilterBean;
|
import org.springframework.web.filter.GenericFilterBean;
|
||||||
|
|
||||||
|
@ -73,6 +74,7 @@ import org.springframework.web.filter.GenericFilterBean;
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @author Ruud Senden
|
* @author Ruud Senden
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
|
* @author Tadaya Tsuyukubo
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFilterBean
|
public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFilterBean
|
||||||
|
@ -86,6 +88,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
private boolean invalidateSessionOnPrincipalChange = true;
|
private boolean invalidateSessionOnPrincipalChange = true;
|
||||||
private AuthenticationSuccessHandler authenticationSuccessHandler = null;
|
private AuthenticationSuccessHandler authenticationSuccessHandler = null;
|
||||||
private AuthenticationFailureHandler authenticationFailureHandler = null;
|
private AuthenticationFailureHandler authenticationFailureHandler = null;
|
||||||
|
private RequestMatcher requiresAuthenticationRequestMatcher = new PreAuthenticatedProcessingRequestMatcher();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether all required properties have been set.
|
* Check whether all required properties have been set.
|
||||||
|
@ -114,7 +117,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
+ SecurityContextHolder.getContext().getAuthentication());
|
+ SecurityContextHolder.getContext().getAuthentication());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requiresAuthentication((HttpServletRequest) request)) {
|
if (requiresAuthenticationRequestMatcher.matches((HttpServletRequest) request)) {
|
||||||
doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response);
|
doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,39 +196,6 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean requiresAuthentication(HttpServletRequest request) {
|
|
||||||
Authentication currentUser = SecurityContextHolder.getContext()
|
|
||||||
.getAuthentication();
|
|
||||||
|
|
||||||
if (currentUser == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!checkForPrincipalChanges) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!principalChanged(request, currentUser)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Pre-authenticated principal has changed and will be reauthenticated");
|
|
||||||
|
|
||||||
if (invalidateSessionOnPrincipalChange) {
|
|
||||||
SecurityContextHolder.clearContext();
|
|
||||||
|
|
||||||
HttpSession session = request.getSession(false);
|
|
||||||
|
|
||||||
if (session != null) {
|
|
||||||
logger.debug("Invalidating existing session");
|
|
||||||
session.invalidate();
|
|
||||||
request.getSession();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts the <code>Authentication</code> instance returned by the authentication
|
* Puts the <code>Authentication</code> instance returned by the authentication
|
||||||
* manager into the secure context.
|
* manager into the secure context.
|
||||||
|
@ -348,6 +318,14 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
this.authenticationFailureHandler = authenticationFailureHandler;
|
this.authenticationFailureHandler = authenticationFailureHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the request matcher to check whether to proceed the request further.
|
||||||
|
*/
|
||||||
|
public void setRequiresAuthenticationRequestMatcher(RequestMatcher requiresAuthenticationRequestMatcher) {
|
||||||
|
Assert.notNull(requiresAuthenticationRequestMatcher, "requestMatcher cannot be null");
|
||||||
|
this.requiresAuthenticationRequestMatcher = requiresAuthenticationRequestMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override to extract the principal information from the current request
|
* Override to extract the principal information from the current request
|
||||||
*/
|
*/
|
||||||
|
@ -359,4 +337,46 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends GenericFi
|
||||||
* return a dummy value.
|
* return a dummy value.
|
||||||
*/
|
*/
|
||||||
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
|
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request matcher for default auth check logic
|
||||||
|
*/
|
||||||
|
private class PreAuthenticatedProcessingRequestMatcher implements RequestMatcher {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(HttpServletRequest request) {
|
||||||
|
|
||||||
|
Authentication currentUser = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
|
if (currentUser == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkForPrincipalChanges) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!principalChanged(request, currentUser)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Pre-authenticated principal has changed and will be reauthenticated");
|
||||||
|
|
||||||
|
if (invalidateSessionOnPrincipalChange) {
|
||||||
|
SecurityContextHolder.clearContext();
|
||||||
|
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
|
||||||
|
if (session != null) {
|
||||||
|
logger.debug("Invalidating existing session");
|
||||||
|
session.invalidate();
|
||||||
|
request.getSession();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,10 +45,12 @@ import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.web.WebAttributes;
|
import org.springframework.security.web.WebAttributes;
|
||||||
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
|
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
|
||||||
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
|
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
|
||||||
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Rob Winch
|
* @author Rob Winch
|
||||||
|
* @author Tadaya Tsuyukubo
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class AbstractPreAuthenticatedProcessingFilterTests {
|
public class AbstractPreAuthenticatedProcessingFilterTests {
|
||||||
|
@ -376,6 +378,43 @@ public class AbstractPreAuthenticatedProcessingFilterTests {
|
||||||
verifyZeroInteractions(am);
|
verifyZeroInteractions(am);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestNotMatchRequestMatcher() throws Exception {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
MockFilterChain chain = new MockFilterChain();
|
||||||
|
|
||||||
|
ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter();
|
||||||
|
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/no-matching"));
|
||||||
|
|
||||||
|
AuthenticationManager am = mock(AuthenticationManager.class);
|
||||||
|
filter.setAuthenticationManager(am);
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
|
||||||
|
filter.doFilter(request, response, chain);
|
||||||
|
|
||||||
|
verifyZeroInteractions(am);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestMatchesRequestMatcher() throws Exception {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
MockFilterChain chain = new MockFilterChain();
|
||||||
|
|
||||||
|
ConcretePreAuthenticatedProcessingFilter filter = new ConcretePreAuthenticatedProcessingFilter();
|
||||||
|
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/**"));
|
||||||
|
|
||||||
|
AuthenticationManager am = mock(AuthenticationManager.class);
|
||||||
|
filter.setAuthenticationManager(am);
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
|
||||||
|
filter.doFilter(request, response, chain);
|
||||||
|
|
||||||
|
verify(am).authenticate(any(PreAuthenticatedAuthenticationToken.class));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void testDoFilter(boolean grantAccess) throws Exception {
|
private void testDoFilter(boolean grantAccess) throws Exception {
|
||||||
MockHttpServletRequest req = new MockHttpServletRequest();
|
MockHttpServletRequest req = new MockHttpServletRequest();
|
||||||
MockHttpServletResponse res = new MockHttpServletResponse();
|
MockHttpServletResponse res = new MockHttpServletResponse();
|
||||||
|
|
Loading…
Reference in New Issue