diff --git a/core/src/main/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisher.java b/core/src/main/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisher.java index a2df060abf1..965a6ee2a95 100644 --- a/core/src/main/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisher.java +++ b/core/src/main/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisher.java @@ -149,7 +149,10 @@ public void setApplicationEventPublisher( * @param additionalExceptionMappings where keys are the fully-qualified string name * of the exception class and the values are the fully-qualified string name of the * event class to fire. + * + * @deprecated use {@link #setAdditionalExceptionMappings(Map)} */ + @Deprecated @SuppressWarnings({ "unchecked" }) public void setAdditionalExceptionMappings(Properties additionalExceptionMappings) { Assert.notNull(additionalExceptionMappings, @@ -169,6 +172,26 @@ public void setAdditionalExceptionMappings(Properties additionalExceptionMapping } } + /** + * Sets additional exception to event mappings. These are automatically merged with + * the default exception to event mappings that ProviderManager defines. + * + * @param mappings where keys are exception classes and values are event classes. + * @since 5.3 + */ + public void setAdditionalExceptionMappings(Map, + Class> mappings){ + Assert.notEmpty(mappings, "The mappings Map must not be empty nor null"); + for (Map.Entry, Class> entry + : mappings.entrySet()) { + Class exceptionClass = entry.getKey(); + Class eventClass = entry.getValue(); + Assert.notNull(exceptionClass, "exceptionClass cannot be null"); + Assert.notNull(eventClass, "eventClass cannot be null"); + addMapping(exceptionClass.getName(), (Class) eventClass); + } + } + /** * Sets a default authentication failure event as a fallback event for any unmapped * exceptions not mapped in the exception mappings. diff --git a/core/src/test/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisherTests.java b/core/src/test/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisherTests.java index 4750ee51496..9c0c14993e3 100644 --- a/core/src/test/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisherTests.java +++ b/core/src/test/java/org/springframework/security/authentication/DefaultAuthenticationEventPublisherTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import org.junit.*; import org.springframework.context.ApplicationEventPublisher; +import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent; import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent; import org.springframework.security.authentication.event.AuthenticationFailureCredentialsExpiredEvent; import org.springframework.security.authentication.event.AuthenticationFailureDisabledEvent; @@ -138,6 +139,47 @@ public void unknownFailureExceptionIsIgnored() { verifyZeroInteractions(appPublisher); } + @Test(expected = IllegalArgumentException.class) + public void emptyMapCausesException() { + Map, + Class> mappings = new HashMap<>(); + publisher = new DefaultAuthenticationEventPublisher(); + publisher.setAdditionalExceptionMappings(mappings); + } + + @Test(expected = IllegalArgumentException.class) + public void missingExceptionClassCausesException() { + Map, + Class> mappings = new HashMap<>(); + mappings.put(null, AuthenticationFailureLockedEvent.class); + publisher = new DefaultAuthenticationEventPublisher(); + publisher.setAdditionalExceptionMappings(mappings); + } + + @Test(expected = IllegalArgumentException.class) + public void missingEventClassAsMapValueCausesException() { + Map, + Class> mappings = new HashMap<>(); + mappings.put(LockedException.class, null); + publisher = new DefaultAuthenticationEventPublisher(); + publisher.setAdditionalExceptionMappings(mappings); + } + + @Test + public void additionalExceptionMappingsUsingMapAreSupported() { + publisher = new DefaultAuthenticationEventPublisher(); + Map, + Class> mappings = new HashMap<>(); + mappings.put(MockAuthenticationException.class,AuthenticationFailureDisabledEvent.class); + publisher.setAdditionalExceptionMappings(mappings); + ApplicationEventPublisher appPublisher = mock(ApplicationEventPublisher.class); + + publisher.setApplicationEventPublisher(appPublisher); + publisher.publishAuthenticationFailure(new MockAuthenticationException("test"), + mock(Authentication.class)); + verify(appPublisher).publishEvent(isA(AuthenticationFailureDisabledEvent.class)); + } + @Test(expected = IllegalArgumentException.class) public void defaultAuthenticationFailureEventClassSetNullThen() { publisher = new DefaultAuthenticationEventPublisher();