SEC-1195: Change <http> parsing behaviour to use an internal AuthenticationManager instance. Implemented "parent" AuthenticationManager in ProviderManager which is delegated to when no authentication is returned by the instances list of authentication providers. Extracted the Authentication success/failure publishing into a separate strategy.
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
package org.springframework.security;
|
||||
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MockApplicationEventPublisher implements ApplicationEventPublisher {
|
||||
private Boolean expectedEvent;
|
||||
private ApplicationEvent lastEvent;
|
||||
|
||||
public MockApplicationEventPublisher() {
|
||||
}
|
||||
|
||||
public MockApplicationEventPublisher(boolean expectedEvent) {
|
||||
this.expectedEvent = Boolean.valueOf(expectedEvent);
|
||||
}
|
||||
|
||||
public void publishEvent(ApplicationEvent event) {
|
||||
if (expectedEvent != null && !expectedEvent.booleanValue()) {
|
||||
throw new IllegalStateException("The ApplicationEventPublisher did not expect to receive this event");
|
||||
}
|
||||
|
||||
lastEvent = event;
|
||||
}
|
||||
|
||||
public ApplicationEvent getLastEvent() {
|
||||
return lastEvent;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.MockApplicationEventPublisher;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.ProviderManager;
|
||||
import org.springframework.security.authentication.ProviderNotFoundException;
|
||||
@@ -31,7 +31,6 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.concurrent.ConcurrentLoginException;
|
||||
import org.springframework.security.authentication.concurrent.ConcurrentSessionController;
|
||||
import org.springframework.security.authentication.concurrent.NullConcurrentSessionController;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
@@ -43,6 +42,7 @@ import org.springframework.security.core.authority.AuthorityUtils;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ProviderManagerTests {
|
||||
|
||||
@Test(expected=ProviderNotFoundException.class)
|
||||
@@ -51,46 +51,34 @@ public class ProviderManagerTests {
|
||||
AuthorityUtils.createAuthorityList("ROLE_ONE", "ROLE_TWO"));
|
||||
|
||||
ProviderManager mgr = makeProviderManager();
|
||||
mgr.setApplicationEventPublisher(new MockApplicationEventPublisher(true));
|
||||
mgr.setMessageSource(mock(MessageSource.class));
|
||||
mgr.authenticate(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationSucceedsWithSupportedTokenAndReturnsExpectedObject() throws Exception {
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("Test", "Password","ROLE_ONE","ROLE_TWO");
|
||||
final Authentication a = mock(Authentication.class);
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
AuthenticationEventPublisher publisher = mock(AuthenticationEventPublisher.class);
|
||||
mgr.setAuthenticationEventPublisher(publisher);
|
||||
mgr.setProviders(Arrays.asList(createProviderWhichReturns(a)));
|
||||
|
||||
ProviderManager mgr = makeProviderManager();
|
||||
mgr.setApplicationEventPublisher(new MockApplicationEventPublisher(true));
|
||||
|
||||
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(AuthorityUtils.createAuthorityList("ROLE_ONE","ROLE_TWO"), castResult.getAuthorities());
|
||||
Authentication result = mgr.authenticate(a);
|
||||
assertEquals(a, result);
|
||||
verify(publisher).publishAuthenticationSuccess(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationSuccessWhenFirstProviderReturnsNullButSecondAuthenticates() {
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("Test", "Password","ROLE_ONE","ROLE_TWO");
|
||||
ProviderManager mgr = makeProviderManagerWithMockProviderWhichReturnsNullInList();
|
||||
mgr.setApplicationEventPublisher(new MockApplicationEventPublisher(true));
|
||||
public void authenticationSucceedsWhenFirstProviderReturnsNullButSecondAuthenticates() {
|
||||
final Authentication a = mock(Authentication.class);
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
AuthenticationEventPublisher publisher = mock(AuthenticationEventPublisher.class);
|
||||
mgr.setAuthenticationEventPublisher(publisher);
|
||||
mgr.setProviders(Arrays.asList(createProviderWhichReturns(null), createProviderWhichReturns(a)));
|
||||
|
||||
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().get(0).getAuthority());
|
||||
assertEquals("ROLE_TWO", castResult.getAuthorities().get(1).getAuthority());
|
||||
Authentication result = mgr.authenticate(a);
|
||||
assertSame(a, result);
|
||||
verify(publisher).publishAuthenticationSuccess(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,11 +87,10 @@ public class ProviderManagerTests {
|
||||
|
||||
//The NullConcurrentSessionController should be the default
|
||||
assertNotNull(target.getSessionController());
|
||||
assertTrue(target.getSessionController() instanceof NullConcurrentSessionController);
|
||||
|
||||
ConcurrentSessionController csc = mock(ConcurrentSessionController.class);
|
||||
target.setSessionController(csc);
|
||||
assertEquals(csc, target.getSessionController());
|
||||
assertSame(csc, target.getSessionController());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
@@ -119,8 +106,6 @@ public class ProviderManagerTests {
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void getProvidersFailsIfProviderListNotSet() throws Exception {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
|
||||
mgr.afterPropertiesSet();
|
||||
mgr.getProviders();
|
||||
}
|
||||
|
||||
@@ -137,6 +122,7 @@ public class ProviderManagerTests {
|
||||
final Object resultDetails = "(Result Details)";
|
||||
ProviderManager authMgr = makeProviderManager();
|
||||
|
||||
// A provider which sets the details object
|
||||
AuthenticationProvider provider = new AuthenticationProvider() {
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
((TestingAuthenticationToken)authentication).setDetails(resultDetails);
|
||||
@@ -166,25 +152,53 @@ public class ProviderManagerTests {
|
||||
request.setDetails(details);
|
||||
|
||||
Authentication result = authMgr.authenticate(request);
|
||||
assertEquals(details, result.getDetails());
|
||||
assertSame(details, result.getDetails());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationExceptionIsIgnoredIfLaterProviderAuthenticates() throws Exception {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
final Authentication authReq = mock(Authentication.class);
|
||||
mgr.setProviders(Arrays.asList(createProviderWhichThrows(new BadCredentialsException("")),
|
||||
createProviderWhichReturns(authReq)));
|
||||
assertSame(authReq, mgr.authenticate(mock(Authentication.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationExceptionIsRethrownIfNoLaterProviderAuthenticates() throws Exception {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
|
||||
mgr.setProviders(Arrays.asList(createProviderWhichThrows(new BadCredentialsException("")),
|
||||
createProviderWhichReturns(null)));
|
||||
try {
|
||||
mgr.authenticate(mock(Authentication.class));
|
||||
fail("Expected BadCredentialsException");
|
||||
} catch (BadCredentialsException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-546
|
||||
@Test(expected=AccountStatusException.class)
|
||||
@Test
|
||||
public void accountStatusExceptionPreventsCallsToSubsequentProviders() throws Exception {
|
||||
ProviderManager authMgr = makeProviderManager();
|
||||
AuthenticationProvider iThrowAccountStatusException = createProviderWhichThrows(new AccountStatusException(""){});
|
||||
AuthenticationProvider otherProvider = mock(AuthenticationProvider.class);
|
||||
|
||||
authMgr.setProviders(Arrays.asList(new MockProviderWhichThrowsAccountStatusException(),
|
||||
new MockProviderWhichThrowsConcurrentLoginException()) );
|
||||
authMgr.setProviders(Arrays.asList(iThrowAccountStatusException, otherProvider));
|
||||
|
||||
authMgr.authenticate(createAuthenticationToken());
|
||||
try {
|
||||
authMgr.authenticate(mock(Authentication.class));
|
||||
fail("Expected AccountStatusException");
|
||||
} catch (AccountStatusException expected) {
|
||||
}
|
||||
verifyZeroInteractions(otherProvider);
|
||||
}
|
||||
|
||||
@Test(expected=ConcurrentLoginException.class)
|
||||
public void concurrentLoginExceptionPreventsCallsToSubsequentProviders() throws Exception {
|
||||
ProviderManager authMgr = makeProviderManager();
|
||||
// Two providers so if the second is polled it will throw an AccountStatusException
|
||||
authMgr.setProviders(Arrays.asList(new MockProvider(), new MockProviderWhichThrowsAccountStatusException()) );
|
||||
// Two providers so if the second is polled it will throw an BadCredentialsException
|
||||
authMgr.setProviders(Arrays.asList(new MockProvider(), createProviderWhichThrows(new BadCredentialsException(""))) );
|
||||
TestingAuthenticationToken request = createAuthenticationToken();
|
||||
ConcurrentSessionController ctrlr = mock(ConcurrentSessionController.class);
|
||||
doThrow(new ConcurrentLoginException("mocked")).when(ctrlr).checkAuthenticationAllowed(request);
|
||||
@@ -193,6 +207,88 @@ public class ProviderManagerTests {
|
||||
authMgr.authenticate(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parentAuthenticationIsUsedIfProvidersDontAuthenticate() throws Exception {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
mgr.setProviders(Arrays.asList(mock(AuthenticationProvider.class)));
|
||||
Authentication authReq = mock(Authentication.class);
|
||||
AuthenticationManager parent = mock(AuthenticationManager.class);
|
||||
when(parent.authenticate(authReq)).thenReturn(authReq);
|
||||
mgr.setParent(parent);
|
||||
assertSame(authReq, mgr.authenticate(authReq));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parentIsNotCalledIfAccountStatusExceptionIsThrown() throws Exception {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
AuthenticationProvider iThrowAccountStatusException = createProviderWhichThrows(new AccountStatusException(""){});
|
||||
mgr.setProviders(Arrays.asList(iThrowAccountStatusException));
|
||||
AuthenticationManager parent = mock(AuthenticationManager.class);
|
||||
mgr.setParent(parent);
|
||||
try {
|
||||
mgr.authenticate(mock(Authentication.class));
|
||||
fail("Expected exception");
|
||||
} catch (AccountStatusException expected) {
|
||||
}
|
||||
verifyZeroInteractions(parent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providerNotFoundFromParentIsIgnored() throws Exception {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
final Authentication authReq = mock(Authentication.class);
|
||||
AuthenticationEventPublisher publisher = mock(AuthenticationEventPublisher.class);
|
||||
mgr.setAuthenticationEventPublisher(publisher);
|
||||
// Set a provider that throws an exception - this is the exception we expect to be propagated
|
||||
mgr.setProviders(Arrays.asList(createProviderWhichThrows(new BadCredentialsException(""))));
|
||||
AuthenticationManager parent = mock(AuthenticationManager.class);
|
||||
when(parent.authenticate(authReq)).thenThrow(new ProviderNotFoundException(""));
|
||||
mgr.setParent(parent);
|
||||
try {
|
||||
mgr.authenticate(authReq);
|
||||
fail("Expected exception");
|
||||
} catch (BadCredentialsException expected) {
|
||||
verify(publisher).publishAuthenticationFailure(expected, authReq);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationExceptionFromParentOverridesPreviousOnes() throws Exception {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
final Authentication authReq = mock(Authentication.class);
|
||||
AuthenticationEventPublisher publisher = mock(AuthenticationEventPublisher.class);
|
||||
mgr.setAuthenticationEventPublisher(publisher);
|
||||
// Set a provider that throws an exception - this is the exception we expect to be propagated
|
||||
final BadCredentialsException expected = new BadCredentialsException("I'm the one from the parent");
|
||||
mgr.setProviders(Arrays.asList(createProviderWhichThrows(new BadCredentialsException(""))));
|
||||
AuthenticationManager parent = mock(AuthenticationManager.class);
|
||||
when(parent.authenticate(authReq)).thenThrow(expected);
|
||||
mgr.setParent(parent);
|
||||
try {
|
||||
mgr.authenticate(authReq);
|
||||
fail("Expected exception");
|
||||
} catch (BadCredentialsException e) {
|
||||
assertSame(expected, e);
|
||||
}
|
||||
verify(publisher).publishAuthenticationFailure(expected, authReq);
|
||||
}
|
||||
|
||||
private AuthenticationProvider createProviderWhichThrows(final AuthenticationException e) {
|
||||
AuthenticationProvider provider = mock(AuthenticationProvider.class);
|
||||
when(provider.supports(any(Class.class))).thenReturn(true);
|
||||
when(provider.authenticate(any(Authentication.class))).thenThrow(e);
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
private AuthenticationProvider createProviderWhichReturns(final Authentication a) {
|
||||
AuthenticationProvider provider = mock(AuthenticationProvider.class);
|
||||
when(provider.supports(any(Class.class))).thenReturn(true);
|
||||
when(provider.authenticate(any(Authentication.class))).thenReturn(a);
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
private TestingAuthenticationToken createAuthenticationToken() {
|
||||
return new TestingAuthenticationToken("name", "password", new ArrayList<GrantedAuthority>(0));
|
||||
}
|
||||
@@ -205,21 +301,6 @@ public class ProviderManagerTests {
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
mgr.setProviders(providers);
|
||||
|
||||
mgr.afterPropertiesSet();
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
private ProviderManager makeProviderManagerWithMockProviderWhichReturnsNullInList() {
|
||||
MockProviderWhichReturnsNull provider1 = new MockProviderWhichReturnsNull();
|
||||
MockProvider provider2 = new MockProvider();
|
||||
List<Object> providers = new ArrayList<Object>();
|
||||
providers.add(provider1);
|
||||
providers.add(provider2);
|
||||
|
||||
ProviderManager mgr = new ProviderManager();
|
||||
mgr.setProviders(providers);
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
@@ -242,43 +323,4 @@ public class ProviderManagerTests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<? extends Object> authentication) {
|
||||
if (TestingAuthenticationToken.class.isAssignableFrom(authentication)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MockProviderWhichThrowsAccountStatusException implements AuthenticationProvider {
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
throw new AccountStatusException("xxx") {};
|
||||
}
|
||||
|
||||
public boolean supports(Class<? extends Object> authentication) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class MockProviderWhichThrowsConcurrentLoginException implements AuthenticationProvider {
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
throw new ConcurrentLoginException("xxx") {};
|
||||
}
|
||||
|
||||
public boolean supports(Class<? extends Object> authentication) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.springframework.security.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MethodInvocationUtilsTests {
|
||||
|
||||
@Test
|
||||
public void createFromClassReturnsMethodWithNoArgInfoForMethodWithNoArgs() {
|
||||
MethodInvocation mi = MethodInvocationUtils.createFromClass(String.class, "length");
|
||||
assertNotNull(mi);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromClassWithNoArgInfoReturnsNullForMethodWithArgs() {
|
||||
MethodInvocation mi = MethodInvocationUtils.createFromClass(String.class, "codePointAt");
|
||||
assertNull(mi);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createFromClassReturnsMethodIfGivArgInfoForMethodWithArgs() {
|
||||
MethodInvocation mi = MethodInvocationUtils.createFromClass(null, String.class, "compareTo",
|
||||
new Class<?>[]{String.class}, new Object[] {""});
|
||||
assertNotNull(mi);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user