SEC-319: Improvements to Siteminder integration: Create its own authentication provider & reeval strategy. Note that documentation not yet complete, but code is functional, test-covered and validated in a Siteminder environment.

This commit is contained in:
Scott McCrory
2006-07-27 01:13:46 +00:00
parent 52a167acfa
commit 8d3a2b42d9
7 changed files with 649 additions and 161 deletions

View File

@@ -0,0 +1,132 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.providers.siteminder;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.AuthenticationServiceException;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.DisabledException;
import org.acegisecurity.LockedException;
import org.acegisecurity.providers.AuthenticationProvider;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.util.Assert;
/**
* An {@link AuthenticationProvider} implementation that retrieves user details from an {@link UserDetailsService}.
*
* @author Scott McCrory
* @version $Id: SiteminderAuthenticationProvider.java 1582 2006-07-15 15:18:51Z smccrory $
*/
public class SiteminderAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
/**
* Our logging object
*/
private static final Log logger = LogFactory.getLog(SiteminderAuthenticationProvider.class);
//~ Instance fields ================================================================================================
/**
* Our user details service (which does the real work of checking the user against a back-end user store).
*/
private UserDetailsService userDetailsService;
//~ Methods ========================================================================================================
/**
* @see org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider#additionalAuthenticationChecks(org.acegisecurity.userdetails.UserDetails, org.acegisecurity.providers.UsernamePasswordAuthenticationToken)
*/
protected void additionalAuthenticationChecks(final UserDetails user,
final UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
// No need for password authentication checks - we only expect one identifying string
// from the HTTP Request header (as populated by Siteminder), but we do need to see if
// the user's account is OK to let them in.
if (!user.isEnabled()) {
throw new DisabledException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled",
"Account disabled"));
}
if (!user.isAccountNonExpired()) {
throw new AccountExpiredException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.expired",
"Account expired"));
}
if (!user.isAccountNonLocked()) {
throw new LockedException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
"Account locked"));
}
if (!user.isCredentialsNonExpired()) {
throw new CredentialsExpiredException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.credentialsExpired", "Credentials expired"));
}
}
/**
* @see org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider#doAfterPropertiesSet()
*/
protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
}
/**
* Return the user details service.
* @return The user details service.
*/
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
/**
* @see org.acegisecurity.providers.dao.AbstractUserDetailsAuthenticationProvider#retrieveUser(java.lang.String, org.acegisecurity.providers.UsernamePasswordAuthenticationToken)
*/
protected final UserDetails retrieveUser(final String username,
final UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
UserDetails loadedUser;
try {
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
} catch (DataAccessException repositoryProblem) {
throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}
if (loadedUser == null) {
throw new AuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
/**
* Sets the user details service.
* @param userDetailsService The user details service.
*/
public void setUserDetailsService(final UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
A Siteminder authentication provider.
</body>
</html>

View File

@@ -15,36 +15,40 @@
package org.acegisecurity.ui.webapp;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationException;
import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Extends Acegi's AuthenticationProcessingFilter to pick up CA/Netegrity Siteminder headers.<P>Also provides a
* backup form-based authentication and the ability set source key names.</p>
* <P><B>Siteminder</B> must present two <B>headers</B> to this filter, a username and password. You must set the
* Extends Acegi's AuthenticationProcessingFilter to pick up CA/Netegrity Siteminder headers.
*
* <P>Also provides a backup form-based authentication and the ability set source key names.</p>
*
* <P><B>Siteminder</B> must present two <B>headers</B> to this filter, a username and password. You must set the
* header keys before this filter is used for authentication, otherwise Siteminder checks will be skipped. If the
* Siteminder check is unsuccessful (i.e. if the headers are not found), then the form parameters will be checked (see
* next paragraph). This allows applications to optionally function even when their Siteminder infrastructure is
* unavailable, as is often the case during development.</p>
* <P><B>Login forms</B> must present two <B>parameters</B> to this filter: a username and password. If not
*
* <P><B>Login forms</B> must present two <B>parameters</B> to this filter: a username and password. If not
* specified, the parameter names to use are contained in the static fields {@link #ACEGI_SECURITY_FORM_USERNAME_KEY}
* and {@link #ACEGI_SECURITY_FORM_PASSWORD_KEY}.</p>
* <P><B>Do not use this class directly.</B> Instead, configure <code>web.xml</code> to use the {@link
*
* <P><B>Do not use this class directly.</B> Instead, configure <code>web.xml</code> to use the {@link
* org.acegisecurity.util.FilterToBeanProxy}.</p>
*
* @author Scott McCrory
* @version $Id$
*/
public class SiteminderAuthenticationProcessingFilter extends AuthenticationProcessingFilter {
//~ Static fields/initializers =====================================================================================
/** Log instance for debugging */
@@ -52,21 +56,15 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
//~ Instance fields ================================================================================================
/** Form password request key. */
private String formPasswordParameterKey = null;
/** Form username request key. */
private String formUsernameParameterKey = null;
/** Siteminder password header key. */
private String siteminderPasswordHeaderKey = null;
/** Siteminder username header key. */
private String siteminderUsernameHeaderKey = null;
//~ Constructors ===================================================================================================
/**
/**
* Basic constructor.
*/
public SiteminderAuthenticationProcessingFilter() {
@@ -76,24 +74,19 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
//~ Methods ========================================================================================================
/**
*
* @see org.acegisecurity.ui.AbstractProcessingFilter#attemptAuthentication(javax.servlet.http.HttpServletRequest)
*/
public Authentication attemptAuthentication(HttpServletRequest request)
throws AuthenticationException {
String username = null;
String password = null;
public Authentication attemptAuthentication(final HttpServletRequest request) throws AuthenticationException {
// Check the Siteminder headers for authentication info
if ((siteminderUsernameHeaderKey != null) && (siteminderUsernameHeaderKey.length() > 0)
&& (siteminderPasswordHeaderKey != null) && (siteminderPasswordHeaderKey.length() > 0)) {
String username = null;
// Check the Siteminder header for identification info
if ((siteminderUsernameHeaderKey != null) && (siteminderUsernameHeaderKey.length() > 0)) {
username = request.getHeader(siteminderUsernameHeaderKey);
password = request.getHeader(siteminderPasswordHeaderKey);
}
// If the Siteminder authentication info wasn't available, then get it
// from the form parameters
if ((username == null) || (username.length() == 0) || (password == null) || (password.length() == 0)) {
// If the Siteminder identification info wasn't available, then try to get it from the form
if ((username == null) || (username.length() == 0)) {
if (logger.isDebugEnabled()) {
logger.debug("Siteminder headers not found for authentication, so trying to use form values");
}
@@ -104,7 +97,6 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
username = request.getParameter(ACEGI_SECURITY_FORM_USERNAME_KEY);
}
password = obtainPassword(request);
}
// Convert username and password to upper case. This is normally not a
@@ -117,14 +109,9 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
username = "";
}
if (password != null) {
password = password.toUpperCase();
} else {
// If password is null, set to blank to avoid a NPE.
password = "";
}
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Pass in a null password value because it isn't relevant for Siteminder.
// Of course the AuthenticationManager needs to not care!
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, null);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
@@ -135,15 +122,6 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
return this.getAuthenticationManager().authenticate(authRequest);
}
/**
* Returns the form password parameter key.
*
* @return The form password parameter key.
*/
public String getFormPasswordParameterKey() {
return formPasswordParameterKey;
}
/**
* Returns the form username parameter key.
*
@@ -153,15 +131,6 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
return formUsernameParameterKey;
}
/**
* Returns the Siteminder password header key.
*
* @return The Siteminder password header key.
*/
public String getSiteminderPasswordHeaderKey() {
return siteminderPasswordHeaderKey;
}
/**
* Returns the Siteminder username header key.
*
@@ -172,20 +141,14 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
}
/**
* Overridden method to obtain different value depending on whether Siteminder or form validation is being
* performed.
* Overridden method to always return a null (Siteminder doesn't pass on the password).
*
* @param request so that request attributes can be retrieved
*
* @return the password that will be presented in the <code>Authentication</code> request token to the
* <code>AuthenticationManager</code>
* <code>AuthenticationManager</code> (null).
*/
protected String obtainPassword(HttpServletRequest request) {
if ((formPasswordParameterKey != null) && (formPasswordParameterKey.length() > 0)) {
return request.getParameter(formPasswordParameterKey);
} else {
return request.getParameter(ACEGI_SECURITY_FORM_PASSWORD_KEY);
}
protected String obtainPassword(final HttpServletRequest request) {
return null;
}
/**
@@ -197,6 +160,7 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
* javax.servlet.http.HttpServletResponse)
*/
protected boolean requiresAuthentication(final HttpServletRequest request, final HttpServletResponse response) {
String uri = request.getRequestURI();
int pathParamIndex = uri.indexOf(';');
@@ -208,8 +172,8 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
//attempt authentication if j_secuity_check is present or if the getDefaultTargetUrl()
//is present and user is not already authenticated.
boolean bAuthenticated = false;
SecurityContext context = (SecurityContext) request.getSession()
.getAttribute(HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
SecurityContext context = (SecurityContext) request.getSession().getAttribute(
HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
if (context != null) {
Authentication auth = context.getAuthentication();
@@ -222,7 +186,7 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
// if true is returned then authentication will be attempted.
boolean bAttemptAuthentication = (uri.endsWith(request.getContextPath() + getFilterProcessesUrl()))
|| ((getDefaultTargetUrl() != null) && uri.endsWith(getDefaultTargetUrl()) && !bAuthenticated);
|| ((getDefaultTargetUrl() != null) && uri.endsWith(getDefaultTargetUrl()) && !bAuthenticated);
if (logger.isDebugEnabled()) {
logger.debug("Authentication attempted for the following URI ==> " + uri + " is " + bAttemptAuthentication);
@@ -231,15 +195,6 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
return bAttemptAuthentication;
}
/**
* Sets the form password parameter key.
*
* @param key The form password parameter key.
*/
public void setFormPasswordParameterKey(final String key) {
this.formPasswordParameterKey = key;
}
/**
* Sets the form username parameter key.
*
@@ -249,15 +204,6 @@ public class SiteminderAuthenticationProcessingFilter extends AuthenticationProc
this.formUsernameParameterKey = key;
}
/**
* Sets the Siteminder password header key.
*
* @param key The Siteminder password header key.
*/
public void setSiteminderPasswordHeaderKey(final String key) {
this.siteminderPasswordHeaderKey = key;
}
/**
* Sets the Siteminder username header key.
*

View File

@@ -1,5 +1,5 @@
<html>
<body>
Authenticates users via a standard web form and <code>HttpSession</code>.
Authenticates users via HTTP properties, headers and session.
</body>
</html>

View File

@@ -0,0 +1,430 @@
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.acegisecurity.providers.siteminder;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
import org.acegisecurity.AccountExpiredException;
import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationServiceException;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.CredentialsExpiredException;
import org.acegisecurity.DisabledException;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.LockedException;
import org.acegisecurity.providers.TestingAuthenticationToken;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.dao.UserCache;
import org.acegisecurity.providers.dao.cache.EhCacheBasedUserCache;
import org.acegisecurity.providers.dao.cache.NullUserCache;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UserDetailsService;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
/**
* Tests {@link SiteminderAuthenticationProvider}.
*
* @author Ben Alex
* @version $Id: SiteminderAuthenticationProviderTests.java 1582 2006-07-15 15:18:51Z smccrory $
*/
public class SiteminderAuthenticationProviderTests extends TestCase {
//~ Methods ========================================================================================================
public static void main(String[] args) {
junit.textui.TestRunner.run(SiteminderAuthenticationProviderTests.class);
}
public final void setUp() throws Exception {
super.setUp();
}
public void testAuthenticateFailsIfAccountExpired() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserPeterAccountExpired());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown AccountExpiredException");
} catch (AccountExpiredException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsIfAccountLocked() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserPeterAccountLocked());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown LockedException");
} catch (LockedException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsIfCredentialsExpired() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserPeterCredentialsExpired());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown CredentialsExpiredException");
} catch (CredentialsExpiredException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsIfUserDisabled() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("peter", "opal");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserPeter());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown DisabledException");
} catch (DisabledException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWhenUserDetailsServiceHasBackendFailure() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceSimulateBackendError());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown AuthenticationServiceException");
} catch (AuthenticationServiceException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWithEmptyUsername() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown BadCredentialsException");
} catch (BadCredentialsException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWithInvalidUsernameAndHideUserNotFoundExceptionFalse() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("INVALID_USER", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setHideUserNotFoundExceptions(false); // we want UsernameNotFoundExceptions
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown UsernameNotFoundException");
} catch (UsernameNotFoundException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWithInvalidUsernameAndHideUserNotFoundExceptionsWithDefaultOfTrue() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("INVALID_USER", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
assertTrue(provider.isHideUserNotFoundExceptions());
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown BadCredentialsException");
} catch (BadCredentialsException expected) {
assertTrue(true);
}
}
public void testAuthenticateFailsWithMixedCaseUsernameIfDefaultChanged() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("MaRiSSA", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
try {
provider.authenticate(token);
fail("Should have thrown BadCredentialsException");
} catch (BadCredentialsException expected) {
assertTrue(true);
}
}
public void testAuthenticates() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
token.setDetails("192.168.0.1");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
Authentication result = provider.authenticate(token);
if (!(result instanceof UsernamePasswordAuthenticationToken)) {
fail("Should have returned instance of UsernamePasswordAuthenticationToken");
}
UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
assertEquals(User.class, castResult.getPrincipal().getClass());
assertEquals("koala", castResult.getCredentials());
assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
assertEquals("192.168.0.1", castResult.getDetails());
}
public void testAuthenticatesASecondTime() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
Authentication result = provider.authenticate(token);
if (!(result instanceof UsernamePasswordAuthenticationToken)) {
fail("Should have returned instance of UsernamePasswordAuthenticationToken");
}
// Now try to authenticate with the previous result (with its UserDetails)
Authentication result2 = provider.authenticate(result);
if (!(result2 instanceof UsernamePasswordAuthenticationToken)) {
fail("Should have returned instance of UsernamePasswordAuthenticationToken");
}
assertEquals(result.getCredentials(), result2.getCredentials());
}
public void testAuthenticatesWithForcePrincipalAsString() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
provider.setUserCache(new MockUserCache());
provider.setForcePrincipalAsString(true);
Authentication result = provider.authenticate(token);
if (!(result instanceof UsernamePasswordAuthenticationToken)) {
fail("Should have returned instance of UsernamePasswordAuthenticationToken");
}
UsernamePasswordAuthenticationToken castResult = (UsernamePasswordAuthenticationToken) result;
assertEquals(String.class, castResult.getPrincipal().getClass());
assertEquals("marissa", castResult.getPrincipal());
}
public void testDetectsNullBeingReturnedFromUserDetailsService() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("marissa", "koala");
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceReturnsNull());
try {
provider.authenticate(token);
fail("Should have thrown AuthenticationServiceException");
} catch (AuthenticationServiceException expected) {
assertEquals("UserDetailsService returned null, which is an interface contract violation", expected
.getMessage());
}
}
public void testGettersSetters() {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserCache(new EhCacheBasedUserCache());
assertEquals(EhCacheBasedUserCache.class, provider.getUserCache().getClass());
assertFalse(provider.isForcePrincipalAsString());
provider.setForcePrincipalAsString(true);
assertTrue(provider.isForcePrincipalAsString());
}
public void testStartupFailsIfNoUserDetailsService() throws Exception {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
try {
provider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testStartupFailsIfNoUserCacheSet() throws Exception {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
provider.setUserDetailsService(new MockUserDetailsServiceUserMarissa());
assertEquals(NullUserCache.class, provider.getUserCache().getClass());
provider.setUserCache(null);
try {
provider.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
public void testStartupSuccess() throws Exception {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
UserDetailsService userDetailsService = new MockUserDetailsServiceUserMarissa();
provider.setUserDetailsService(userDetailsService);
provider.setUserCache(new MockUserCache());
assertEquals(userDetailsService, provider.getUserDetailsService());
provider.afterPropertiesSet();
assertTrue(true);
}
public void testSupports() {
SiteminderAuthenticationProvider provider = new SiteminderAuthenticationProvider();
assertTrue(provider.supports(UsernamePasswordAuthenticationToken.class));
assertTrue(!provider.supports(TestingAuthenticationToken.class));
}
//~ Inner Classes ==================================================================================================
private class MockUserDetailsServiceReturnsNull implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
return null;
}
}
private class MockUserDetailsServiceSimulateBackendError implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
throw new DataRetrievalFailureException("This mock simulator is designed to fail");
}
}
private class MockUserDetailsServiceUserMarissa implements UserDetailsService {
private String password = "koala";
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("marissa".equals(username)) {
return new User("marissa", password, true, true, true, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
public void setPassword(String password) {
this.password = password;
}
}
private class MockUserDetailsServiceUserMarissaWithSalt implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("marissa".equals(username)) {
return new User("marissa", "koala{SYSTEM_SALT_VALUE}", true, true, true, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserDetailsServiceUserPeter implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username)) {
return new User("peter", "opal", false, true, true, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserDetailsServiceUserPeterAccountExpired implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username)) {
return new User("peter", "opal", true, false, true, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserDetailsServiceUserPeterAccountLocked implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username)) {
return new User("peter", "opal", true, true, true, false, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserDetailsServiceUserPeterCredentialsExpired implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
if ("peter".equals(username)) {
return new User("peter", "opal", true, true, false, true, new GrantedAuthority[] {
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO") });
} else {
throw new UsernameNotFoundException("Could not find: " + username);
}
}
}
private class MockUserCache implements UserCache {
private Map cache = new HashMap();
public UserDetails getUserFromCache(String username) {
return (User) cache.get(username);
}
public void putUserInCache(UserDetails user) {
cache.put(user.getUsername(), user);
}
public void removeUserFromCache(String username) {
}
}
}

View File

@@ -19,13 +19,10 @@ import junit.framework.TestCase;
import org.acegisecurity.Authentication;
import org.acegisecurity.MockAuthenticationManager;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Tests SiteminderAuthenticationProcessingFilter.
*
@@ -36,18 +33,18 @@ import org.springframework.mock.web.MockHttpServletResponse;
public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
//~ Constructors ===================================================================================================
/**
* Basic constructor.
*/
/**
* Basic constructor.
*/
public SiteminderAuthenticationProcessingFilterTests() {
super();
}
/**
* Argument constructor.
*
* @param arg0
*/
/**
* Argument constructor.
*
* @param arg0
*/
public SiteminderAuthenticationProcessingFilterTests(String arg0) {
super(arg0);
}
@@ -92,15 +89,9 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
filter.setFilterProcessesUrl("foobar");
assertEquals("foobar", filter.getFilterProcessesUrl());
filter.setFormPasswordParameterKey("passwordParamKey");
assertEquals("passwordParamKey", filter.getFormPasswordParameterKey());
filter.setFormUsernameParameterKey("usernameParamKey");
assertEquals("usernameParamKey", filter.getFormUsernameParameterKey());
filter.setSiteminderPasswordHeaderKey("passwordHeaderKey");
assertEquals("passwordHeaderKey", filter.getSiteminderPasswordHeaderKey());
filter.setSiteminderUsernameHeaderKey("usernameHeaderKey");
assertEquals("usernameHeaderKey", filter.getSiteminderUsernameHeaderKey());
}
@@ -131,8 +122,7 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
*
* @throws Exception
*/
public void testFormNullPasswordHandledGracefully()
throws Exception {
public void testFormNullPasswordHandledGracefully() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter(SiteminderAuthenticationProcessingFilter.ACEGI_SECURITY_FORM_USERNAME_KEY, "marissa");
@@ -151,8 +141,7 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
*
* @throws Exception
*/
public void testFormNullUsernameHandledGracefully()
throws Exception {
public void testFormNullUsernameHandledGracefully() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter(SiteminderAuthenticationProcessingFilter.ACEGI_SECURITY_FORM_PASSWORD_KEY, "koala");
@@ -186,7 +175,6 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
filter.setAuthenticationManager(authMgrThatGrantsAccess);
filter.setSiteminderUsernameHeaderKey("SM_USER");
filter.setSiteminderPasswordHeaderKey("SM_USER");
filter.init(null);
// Requests for an unknown URL should NOT require (re)authentication
@@ -220,7 +208,6 @@ public class SiteminderAuthenticationProcessingFilterTests extends TestCase {
SiteminderAuthenticationProcessingFilter filter = new SiteminderAuthenticationProcessingFilter();
filter.setAuthenticationManager(authMgr);
filter.setSiteminderUsernameHeaderKey("SM_USER");
filter.setSiteminderPasswordHeaderKey("SM_USER");
filter.init(null);
Authentication result = filter.attemptAuthentication(request);