'AuthenticationSuccessEvent never fired
I writing app where user logs in using facebook.
My security config/application class:
@SpringBootApplication
@EnableOAuth2Sso
@ComponentScan(basePackages = { "app" })
public class Application extends WebSecurityConfigurerAdapter {
@SuppressWarnings("SpringJavaAutowiringInspection")
@Autowired
private OAuth2ClientContext oauth2ClientContext;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/",
"/login**",
"/webjars/**",
"/bower_components/**",
"/assets/**",
"/app/**",
"/api/auth/isAuthenticated")
.permitAll()
.anyRequest()
.authenticated()
.and().formLogin().defaultSuccessUrl("/", true).loginPage("/login").permitAll()
.and().logout().logoutSuccessUrl("/").permitAll()
.and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
}
@Bean
@ConfigurationProperties("facebook")
ClientResources facebook() {
return new ClientResources();
}
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(facebook(), "/login/facebook"));
filter.setFilters(filters);
return filter;
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(path);
OAuth2RestTemplate facebookTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
filter.setRestTemplate(facebookTemplate);
filter.setTokenServices(new UserInfoTokenServices(client.getResource().getUserInfoUri(), client.getClient().getClientId()));
return filter;
}
class ClientResources {
private OAuth2ProtectedResourceDetails client = new AuthorizationCodeResourceDetails();
private ResourceServerProperties resource = new ResourceServerProperties();
public OAuth2ProtectedResourceDetails getClient() {
return client;
}
public ResourceServerProperties getResource() {
return resource;
}
}
My problem is that even that I configured listener:
package app;
@Component
public class AuthenticationListener implements ApplicationListener<AuthenticationSuccessEvent> {
@Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
System.out.println("Event fired");
}
}
it is never fired. I tried solution provided here : Spring boot OAuth successful login listener not triggering but it does not help either. SecurityContextHolder.getContext().getAuthentication().isAuthenticated()
returns true after logging in.
Solution 1:[1]
OAuth SSO support does not fire AuthenticationSuccessEvent
indeed. This is something I've been facing recently as well. This is implemented now but not released yet.
Solution 2:[2]
To publish authentication events it's possible to override authenticationHandler's.
basic security config:
@EnableWebFluxSecurity
public class SecurityConfig {
@Autowired
public ApplicationEventPublisher applicationEventPublisher;
@Bean
public AuthenticationEventPublisher authenticationEventPublisher() {
return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
}
@Bean
public ServerAuthenticationEntryPoint serverAuthenticationEntryPoint() {
return new HttpBasicServerAuthenticationEntryPoint();
}
@Bean
public LoggerListener loggerListener() {
return new LoggerListener();
}
@Bean
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
return http.authorizeExchange()
.anyExchange().authenticated()
.and()
.formLogin(login -> {
login.authenticationSuccessHandler(new LoggingAuthenticationSuccessHandler());
login.authenticationFailureHandler(new LoggingAuthenticaionFailedHandler(serverAuthenticationEntryPoint()));
})
.build();
}
}
success handler:
class LoggingAuthenticationSuccessHandler extends WebFilterChainServerAuthenticationSuccessHandler {
@Autowired
private AuthenticationEventPublisher eventPublisher;
@Override
public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
this.eventPublisher.publishAuthenticationSuccess(authentication);
return super.onAuthenticationSuccess(webFilterExchange,authentication);
}
}
failure handler:
class LoggingAuthenticaionFailureHandler extends ServerAuthenticationEntryPointFailureHandler {
@Autowired
private AuthenticationEventPublisher eventPublisher;
public LoggingAuthenticaionFailureHandler(ServerAuthenticationEntryPoint authenticationEntryPoint) {
super(authenticationEntryPoint);
}
@Override
public Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception) {
AnonymousAuthenticationToken token = new AnonymousAuthenticationToken("key", "anonymousUser",
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
this.eventPublisher.publishAuthenticationFailure(exception, token);
return super.onAuthenticationFailure(webFilterExchange, exception);
}
}
and event listener:
public class AuthenticationEvents {
private LoggerListener loggerListener;
@Autowired
public AuthenticationEvents(LoggerListener logger) {
this.loggerListener = logger;
}
@EventListener
public void onSuccess(InteractiveAuthenticationSuccessEvent success) {
loggerListener.onApplicationEvent(success);
}
@EventListener
public void onSuccess(AuthenticationSuccessEvent success) {
loggerListener.onApplicationEvent(success);
}
@EventListener
public void onFailure(AbstractAuthenticationFailureEvent failures) {
loggerListener.onApplicationEvent(failures);
}
}
The standard LoggerListener could be replaced with own implementation. Keep in mind, if Your security filter chain has UsernamePasswordAuthenticationFilter then overrides the success handler is not necessary.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Stephane Nicoll |
Solution 2 | cane |