OPEN - issue SEC-657: Create pre-authenticated processing filter which obtains username from request header

http://jira.springframework.org/browse/SEC-657. Added filter and test class.
This commit is contained in:
Luke Taylor 2008-03-30 13:37:13 +00:00
parent b98c72056a
commit c9b6fe9555
4 changed files with 178 additions and 8 deletions

View File

@ -63,11 +63,11 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
/**
* Do the actual authentication for a pre-authenticated user.
*/
private void doAuthenticate(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
private void doAuthenticate(HttpServletRequest request, HttpServletResponse response) {
Authentication authResult = null;
Object principal = getPreAuthenticatedPrincipal(httpRequest);
Object credentials = getPreAuthenticatedCredentials(httpRequest);
Object principal = getPreAuthenticatedPrincipal(request);
Object credentials = getPreAuthenticatedCredentials(request);
if (principal == null) {
if (logger.isDebugEnabled()) {
@ -83,11 +83,11 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
try {
PreAuthenticatedAuthenticationToken authRequest = new PreAuthenticatedAuthenticationToken(principal, credentials);
authRequest.setDetails(authenticationDetailsSource.buildDetails(httpRequest));
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
authResult = authenticationManager.authenticate(authRequest);
successfulAuthentication(httpRequest, httpResponse, authResult);
successfulAuthentication(request, response, authResult);
} catch (AuthenticationException failed) {
unsuccessfulAuthentication(httpRequest, httpResponse, failed);
unsuccessfulAuthentication(request, response, failed);
}
}
@ -144,7 +144,7 @@ public abstract class AbstractPreAuthenticatedProcessingFilter extends SpringSec
this.authenticationManager = authenticationManager;
}
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest httpRequest);
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest httpRequest);
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
}

View File

@ -0,0 +1,11 @@
package org.springframework.security.ui.preauth;
import org.springframework.security.AuthenticationException;
public class PreAuthenticatedCredentialsNotFoundException extends AuthenticationException {
public PreAuthenticatedCredentialsNotFoundException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,76 @@
package org.springframework.security.ui.preauth.header;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.ui.FilterChainOrder;
import org.springframework.security.ui.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.ui.preauth.PreAuthenticatedCredentialsNotFoundException;
import org.springframework.util.Assert;
/**
* A simple pre-authenticated filter which obtains the username from a request header, for use with systems such as
* CA Siteminder.
* <p>
* As with most pre-authenticated scenarios, it is essential that the external authentication system is set up
* correctly as this filter does no authentication whatsoever. All the protection is assumed to be provided externally
* and if this filter is included inappropriately in a configuration, it would be possible to assume the
* identity of a user merely by setting the correct header name. This also means it should not be used in combination
* with other Spring Security authentication mechanisms such as form login, as this would imply there was a means of
* bypassing the external system which would be risky.
* <p>
* The property <tt>principalRequestHeader</tt> is the name of the request header that contains the username. It
* defaults to "SM_USER" for compatibility with Siteminder.
*
*
* @author Luke Taylor
* @version $Id$
* @since 2.0
*/
public class RequestHeaderPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
private String principalRequestHeader = "SM_USER";
private String credentialsRequestHeader;
/**
* Read and returns the header named by <tt>principalRequestHeader</tt> from the request.
*
* @throws PreAuthenticatedCredentialsNotFoundException if the header is missing
*/
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
String principal = request.getHeader(principalRequestHeader);
if (principal == null) {
throw new PreAuthenticatedCredentialsNotFoundException(principalRequestHeader
+ " header not found in request.");
}
return principal;
}
/**
* Credentials aren't usually applicable, but if a <tt>credentialsRequestHeader</tt> is set, this
* will be read and used as the credentials value. Otherwise a dummy value will be used.
*/
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
if (credentialsRequestHeader != null) {
String credentials = request.getHeader(credentialsRequestHeader);
return credentials;
}
return "N/A";
}
public void setPrincipalRequestHeader(String principalRequestHeader) {
Assert.hasText(principalRequestHeader, "principalRequestHeader must not be empty or null");
this.principalRequestHeader = principalRequestHeader;
}
public void setCredentialsRequestHeader(String credentialsRequestHeader) {
Assert.hasText(credentialsRequestHeader, "credentialsRequestHeader must not be empty or null");
this.credentialsRequestHeader = credentialsRequestHeader;
}
public int getOrder() {
return FilterChainOrder.PRE_AUTH_FILTER;
}
}

View File

@ -0,0 +1,83 @@
package org.springframework.security.ui.preauth.header;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.MockAuthenticationManager;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.security.ui.preauth.PreAuthenticatedCredentialsNotFoundException;
/**
*
* @author Luke Taylor
* @version $Id$
*/
public class RequestHeaderPreAuthenticatedProcessingFilterTests {
@After
public void clearContext() {
SecurityContextHolder.clearContext();
}
@Test(expected = PreAuthenticatedCredentialsNotFoundException.class)
public void rejectsMissingHeader() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
RequestHeaderPreAuthenticatedProcessingFilter filter = new RequestHeaderPreAuthenticatedProcessingFilter();
filter.getOrder();
filter.doFilter(request, response, chain);
}
@Test
public void defaultsToUsingSiteminderHeader() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("SM_USER", "cat");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
RequestHeaderPreAuthenticatedProcessingFilter filter = new RequestHeaderPreAuthenticatedProcessingFilter();
filter.setAuthenticationManager(new MockAuthenticationManager());
filter.doFilter(request, response, chain);
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
assertEquals("cat", SecurityContextHolder.getContext().getAuthentication().getName());
assertEquals("N/A", SecurityContextHolder.getContext().getAuthentication().getCredentials());
}
@Test
public void alternativeHeaderNameIsSupported() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("myUsernameHeader", "wolfman");
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
RequestHeaderPreAuthenticatedProcessingFilter filter = new RequestHeaderPreAuthenticatedProcessingFilter();
filter.setAuthenticationManager(new MockAuthenticationManager());
filter.setPrincipalRequestHeader("myUsernameHeader");
filter.doFilter(request, response, chain);
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
assertEquals("wolfman", SecurityContextHolder.getContext().getAuthentication().getName());
}
@Test
public void credentialsAreRetrievedIfHeaderNameIsSet() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
MockFilterChain chain = new MockFilterChain();
RequestHeaderPreAuthenticatedProcessingFilter filter = new RequestHeaderPreAuthenticatedProcessingFilter();
filter.setAuthenticationManager(new MockAuthenticationManager());
filter.setCredentialsRequestHeader("myCredentialsHeader");
request.addHeader("SM_USER", "cat");
request.addHeader("myCredentialsHeader", "catspassword");
filter.doFilter(request, response, chain);
assertNotNull(SecurityContextHolder.getContext().getAuthentication());
assertEquals("catspassword", SecurityContextHolder.getContext().getAuthentication().getCredentials());
}
}