Forráskód Böngészése

AuthenticationFailureEvent should publish once

Fixes gh-6281
Joe Grandja 6 éve
szülő
commit
be23ab8114

+ 7 - 2
core/src/main/java/org/springframework/security/authentication/ProviderManager.java

@@ -156,6 +156,7 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
 			throws AuthenticationException {
 			throws AuthenticationException {
 		Class<? extends Authentication> toTest = authentication.getClass();
 		Class<? extends Authentication> toTest = authentication.getClass();
 		AuthenticationException lastException = null;
 		AuthenticationException lastException = null;
+		AuthenticationException parentException = null;
 		Authentication result = null;
 		Authentication result = null;
 		Authentication parentResult = null;
 		Authentication parentResult = null;
 		boolean debug = logger.isDebugEnabled();
 		boolean debug = logger.isDebugEnabled();
@@ -205,7 +206,7 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
 				// handled the request
 				// handled the request
 			}
 			}
 			catch (AuthenticationException e) {
 			catch (AuthenticationException e) {
-				lastException = e;
+				lastException = parentException = e;
 			}
 			}
 		}
 		}
 
 
@@ -234,7 +235,11 @@ public class ProviderManager implements AuthenticationManager, MessageSourceAwar
 					"No AuthenticationProvider found for {0}"));
 					"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;
 		throw lastException;
 	}
 	}

+ 34 - 7
core/src/test/java/org/springframework/security/authentication/ProviderManagerTests.java

@@ -16,17 +16,19 @@
 
 
 package org.springframework.security.authentication;
 package org.springframework.security.authentication;
 
 
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.Mockito.*;
+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.ArrayList;
 import java.util.Arrays;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 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 static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+import static org.mockito.Mockito.*;
 
 
 /**
 /**
  * Tests {@link ProviderManager}.
  * Tests {@link ProviderManager}.
@@ -257,7 +259,6 @@ public class ProviderManagerTests {
 		catch (BadCredentialsException e) {
 		catch (BadCredentialsException e) {
 			assertThat(e).isSameAs(expected);
 			assertThat(e).isSameAs(expected);
 		}
 		}
-		verify(publisher).publishAuthenticationFailure(expected, authReq);
 	}
 	}
 
 
 	@Test
 	@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(
 	private AuthenticationProvider createProviderWhichThrows(
 			final AuthenticationException e) {
 			final AuthenticationException e) {
 		AuthenticationProvider provider = mock(AuthenticationProvider.class);
 		AuthenticationProvider provider = mock(AuthenticationProvider.class);