Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use custom exceptions in Spring Security

I have created a custom AuthenticationProvider to perform custom security checks. I have also created custom exceptions that inherit from AccountStatusException to notify user status problems such as when the user has not verified his account for an specific period of time.My UserDetails is also acustom implementation.

Here is the code for the security checks I perform. Code that is irrelevant to the case has been omitted.

public class SsoAuthenticationProvider implements AuthenticationProvider {

    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = (String) authentication.getPrincipal();
        User user = null;
        if (username != null) {
            user = getUserRepository().findByUserName(username);
            if (user != null) {
                if (user.getEnabled() != 0) {
                    if ((user.getUserDetail().getConfirmed() != 0)
                            || ((new Date().getTime() - user.getUserDetail().getRequestDate().getTime()) / (1000 * 60 * 60 * 24)) <= getUnconfirmedDays()) {
                        if (getPasswordEncoder().isPasswordValid(user.getPassword(),
                                (String) authentication.getCredentials(), user)) {
                            user.authenticated = true;
                            user.getAuthorities();
                        }
                    } else {
                        throw new UserNotConfirmedAndTimeExceeded(
                                "User has not been cofirmed in the established time period");
                    }
                } else {
                    throw new DisabledException("User is disabled");
                }
            } else {
                throw new BadCredentialsException("User or password incorrect");
            }
        } else {
            throw new AuthenticationCredentialsNotFoundException("No credentials found in context");
        }
        return user;
    }
}

The SsoAuthenticationProvider checks:

  1. That the username is registered (exists in the db)
  2. That the user has confirmed his email
  3. If the user has not confirmed his email, check that he is still in the grace period (this is a few days we give users to confirm their email while letting them access the site)
  4. If the user has not confirmed email and he is not in the grace period, throw security exception to signal these status and reject authentication

The problem is that not all of these exceptions are thrown up the stack up to the controller so it seems impossible to inform the user about the login problem.

Using UserDetails methods such as isEnabled() (and similar) is not a possibility as the semantics of our different user account statuses are completely different.

Is this the right approach to build custom security with custom exceptions? Should i implement sth else to make this work?

like image 813
Daniel Cerecedo Avatar asked Aug 20 '12 09:08

Daniel Cerecedo


People also ask

How do you handle a custom exception in spring boot?

The @ExceptionHandler is an annotation used to handle the specific exceptions and sending the custom responses to the client. Define a class that extends the RuntimeException class. You can define the @ExceptionHandler method to handle the exceptions as shown.

How do you handle exceptions in spring?

Spring MVC provides exception handling for your web application to make sure you are sending your own exception page instead of the server-generated exception to the user. The @ExceptionHandler annotation is used to detect certain runtime exceptions and send responses according to the exception.

How does Spring MVC handle custom exceptions?

Spring MVC Framework provides following ways to help us achieving robust exception handling. Controller Based - We can define exception handler methods in our controller classes. All we need is to annotate these methods with @ExceptionHandler annotation. This annotation takes Exception class as argument.

Can we handle exceptions in spring boot?

Exception Handling in Spring Boot helps to deal with errors and exceptions present in APIs so as to deliver a robust enterprise application. This article covers various ways in which exceptions can be handled in a Spring Boot Project. Let's do the initial setup to explore each approach in more depth.


2 Answers

To close the previously asked question let me explain what we did. As I commented to previous responses, using provided methods in UserDetails objectis not feasible as you cannot capture all the login failure semantics with the given methods. In our case these semantics are still very limited but in other cases it could indfinitely extend over time to express different user situations. The exception approach was finally the best one. The final code looks like this

    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String username=(String)authentication.getPrincipal();
    User user=null;
    if(username!=null){
        user=getUserRepository().findByUserName(username);
        if(user!=null){
            if(user.getEnabled()!=0){
                if((user.getUserDetail().getConfirmed()!=0)||((new Date().getTime()-user.getUserDetail().getRequestDate().getTime())/(1000 * 60 * 60 * 24))<=getUnconfirmedDays()){
                    if(getPasswordEncoder().isPasswordValid(user.getPassword(), (String)authentication.getCredentials(), user)){
                        user.authenticated=true;
                        user.getAuthorities();
                    } else {
                        throw new BadCredentialsException("Password incorrect");
                    }
                }else{
                    throw new UserNotConfirmedAndTimeExceeded("User has not been cofirmed in the established time period");         
                }
            }else{
                throw new DisabledException("User is disabled");
            }
        }else{
            throw new BadCredentialsException("User does not exist");
        }
    }else{
        throw new AuthenticationCredentialsNotFoundException("No credentials found in context");
    }
    return user;
}

All exceptions are part of the spring security exception stack. This is, those custom exceptions inherit from some existing exception. Then, in your security controller you should check for security exceptions and treat them as desired. For example redirecting to different pages.

Hope this helps!

like image 51
Daniel Cerecedo Avatar answered Sep 20 '22 14:09

Daniel Cerecedo


i think its better to use other method/properties of user detail object for this purpose. like

isAccountNonExpired() 
isAccountNonLocked() 
isEnabled() 

and if you want to display custom error message then use message properties as explained in this article

like image 42
Jigar Parekh Avatar answered Sep 23 '22 14:09

Jigar Parekh