Background:
In my project, I needed to have two factor authentication (by sending OTP to registered email) which I implemented by extending DaoAuthenticationProvider
.
In order to identify reason of why OTP authentication has failed, my custom authentication provider throws new custom exceptions for example BadOtpException
, ExpiredOtpException
, ConsumedOtpException
. All these exceptions are subclasses of BadCredentialsException
. This authentication flow is working fine.
Issue:
The Authentication events that were earlier getting published while I was using DaoAuthenticationProvider
are now not getting published with my custom authentication provider.
Cause:
Upon some troubleshooting I figured out that Grails Spring Security Core plugin uses DefaultAuthenticationEventPublisher
to publish the events. And this class publishes events on the basis of exception mappings which contain exception name vs event name to resolve the event that needs to be published whenever exception occurs. And these mappings are configured in its constructor.
Since mappings of my custom exceptions are not present in this constructor, the authentication failure events are not getting published.
Tried Solution:
I tried overriding DefaultAuthenticationEventPublisher
and added new exception mappings by invoking super.setAdditionalExceptionMappings()
. Here is the custom event publisher:
class CustomAuthenticationEventPublisher extends DefaultAuthenticationEventPublisher {
CustomAuthenticationEventPublisher() {
}
CustomAuthenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
super(applicationEventPublisher)
println('CustomAuthenticationEventPublisher')
Properties exceptionMappings = new Properties()
exceptionMappings.setProperty(BadOtpException.class.name, AuthenticationFailureBadCredentialsEvent.class.name)
super.setAdditionalExceptionMappings(exceptionMappings)
}
}
In resources.groovy, I registered my custom event publisher using following:
beans = {
authenticationEventPublisher(CustomAuthenticationEventPublisher)
}
But above solution is not working. Even the println()
statement in the constructor is not getting logged. Seems like the bean is not getting registered.
Am I doing anything wrong in the above solution?
Is there any other way I can override the exception mappings?