Modify contract of AuthenticationProvider to allow AuthenticationProvider implementations to return null if they do not wish to process a given Authentication request, despite asserting they support it.

This commit is contained in:
Ben Alex 2004-04-18 12:03:07 +00:00
parent a6b5b8d828
commit 872ace9164
3 changed files with 79 additions and 5 deletions

View File

@ -35,7 +35,12 @@ public interface AuthenticationProvider {
* *
* @param authentication the authentication request object. * @param authentication the authentication request object.
* *
* @return a fully authenticated object including credentials. * @return a fully authenticated object including credentials. May return
* <code>null</code> if the <code>AuthenticationProvider</code> is
* unable to support authentication of the passed
* <code>Authentication</code> object. In such a case, the next
* <code>AuthenticationProvider</code> that supports the presented
* <code>Authentication</code> class will be tried.
* *
* @throws AuthenticationException if authentication fails. * @throws AuthenticationException if authentication fails.
*/ */
@ -43,8 +48,18 @@ public interface AuthenticationProvider {
throws AuthenticationException; throws AuthenticationException;
/** /**
* Returns true if this <Code>AuthenticationProvider</code> supports the * Returns <code>true</code> if this <Code>AuthenticationProvider</code>
* indicated <Code>Authentication</code> object. * supports the indicated <Code>Authentication</code> object.
*
* <p>
* Returning <code>true</code> does not guarantee an
* <code>AuthenticationProvider</code> will be able to authenticate the
* presented instance of the <code>Authentication</code> class. It simply
* indicates it can support closer evaluation of it. An
* <code>AuthenticationProvider</code> can still return <code>null</code>
* from the {@link #authenticate(Authentication)} method to indicate
* another <code>AuthenticationProvider</code> should be tried.
* </p>
* *
* <P> * <P>
* Selection of an <code>AuthenticationProvider</code> capable of * Selection of an <code>AuthenticationProvider</code> capable of
@ -52,7 +67,8 @@ public interface AuthenticationProvider {
* <code>ProviderManager</code>. * <code>ProviderManager</code>.
* </p> * </p>
* *
* @return DOCUMENT ME! * @return <code>true</code> if the implementation can more closely
* evaluate the <code>Authentication</code> class presented
*/ */
public boolean supports(Class authentication); public boolean supports(Class authentication);
} }

View File

@ -123,7 +123,11 @@ public class ProviderManager implements InitializingBean, AuthenticationManager
logger.debug("Authentication attempt using " logger.debug("Authentication attempt using "
+ provider.getClass().getName()); + provider.getClass().getName());
return provider.authenticate(authentication); Authentication result = provider.authenticate(authentication);
if (result != null) {
return result;
}
} }
} }

View File

@ -90,6 +90,26 @@ public class ProviderManagerTests extends TestCase {
assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority()); assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
} }
public void testAuthenticationSuccessWhenFirstProviderReturnsNullButSecondAuthenticates() {
TestingAuthenticationToken token = new TestingAuthenticationToken("Test",
"Password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(
"ROLE_TWO")});
ProviderManager mgr = makeProviderManagerWithMockProviderWhichReturnsNullInList();
Authentication result = mgr.authenticate(token);
if (!(result instanceof TestingAuthenticationToken)) {
fail("Should have returned instance of TestingAuthenticationToken");
}
TestingAuthenticationToken castResult = (TestingAuthenticationToken) result;
assertEquals("Test", castResult.getPrincipal());
assertEquals("Password", castResult.getCredentials());
assertEquals("ROLE_ONE", castResult.getAuthorities()[0].getAuthority());
assertEquals("ROLE_TWO", castResult.getAuthorities()[1].getAuthority());
}
public void testStartupFailsIfProviderListDoesNotContainingProviders() public void testStartupFailsIfProviderListDoesNotContainingProviders()
throws Exception { throws Exception {
List providers = new Vector(); List providers = new Vector();
@ -146,6 +166,19 @@ public class ProviderManagerTests extends TestCase {
return mgr; return mgr;
} }
private ProviderManager makeProviderManagerWithMockProviderWhichReturnsNullInList() {
MockProviderWhichReturnsNull provider1 = new MockProviderWhichReturnsNull();
MockProvider provider2 = new MockProvider();
List providers = new Vector();
providers.add(provider1);
providers.add(provider2);
ProviderManager mgr = new ProviderManager();
mgr.setProviders(providers);
return mgr;
}
//~ Inner Classes ========================================================== //~ Inner Classes ==========================================================
private class MockProvider implements AuthenticationProvider { private class MockProvider implements AuthenticationProvider {
@ -168,4 +201,25 @@ public class ProviderManagerTests extends TestCase {
} }
} }
} }
private class MockProviderWhichReturnsNull implements AuthenticationProvider {
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
if (supports(authentication.getClass())) {
return null;
} else {
throw new AuthenticationServiceException(
"Don't support this class");
}
}
public boolean supports(Class authentication) {
if (TestingAuthenticationToken.class.isAssignableFrom(
authentication)) {
return true;
} else {
return false;
}
}
}
} }