AuthenticationFailureEvent should publish once

Fixes gh-6281
This commit is contained in:
Joe Grandja 2018-12-18 17:08:08 -05:00
parent b838f7c7b7
commit be23ab8114
2 changed files with 42 additions and 10 deletions

View File

@ -156,6 +156,7 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
throws AuthenticationException {
Class<? extends Authentication> toTest = authentication.getClass();
AuthenticationException lastException = null;
AuthenticationException parentException = null;
Authentication result = null;
Authentication parentResult = null;
boolean debug = logger.isDebugEnabled();
@ -205,7 +206,7 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
// handled the request
}
catch (AuthenticationException e) {
lastException = e;
lastException = parentException = e;
}
}
@ -234,7 +235,11 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
"No AuthenticationProvider found for {0}"));
}
prepareException(lastException, authentication);
// If the parent AuthenticationManager was attempted and failed than it will publish an AbstractAuthenticationFailureEvent
// This check prevents a duplicate AbstractAuthenticationFailureEvent if the parent AuthenticationManager already published it
if (parentException == null) {
prepareException(lastException, authentication);
}
throw lastException;
}

View File

@ -16,18 +16,20 @@
package org.springframework.security.authentication;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.springframework.context.MessageSource;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.*;
/**
* Tests {@link ProviderManager}.
*
@ -257,7 +259,6 @@ public class ProviderManagerTests {
catch (BadCredentialsException e) {
assertThat(e).isSameAs(expected);
}
verify(publisher).publishAuthenticationFailure(expected, authReq);
}
@Test
@ -298,6 +299,32 @@ public class ProviderManagerTests {
}
}
// gh-6281
@Test
public void authenticateWhenFailsInParentAndPublishesThenChildDoesNotPublish() {
BadCredentialsException badCredentialsExParent = new BadCredentialsException("Bad Credentials in parent");
ProviderManager parentMgr = new ProviderManager(
Collections.singletonList(createProviderWhichThrows(badCredentialsExParent)));
ProviderManager childMgr = new ProviderManager(Collections.singletonList(createProviderWhichThrows(
new BadCredentialsException("Bad Credentials in child"))), parentMgr);
AuthenticationEventPublisher publisher = mock(AuthenticationEventPublisher.class);
parentMgr.setAuthenticationEventPublisher(publisher);
childMgr.setAuthenticationEventPublisher(publisher);
final Authentication authReq = mock(Authentication.class);
try {
childMgr.authenticate(authReq);
fail("Expected exception");
}
catch (BadCredentialsException e) {
assertThat(e).isSameAs(badCredentialsExParent);
}
verify(publisher).publishAuthenticationFailure(badCredentialsExParent, authReq); // Parent publishes
verifyNoMoreInteractions(publisher); // Child should not publish (duplicate event)
}
private AuthenticationProvider createProviderWhichThrows(
final AuthenticationException e) {
AuthenticationProvider provider = mock(AuthenticationProvider.class);