Subclasses of AbstractAuthenticationEvent are not fired anymore
See original GitHub issueGiven the following application
import java.security.Principal;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@Configuration
@RestController
public class AuthlistenerApplication {
    @GetMapping("/")
    public String hello(final Principal principal) {
        return "Hello, " + principal.getName() + ".";
    }
    @Bean
    public ApplicationListener<AuthenticationSuccessEvent> onSuccessListener() {
        return (AuthenticationSuccessEvent event) -> {
            System.out.println("Yeah!");
        };
    }
    @Bean
    public ApplicationListener<AuthenticationFailureBadCredentialsEvent> onBadCredentialsListener() {
        return (AuthenticationFailureBadCredentialsEvent event) -> {
            System.out.println("Oh no...");
        };
    }
    public static void main(String[] args) {
        SpringApplication.run(AuthlistenerApplication.class, args);
    }
}
Running this on Spring Boot 1.5.9.RELEASE triggers either AuthenticationSuccessEvent or an AuthenticationFailureBadCredentialsEvent event, depending if one uses the correct password.
Neither of those events are triggered on 2.0.0.BUILD-SNAPSHOT and probably not on the Milestone as well. Here’s a test to confirm this:
import java.util.Base64;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
@TestPropertySource(properties = {
    "security.user.name = testuser",
    "security.user.password = testpassword",
    "spring.security.user.name = testuser",
    "spring.security.user.password = testpassword",})
public class AuthlistenerApplicationTests {
    @Rule
    public OutputCapture output = new OutputCapture();
    @Autowired
    TestRestTemplate restTemplate;
    @Test
    public void logsSuccess() throws Exception {
        final HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Basic " + Base64.getEncoder().encodeToString("testuser:testpassword".getBytes()));
        headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
        final ResponseEntity<String> r = restTemplate
                .exchange("/", HttpMethod.GET, new HttpEntity<>(headers), String.class);
        assertThat(r.getStatusCode(), is(equalTo(HttpStatus.OK)));
        assertThat(r.getBody(), is(equalTo("Hello, testuser.")));
        assertThat("Output did not contain 'Yeah!'", output.toString(), containsString("Yeah!"));
    }
    @Test
    public void logsFailure() throws Exception {
        final HttpHeaders headers = new HttpHeaders();
        headers.add("Authorization", "Basic " + Base64.getEncoder().encodeToString("testuser:fump".getBytes()));
        headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
        final ResponseEntity<String> r = restTemplate
                .exchange("/", HttpMethod.GET, new HttpEntity<>(headers), String.class);        
        assertThat(r.getStatusCode(), is(equalTo(HttpStatus.UNAUTHORIZED)));
        assertThat("Output did not contain 'Oh no...'", output.toString(), containsString("Oh no..."));        
    }
}
I used the snapshot for the test as the test makes use of the new old properties to configure the user (see #10963).
I already checked if the DefaultAuthenticationEventPublisher is still part of SecurityAutoConfiguration and yes, it is. So I assume that those events should still be published.
Issue Analytics
- State:
 - Created 6 years ago
 - Comments:15 (10 by maintainers)
 
Top Results From Across the Web
spring - @EventListener for AuthenticationSuccessEvent or ...
When I authenticate correctly in the application, no event is released by Spring Security and therefore this Event Listener is not called.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

@michael-simons Spring Security will provide a hook to register a bean of type
AuthenticationEventPublisher. If it finds a bean of that type, it will use that as the default publisher. This is consistent with the approach of registering aUserDetailsServicebean (orPasswordEncoder,AuthenticationProvider), which gets picked up by Spring Security.@mctdi remove extends WebSecurityConfigurerAdapter in your MultiHttpSecurityConfig class and copy your protected void configure(AuthenticationManagerBuilder auth) implementation in RestWebSecurityConfigurationAdapter and FormLoginWebSecurityConfigurerAdapter