Login component display different error message, check for expired account

Login component, checks for “error” parameter and displays an error message if user is not authenticated. However, I am throwing AccountExpiredException in a custom UserDetailsService if authenticated user account is expired by checking expiration date in database. So, I want to display a message that account is expired on login page. Tried redirecting UI to “/login?expired” so that I can display custom error message with:
if (beforeEnterEvent.getLocation()
.getQueryParameters()
.getParameters()
.containsKey(“expired”)) {
login.showErrorMessage(“expired”, “expired account”);
}

But does not work. How can I change the default error message on login component depending on user account status like
1- username or e-mail not found (this is already working by default)
2- username and password is correct but account expired (by checking db)
3- username and password is correct but account is disabled in db

Thank you.

what exactly does not work? Redirecting? Your if or showing an error message?

In my userdetails class throw new AccountExpiredException(“expired”) if account expired. then try to catch it with a AuthenticationFailureHandler.

if (exception.getMessage().equals("expired")) {
            response.sendRedirect("/login/?expired");
 }

This works and redirects, then in login view

if (beforeEnterEvent.getLocation()
                .getQueryParameters()
                .getParameters()
                .containsKey("expired")) {
            login.showErrorMessage("expired", "expired account");
}

This works, with following in the SecurityConfig

http.formLogin(formLogin -> formLogin
                .failureUrl("/login?error")
                .loginPage("/login")
                .failureHandler(new CustomAuthenticationFailureHandler())  
                .permitAll());

BUT this time, normal login failure (incorrect password, or email) stops working.

Basically, I want to give more information to users after authentication successful. A user account may be expired, or disabled, when user enters username/password, he/she should be given information about the account status.

Since I cannot handle expired, and disabled cases on login window directly, I added following to MainLayout class so that if user account is expired, it displays a simple dialog to give information, and logout user when closed.

@Override
    protected void afterNavigation() {
        super.afterNavigation();

        Dialog d = new Dialog();
        H4 h4 = new H4("expired " + userInformation.getEmail());
        d.add(h4);
        d.open();
        d.addDialogCloseActionListener((t) -> {
            securityService.logout();
        });
    }

Is there any good way to implement this?

Sounds like your failureHandler does not cover those cases correctly.

Your other idea with the main layout could also work… even tho I think that the main layout might be not the best place. Sounds like a good candidate for a dedicated BeforeEnterHandler which can be registered on the UI

Thank you, following solves the problem the last “else” blocks handles incorrect user/password.

One last thing, when user/password incorrect, it redirects to /login?error and no runtime exception printed on system.out.
When it is AccountExpiredException and DisabledException, it redirects to correct /login?expired and /login?disabled BUT it also prints exception stacktrace on system.out. How can I catch that exception to prevent system.out printing.

http.formLogin(formLogin -> formLogin.failureHandler((request, response, exception) -> {
            if (exception.getMessage().equals("expired")) {
                response.sendRedirect("/login/?expired");
            } else if (exception.getMessage().equals("disabled")) {
                response.sendRedirect("/login/?disabled");
            } else {
                response.sendRedirect("/login/?error");
            }
        }));

Hard to say with the amount of information given. If you are 100% sure that it’s System.out - it’s your code doing it; neither Spring or Vaadin would ever use System.out. If it’s a Logging Statement… you need to find the place that prints it… might be a default spring security feature for failed logins with exceptions that differ from the “default” errors thrown to ensure they are seen - normally those features can be configured if you identify its origin