3

I have an authentication provider, that throwing my custom exception. This provider validating token on every request to controllers. Exceptions in controllers handling by controller advice, but provider works before controller, so controller advice cant handle exceptions that provider throws. How can i handle exception from provider?

Provider

@Component
@RequiredArgsConstructor
public class BearerTokenAuthenticationProvider implements AuthenticationProvider {

private final Wso2TokenVerificationClient client;

@Override
public Authentication authenticate( Authentication authentication ) {
    BearerTokenAuthenticationToken token = (BearerTokenAuthenticationToken) authentication;
    Map<String, String> requestBody = new HashMap<>();
    requestBody.put( "token", token.getToken() );
    Wso2TokenValidationResponse tokenValidationResponse = client.introspectToken( requestBody );
    if( !Boolean.parseBoolean( tokenValidationResponse.getActive() ) ) {
        throw new AuthenticationException(
            "Token not valid", HttpStatus.UNAUTHORIZED
        );
    }
    DecodedJWT jwt = JWT.decode(token.getToken());
    UserDetails details = new UserDetails();
    details.setId( Long.parseLong(jwt.getClaim( OidcUserClaims.USER_ID ).asString()) );
    details.setEmail( jwt.getClaim( OidcUserClaims.EMAIL ).asString() );
    token.setDetails( details );
    return token;
}

@Override
public boolean supports( Class<?> aClass ) {
    return BearerTokenAuthenticationToken.class.equals( aClass );
}

Security Config

@Configuration
@RequiredArgsConstructor
public class CommonWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

private final BearerTokenAuthenticationProvider bearerTokenProvider;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.headers().contentSecurityPolicy("script-src 'self'");
    http
            .csrf().disable()
            .authorizeRequests(auth -> auth
                    .antMatchers("/public/**").not().hasAuthority("ROLE_ANONYMOUS")
            )
        .and()
        .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
}

@Override
protected void configure( AuthenticationManagerBuilder auth ) throws Exception {
    auth.authenticationProvider( bearerTokenProvider );
}

}

Montana
  • 65
  • 7

2 Answers2

4

You can add an authenticationEntryPoint to handle custom exception.

@Configuration
@RequiredArgsConstructor
static class CommonWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

    private final BearerTokenAuthenticationProvider bearerTokenProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .headers()
                .contentSecurityPolicy("script-src 'self'");
        http
            .csrf().disable()
            .authorizeRequests(auth -> auth
                 .antMatchers("/public/**").not().hasAuthority("ROLE_ANONYMOUS")
            )
            .oauth2ResourceServer(c -> c.jwt()
                .and()
                .authenticationEntryPoint((request, response, authException) -> {
                    //handle CustomAuthenticationException
                    
                    }
                )
            );
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(bearerTokenProvider);
    }
}

public class CustomAuthenticationException extends AuthenticationException {
    HttpStatus status;
    
    public CustomAuthenticationException(String message, HttpStatus status) {
        super(message);
        this.status = status;
    }
}
dur
  • 15,689
  • 25
  • 79
  • 125
DingHao
  • 313
  • 1
  • 5
2

I support the accepted answer here but want to highlight key tricky part of it:

I had same structure but instead of throwing my custom exception, I used AuthenticationServiceException and that was simply not working.

To be able to handle exception in your custom AuthenticationEntryPoint you MUST extend AuthenticationException with your own implementation as it is done in accepted answer.

  • 1
    Yes AuthenticationEntryPoint's method "commence" hadling only org.springframework.security.core.AuthenticationException and his subclasses – Montana Mar 15 '23 at 14:38