Exception handling thrown by Spring security oauth2 ExceptionTranslationFilter

Keywords: Java Spring REST Lombok

The core of Spring security is a set of filter chains. Project launch on autoconfig.

The core is the Basic Authentication Filter used to authenticate the user's identity;

One filter handles one authentication mode;

For the username password authentication filter,

  • Will check if it is a login request,
  • Whether to include username and password (that is, some authentication information required by the filter)
  • If not, release to next

The next information to determine whether it is necessary according to their own responsibilities,

Basic is characterized by Authorization:Basic eHh4Onh4 information in the request header

There may be more certified filters in the middle. The last step is the filter security interceptor,

It will be determined whether the request can access the rest Service Based on the configuration in BrowserSecurityConfig;

If rejected, a different exception will be thrown (depending on the reason).

Exception Translation Filter will catch the thrown errors, and then prompt the return of information according to different authentication methods

Note: the green filter can be configured to be effective or not, and other filters cannot be controlled;

The above is the basic principle of security. Other derivative functions are based on this shelf

How to handle exceptions thrown in the ExceptionTranslationFilter?

package com.healthy.security.server.handler;

import com.healthy.security.core.support.SimpleResponse;
import com.healthy.security.server.handler.exception.HealthyOauthException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestMethodNotSupportedException;

import java.io.IOException;
import java.nio.file.AccessDeniedException;

/**
 * healthy translator that converts exceptions into {@link OAuth2Exception}s. The output matches the OAuth 2.0
 * specification in terms of error response format and HTTP status code.
 */
@Slf4j
@Component("healthyResponseExceptionTranslator")
public class HealthyResponseExceptionTranslator implements WebResponseExceptionTranslator<SimpleResponse> {

    private ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();

    @Override
    public ResponseEntity<SimpleResponse> translate(Exception e) throws Exception {

        // Try to extract a SpringSecurityException from the stacktrace
        Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);

        // Exception stack get OAuth2Exception exception
        Exception exception = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain);


        // OAuth2Exception in exception stack
        if (exception != null) {
            return handleOAuth2Exception((OAuth2Exception) exception);
        }

        exception = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class,
                causeChain);

        if (exception != null) {
            return handleOAuth2Exception(new HealthyOauthException(e.getMessage(), e));
        }

        exception = (AccessDeniedException) throwableAnalyzer
                .getFirstThrowableOfType(AccessDeniedException.class, causeChain);
        if (exception instanceof AccessDeniedException) {
            return handleOAuth2Exception(new HealthyOauthException(exception.getMessage(), exception));
        }

        exception = (HttpRequestMethodNotSupportedException) throwableAnalyzer
                .getFirstThrowableOfType(HttpRequestMethodNotSupportedException.class, causeChain);
        if (exception instanceof HttpRequestMethodNotSupportedException) {
            return handleOAuth2Exception(new HealthyOauthException(exception.getMessage(), exception));
        }

        exception = (UsernameNotFoundException) throwableAnalyzer
                .getFirstThrowableOfType(UsernameNotFoundException.class, causeChain);
        if (exception instanceof UsernameNotFoundException) {
            return handleOAuth2Exception(new HealthyOauthException(exception.getMessage(), exception));
        }

        // Server internal error if the above exception is not included
        return handleOAuth2Exception(new HealthyOauthException(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), e));
    }

    private ResponseEntity<SimpleResponse> handleOAuth2Exception(OAuth2Exception e) throws IOException {

        int status = e.getHttpErrorCode();
        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) {
            headers.set("WWW-Authenticate", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary()));
        }

        SimpleResponse simpleResponse = new SimpleResponse(e.getMessage());

        return new ResponseEntity<SimpleResponse>(simpleResponse, headers, HttpStatus.valueOf(status));
    }
}
package com.healthy.security.server.handler.exception;

import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;

public class HealthyOauthException extends OAuth2Exception {

    public HealthyOauthException(String msg, Throwable t) {
        super(msg, t);
    }

    public HealthyOauthException(String msg) {
        super(msg);
    }
}
package com.healthy.security.server;

import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;

/**
 * Authentication server configuration
 */
@Configuration
@EnableAuthorizationServer
public class HealthyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    //  ... omission

    @Autowired
    private WebResponseExceptionTranslator healthyResponseExceptionTranslator;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .exceptionTranslator(healthyResponseExceptionTranslator);
        }
    
    //  ... omission
}

 

65 original articles published, 63 praised, 130000 visitors+
Private letter follow

Posted by sharpmac on Mon, 16 Mar 2020 04:37:29 -0700