Issue
I implement a brute force prevent mechanism as for my Login service as shown below by inspiring Baeldung's Prevent Brute Force Authentication Attempts with Spring Security page:
@Service
@RequiredArgsConstructor
public class LoginServiceImpl implements LoginService {
private final UserService userService;
private final LoginAttemptService loginAttemptService;
public UserTokenDTO login(final LoginRequest request) {
if(!user.isValid) {
throw new InvalidCredentialsException();
}
// code omitted for brevity
}
}
When a user is not validated, LoginService
throws InvalidCredentialsException()
and then I am trying to catch this exception in AuthenticationFailureListener
class:
@Component
public class AuthenticationFailureListener implements
ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
@Autowired
private HttpServletRequest request;
@Autowired
private LoginAttemptService loginAttemptService;
@Override
public void onApplicationEvent(final AuthenticationFailureBadCredentialsEvent e) {
final String xfHeader = request.getHeader("X-Forwarded-For");
if (xfHeader == null) {
loginAttemptService.loginFailed(request.getRemoteAddr());
} else {
loginAttemptService.loginFailed(xfHeader.split(",")[0]);
}
}
}
When there is an error, then loginAttemptService.loginFailed()
method will be called. However, I cannot catch the exception in my onApplicationEvent()
. I have tried using different event types, but for some event e.g. ApplicationEvent
it is triggered on each event and I should fire it only when the user is not authenticated when InvalidCredentialsException
is thrown.
After making a search, I have seen that I need to make a config so that Spring Security catch these event on failure or success. But the definitions is not clear and I thought that maybe I can catch the event by using the correct event type in my AuthenticationFailureListener
class. I also have an event Handler class, but I am not sure if it helps anything.
Update: Here is my SecurityConfig
. I still cannot fire AuthenticationFailureBadCredentialsEvent
and cannot get any exception onApplicationEvent
.
@EnableWebSecurity
@AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
AuthenticationFailureHandler eventAuthenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
private final AuthenticationFailureHandler eventAuthenticationFailureHandler;
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.formLogin().failureHandler(eventAuthenticationFailureHandler)
.and()
.httpBasic();
}
}
Solution
As wrote in this answer:
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.
Answered By - xTheDoctah