Spring BadCredentials Event not firing

好久不见. 提交于 2021-02-07 11:49:13

问题


I want to log if a user tries to authenticate with wrong credentials. Therefore i have added this event listener class to my project:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.stereotype.Component;

@Component
public class AuthenticationFailureListener
        implements ApplicationListener<AuthenticationFailureBadCredentialsEvent>{

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
        System.out.println("test");
        logger.info("test2");
    }
}

Problem is it does not work at all. I use Spring Security default login page. The page shows "bad credentials" error when using wrong credentials, but my method above does not get called. I have very similar code for a success event listener, which works wonderfully:

@Component
public class AuthenticationSuccessListener implements
        ApplicationListener<InteractiveAuthenticationSuccessEvent> {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired private UserService users;

    @Override
    public void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
        User user = users.get(event.getAuthentication().getName());
        boolean isAdmin = user.getRole().equals(User.ROLE_ADMIN);
        logger.info((isAdmin ? "Admin" : "User") + " with id " + user.getIdLink()
                + " has successfully logged in!");
    }
}

Here is my Spring Security Java Configuration:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .formLogin()
                .and()
            .httpBasic();
    }
}

I have no clue whats going on here, help appreciated a lot!

Spring version: 4.0.9
Spring Security version: 3.2.5 (also tried 4.0.1)


Edit:

Okay, i set log level to DEBUG for Spring, but nothing. I searched for every occurance of "Listener" and the log states that instances of AuthenticationFailureListener as well as AuthenticationSuccessListeners have been created without any error.

I even put the log into diff tool (after replacing all times & censoring) and compared with a code version where FailureListener code is commented out, but didn't find something. You can search it yourself if you want to:
https://www.diffchecker.com/cwdn4sp4
On the bottom of the page you will find the plain log text on the left side.


Edit2: Partly Solved

Serges solution helped, here is my complete implementation of the onAuthenticationFailure method:

@Override
public void onAuthenticationFailure(
        HttpServletRequest request, HttpServletResponse response,
        AuthenticationException exception) throws IOException, ServletException {

    if (exception instanceof BadCredentialsException) {
        String name = request.getParameter("username");
        String password = request.getParameter("password");
        Authentication auth =
                new UsernamePasswordAuthenticationToken(name, password);
        eventPublisher.publishEvent(
                new AuthenticationFailureBadCredentialsEvent(auth, exception));
    }
    super.onAuthenticationFailure(request, response, exception);
}

回答1:


That is by design.

Javadoc for AbstractAuthenticationProcessingFilter is clear on that :

Event Publication :

If authentication is successful, an InteractiveAuthenticationSuccessEvent will be published via the application context. No events will be published if authentication was unsuccessful, because this would generally be recorded via an AuthenticationManager-specific application event.

(emphasize mine)

If you want to send explicitely an event for authentication failures, you could use a custom AuthenticationFailureHandler extending SimpleUrlAuthenticationFailureHandler that would send the event and call base class onAuthenticationFailure method.

public class EventSendingAuthenticationFailureHandler
        extends SimpleUrlAuthenticationFailureHandler,
        implements ApplicationEventPublisherAware {

    protected ApplicationEventPublisher eventPublisher;

    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    @Override
    void onAuthenticationFailure(javax.servlet.http.HttpServletRequest request,
                       javax.servlet.http.HttpServletResponse response,
                       AuthenticationException exception)
                         throws IOException,
                                javax.servlet.ServletException {
        // use eventPublisher to publish the event according to exception
        super.onAuthenticationFailure(request, response, exception);
    }
}

You should be able to configure it that way :

@Bean
AuthenticationFailureHandler eventAuthenticationFailureHandler() {
    return new EventSendingAuthenticationFailureHandler();
}

@Autowired
AuthenticationFailureHandler eventAuthenticationFailureHandler;

protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .formLogin().failureHandler(eventAuthenticationFailureHandler)
            .and()
        .httpBasic();
}



回答2:


I got this working in a different way.

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{

    // Inject applicationEventPublisher
    @Inject
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            // configure a auth event publisher
            .authenticationEventPublisher(new DefaultAuthenticationEventPublisher(applicationEventPublisher))
            .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .formLogin()
                .and()
            .httpBasic();
    }
}

With these changes, my event listener was able to receive auth failure events. This is with spring-security 4.0.2.RELEASE and spring-boot 1.2.5.RELEASE

Hope it helps.




回答3:


The LoggerListener works fine with Spring Security 3.2.8. See Grepcode for source code.

Your adpoted code:

@Named
public class AuthenticationSuccessListener implements ApplicationListener<AbstractAuthenticationEvent> {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Inject
    private UserService users;

    @Override
    public void onApplicationEvent(AbstractAuthenticationEvent event) {

        if (event instanceof InteractiveAuthenticationSuccessEvent) {

            User user = users.get(event.getAuthentication().getName());
            boolean isAdmin = user.getRole().equals(User.ROLE_ADMIN);
            logger.info((isAdmin ? "Admin" : "User") + " with id " + user.getIdLink() + " has successfully logged in!");
        }
    }
}


来源:https://stackoverflow.com/questions/30278293/spring-badcredentials-event-not-firing

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!