浏览代码

DefaultAuthenticationEventPublisher Default Event

Fixes gh-7825
Zeeshan Adnan 5 年之前
父节点
当前提交
51b9b2f693

+ 28 - 0
core/src/main/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisher.java

@@ -64,6 +64,7 @@ public class DefaultAuthenticationEventPublisher implements AuthenticationEventP
 
 	private ApplicationEventPublisher applicationEventPublisher;
 	private final HashMap<String, Constructor<? extends AbstractAuthenticationEvent>> exceptionMappings = new HashMap<>();
+	private Constructor<? extends AbstractAuthenticationFailureEvent> defaultAuthenticationFailureEventConstructor;
 
 	public DefaultAuthenticationEventPublisher() {
 		this(null);
@@ -117,6 +118,13 @@ public class DefaultAuthenticationEventPublisher implements AuthenticationEventP
 			catch (IllegalAccessException | InvocationTargetException | InstantiationException ignored) {
 			}
 		}
+		else if (defaultAuthenticationFailureEventConstructor != null) {
+			try {
+				event = defaultAuthenticationFailureEventConstructor.newInstance(authentication, exception);
+			}
+			catch (IllegalAccessException | InvocationTargetException | InstantiationException ignored) {
+			}
+		}
 
 		if (event != null) {
 			if (applicationEventPublisher != null) {
@@ -163,6 +171,26 @@ public class DefaultAuthenticationEventPublisher implements AuthenticationEventP
 		}
 	}
 
+	/**
+	 * Sets a default authentication failure event as a fallback event for any unmapped
+	 * exceptions not mapped in the exception mappings.
+	 *
+	 * @param defaultAuthenticationFailureEventClass is the authentication failure event class
+	 * to be fired for unmapped exceptions.
+	 */
+	public void setDefaultAuthenticationFailureEvent(
+			Class<? extends AbstractAuthenticationFailureEvent> defaultAuthenticationFailureEventClass) {
+		Assert.notNull(defaultAuthenticationFailureEventClass,
+				"The defaultAuthenticationFailureEventClass must not be null");
+		try {
+			this.defaultAuthenticationFailureEventConstructor = defaultAuthenticationFailureEventClass
+					.getConstructor(Authentication.class, AuthenticationException.class);
+		} catch (NoSuchMethodException e) {
+			throw new RuntimeException("Default Authentication Failure event class "
+					+ defaultAuthenticationFailureEventClass.getName() + " has no suitable constructor");
+		}
+	}
+
 	private void addMapping(String exceptionClass,
 			Class<? extends AbstractAuthenticationFailureEvent> eventClass) {
 		try {

+ 32 - 0
core/src/test/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisherTests.java

@@ -27,6 +27,7 @@ import org.springframework.security.authentication.event.AuthenticationFailureLo
 import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
 import org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent;
 import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
+import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
@@ -137,6 +138,37 @@ public class DefaultAuthenticationEventPublisherTests {
 		verifyZeroInteractions(appPublisher);
 	}
 
+	@Test(expected = IllegalArgumentException.class)
+	public void defaultAuthenticationFailureEventClassSetNullThen() {
+		publisher = new DefaultAuthenticationEventPublisher();
+		publisher.setDefaultAuthenticationFailureEvent(null);
+	}
+
+	@Test
+	public void defaultAuthenticationFailureEventIsPublished() {
+		publisher = new DefaultAuthenticationEventPublisher();
+		publisher.setDefaultAuthenticationFailureEvent(AuthenticationFailureBadCredentialsEvent.class);
+		ApplicationEventPublisher appPublisher = mock(ApplicationEventPublisher.class);
+
+		publisher.setApplicationEventPublisher(appPublisher);
+		publisher.publishAuthenticationFailure(new AuthenticationException("") {
+		}, mock(Authentication.class));
+		verify(appPublisher).publishEvent(isA(AuthenticationFailureBadCredentialsEvent.class));
+	}
+
+	@Test(expected = RuntimeException.class)
+	public void defaultAuthenticationFailureEventMissingAppropriateConstructorThen() {
+		publisher = new DefaultAuthenticationEventPublisher();
+		publisher.setDefaultAuthenticationFailureEvent(AuthenticationFailureEventWithoutAppropriateConstructor.class);
+	}
+
+	private static final class AuthenticationFailureEventWithoutAppropriateConstructor extends
+			AbstractAuthenticationFailureEvent {
+		AuthenticationFailureEventWithoutAppropriateConstructor(Authentication auth) {
+			super(auth, new AuthenticationException("") {});
+		}
+	}
+
 	private static final class MockAuthenticationException extends
 			AuthenticationException {
 		MockAuthenticationException(String msg) {