Skip to content

Commit 7ccc489

Browse files
committed
Option for default event in DefaultAuthenticationEventPublisher
Fixes gh-7825
1 parent ee6df17 commit 7ccc489

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

core/src/main/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisher.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public class DefaultAuthenticationEventPublisher implements AuthenticationEventP
6464

6565
private ApplicationEventPublisher applicationEventPublisher;
6666
private final HashMap<String, Constructor<? extends AbstractAuthenticationEvent>> exceptionMappings = new HashMap<>();
67+
private Constructor<? extends AbstractAuthenticationFailureEvent> defaultAuthenticationFailureEventConstructor;
6768

6869
public DefaultAuthenticationEventPublisher() {
6970
this(null);
@@ -114,6 +115,13 @@ public void publishAuthenticationFailure(AuthenticationException exception,
114115
catch (IllegalAccessException | InvocationTargetException | InstantiationException ignored) {
115116
}
116117
}
118+
else if (defaultAuthenticationFailureEventConstructor != null) {
119+
try {
120+
event = defaultAuthenticationFailureEventConstructor.newInstance(authentication, exception);
121+
}
122+
catch (IllegalAccessException | InvocationTargetException | InstantiationException ignored) {
123+
}
124+
}
117125

118126
if (event != null) {
119127
if (applicationEventPublisher != null) {
@@ -160,6 +168,26 @@ public void setAdditionalExceptionMappings(Properties additionalExceptionMapping
160168
}
161169
}
162170

171+
/**
172+
* Sets a default authentication failure event as a fallback event for any unmapped
173+
* exceptions not mapped in the exception mappings.
174+
*
175+
* @param defaultAuthenticationFailureEventClass is the authentication failure event class
176+
* to be fired for unmapped exceptions.
177+
*/
178+
public void setDefaultAuthenticationFailureEvent(
179+
Class<? extends AbstractAuthenticationFailureEvent> defaultAuthenticationFailureEventClass) {
180+
Assert.notNull(defaultAuthenticationFailureEventClass,
181+
"The defaultAuthenticationFailureEventClass must not be null");
182+
try {
183+
this.defaultAuthenticationFailureEventConstructor = defaultAuthenticationFailureEventClass
184+
.getConstructor(Authentication.class, AuthenticationException.class);
185+
} catch (NoSuchMethodException e) {
186+
throw new RuntimeException("Default Authentication Failure event class "
187+
+ defaultAuthenticationFailureEventClass.getName() + " has no suitable constructor");
188+
}
189+
}
190+
163191
private void addMapping(String exceptionClass,
164192
Class<? extends AbstractAuthenticationFailureEvent> eventClass) {
165193
try {

core/src/test/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisherTests.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
2828
import org.springframework.security.authentication.event.AuthenticationFailureServiceExceptionEvent;
2929
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
30+
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
3031
import org.springframework.security.core.Authentication;
3132
import org.springframework.security.core.AuthenticationException;
3233
import org.springframework.security.core.userdetails.UsernameNotFoundException;
@@ -137,6 +138,37 @@ public void unknownFailureExceptionIsIgnored() {
137138
verifyZeroInteractions(appPublisher);
138139
}
139140

141+
@Test(expected = IllegalArgumentException.class)
142+
public void defaultAuthenticationFailureEventClassSetNullThen() {
143+
publisher = new DefaultAuthenticationEventPublisher();
144+
publisher.setDefaultAuthenticationFailureEvent(null);
145+
}
146+
147+
@Test
148+
public void defaultAuthenticationFailureEventIsPublished() {
149+
publisher = new DefaultAuthenticationEventPublisher();
150+
publisher.setDefaultAuthenticationFailureEvent(AuthenticationFailureBadCredentialsEvent.class);
151+
ApplicationEventPublisher appPublisher = mock(ApplicationEventPublisher.class);
152+
153+
publisher.setApplicationEventPublisher(appPublisher);
154+
publisher.publishAuthenticationFailure(new AuthenticationException("") {
155+
}, mock(Authentication.class));
156+
verify(appPublisher).publishEvent(isA(AuthenticationFailureBadCredentialsEvent.class));
157+
}
158+
159+
@Test(expected = RuntimeException.class)
160+
public void defaultAuthenticationFailureEventMissingAppropriateConstructorThen() {
161+
publisher = new DefaultAuthenticationEventPublisher();
162+
publisher.setDefaultAuthenticationFailureEvent(AuthenticationFailureEventWithoutAppropriateConstructor.class);
163+
}
164+
165+
private static final class AuthenticationFailureEventWithoutAppropriateConstructor extends
166+
AbstractAuthenticationFailureEvent {
167+
AuthenticationFailureEventWithoutAppropriateConstructor(Authentication auth) {
168+
super(auth, new AuthenticationException("") {});
169+
}
170+
}
171+
140172
private static final class MockAuthenticationException extends
141173
AuthenticationException {
142174
MockAuthenticationException(String msg) {

0 commit comments

Comments
 (0)