Justin Cranford
Justin Cranford

Reputation: 732

Spring Security Default Event workaround not working, I get "DefaultAuthenticationEventPublisher : No event was found for the exception MyException"

I have a custom MyAuthenticationProvider. It throws a custom MyException, which extends BadCredentialsException. It seems to work for success and failure authentication, but for failures it doesn't seem to trigger publishing an authentication failure event.

"DefaultAuthenticationEventPublisher : No event was found for the exception MyException"

I copy-and-pasted this code from Authentication Events - Default Event for triggering publication of unmapped exceptions, but it didn't work for me.

@Bean
public AuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    DefaultAuthenticationEventPublisher authenticationEventPublisher = new DefaultAuthenticationEventPublisher(applicationEventPublisher);
    authenticationEventPublisher.setDefaultAuthenticationFailureEvent(AbstractAuthenticationFailureEvent.class);
    return authenticationEventPublisher;
}

The "No event was found for the exception" log comes from DefaultAuthenticationEventPublisher.publishAuthenticationFailure, so I set a breakpoint. I walked through the method, and it seems like the constructor.newInstance(authentication, exception) silently fails.

    @Override
    public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
        Constructor<? extends AbstractAuthenticationEvent> constructor = getEventConstructor(exception);
        AbstractAuthenticationEvent event = null;
        if (constructor != null) {
            try {
                event = constructor.newInstance(authentication, exception);
            }
            catch (IllegalAccessException | InvocationTargetException | InstantiationException ignored) {
            }
        }
        if (event != null) {
            if (this.applicationEventPublisher != null) {
                this.applicationEventPublisher.publishEvent(event);
            }
        }
        else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("No event was found for the exception " + exception.getClass().getName());
            }
        }
    }

The constructor call failed because the docs told me to use is AbstractAuthenticationFailureEvent. Furthermore, the catch ignores the exception.

To test my theory, I changed the workaround from the doc to use a concrete class instead of AbstractAuthenticationFailureEvent. That worked, because my unmapped exception triggered publishing a failure event now.

@Bean
public AuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    DefaultAuthenticationEventPublisher authenticationEventPublisher = new DefaultAuthenticationEventPublisher(applicationEventPublisher);
    authenticationEventPublisher.setDefaultAuthenticationFailureEvent(UnmappedAuthenticationFailureEvent .class);
    return authenticationEventPublisher;
}

public static class UnmappedAuthenticationFailureEvent extends AbstractAuthenticationFailureEvent {
    public UnmappedAuthenticationFailureEvent(Authentication authentication, AuthenticationException exception) {
        super(authentication, exception);
    }
}

Questions:

  1. Is the Authentication Events - Default Event doc wrong to suggest using the AbstractAuthenticationFailureEvent parent class?
  2. Is the code wrong to ignore the reflection exceptions?

I think the answer to both is yes. If you agree, could you:

  1. Please fix the doc to recommend using a concrete class that extends AbstractAuthenticationFailureEvent, instead of trying to use AbstractAuthenticationFailureEvent directly.
  2. Please add a TRACE or DEBUG diagnostic log to the publishAuthenticationFailure catch.

Thank you.

P.S. I think a diagnostic log would be especially helpful. It was frustrating and time consuming trying to figure out why the official solution from the docs did not work. P.P.S I would also like to point out that searching for workarounds in Stack Exchange, search engines, and AI chatbots did not help. A diagnostic log would be more effective.

Upvotes: 0

Views: 42

Answers (0)

Related Questions