Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring: ExceptionTranslator of OAuth2 not working

In Spring with OAuth2, with an invalid access token, InvalidTokenException will occur and output:

{"error":"invalid_token","error_description":"Invalid access token: asdfasdf"}

when in json format.

I am trying to customize the output, such as

{"code": 123, "error":"invalid_token","error_description":"Invalid access token: asdfasdf"}

To do this I followed this example on Github https://github.com/spring-projects/spring-security-oauth/issues/375 and my code looks like this below. The problem is that my webResponseExceptionTranslator() never gets called. What is the problem?

package com.my.config;

import....

@Configuration
public class OAuth2ServerConfiguration {

    private final DataSource dataSource;

    public OAuth2ServerConfiguration(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public JdbcTokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

        private final TokenStore tokenStore;

        private final Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint;

        private final AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;

        private final CorsFilter corsFilter;

        public ResourceServerConfiguration(TokenStore tokenStore, Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint,
                                           AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler, CorsFilter corsFilter) {

            this.tokenStore = tokenStore;
            this.http401UnauthorizedEntryPoint = http401UnauthorizedEntryPoint;
            this.ajaxLogoutSuccessHandler = ajaxLogoutSuccessHandler;
            this.corsFilter = corsFilter;
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                .exceptionHandling()
                .authenticationEntryPoint(http401UnauthorizedEntryPoint)
                .and()
                .logout()
                .logoutUrl("/api/logout")
                .logoutSuccessHandler(ajaxLogoutSuccessHandler)
                .and()
                .csrf()
                .disable()
                .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
                .headers()
                .frameOptions().disable()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers("/api/authenticate").permitAll()
                .antMatchers("/api/register").permitAll()
                .antMatchers("/api/profile-info").permitAll()
                .antMatchers("/api/**").authenticated()
                .antMatchers(G.IFTTT_PATH).permitAll()
                .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
                .antMatchers("/v2/api-docs/**").permitAll()
                .antMatchers("/swagger-resources/configuration/ui").permitAll()
                .antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN);
        }

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId("res_q").tokenStore(tokenStore)
                .accessDeniedHandler(new OAuth2AccessDeniedHandler());
        }
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

        private final AuthenticationManager authenticationManager;

        private final TokenStore tokenStore;

        private final DataSource dataSource;

        public AuthorizationServerConfiguration(@Qualifier("authenticationManagerBean") AuthenticationManager authenticationManager,
                                                TokenStore tokenStore, DataSource dataSource) {

            this.authenticationManager = authenticationManager;
            this.tokenStore = tokenStore;
            this.dataSource = dataSource;
        }

        @Bean
        protected AuthorizationCodeServices authorizationCodeServices() {
            return new JdbcAuthorizationCodeServices(dataSource);
        }


        @Bean
        public WebResponseExceptionTranslator webResponseExceptionTranslator() {
            return new DefaultWebResponseExceptionTranslator() {

                @Override
                public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
                    // ==================== never gets called ===============
                    ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
                    OAuth2Exception body = responseEntity.getBody();
                    HttpHeaders headers = new HttpHeaders();
                    headers.setAll(responseEntity.getHeaders().toSingleValueMap());
                    // do something with header or response
                    System.out.println("========================== in webResponseExceptionTranslator  ===============================");
                    return new ResponseEntity<>(body, headers, responseEntity.getStatusCode());
                }
            };
        }

        @Bean
        public ApprovalStore approvalStore() {
            return new JdbcApprovalStore(dataSource);
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
            endpoints
                //========================== here ====================
                .exceptionTranslator(webResponseExceptionTranslator())
                //====================================================
                .authorizationCodeServices(authorizationCodeServices())
                .approvalStore(approvalStore())
                .tokenStore(tokenStore)
                .authenticationManager(authenticationManager);
        }


        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer.allowFormAuthenticationForClients();
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.jdbc(dataSource);
        }
    }
}
like image 490
supercobra Avatar asked Oct 30 '22 01:10

supercobra


1 Answers

My working solution for customizing the default oauth error message is this:

@Configurationpublic class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

@Override
public void configure(ResourceServerSecurityConfigurer resources) {
    OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
    authenticationEntryPoint.setExceptionTranslator(new CustomWebResponseExceptionTranslator());
    resources.authenticationEntryPoint(authenticationEntryPoint);
}

private class CustomWebResponseExceptionTranslator extends DefaultWebResponseExceptionTranslator  {
    @Override
    public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
        ResponseEntity<OAuth2Exception> responseEntity = super.translate(e);
        OAuth2Exception body = responseEntity.getBody();
        HttpHeaders headers = new HttpHeaders();
        headers.setAll(responseEntity.getHeaders().toSingleValueMap());
        // do something with header or response
        return new ResponseEntity<>(body, headers, responseEntity.getStatusCode());
    }
}

}

like image 116
Kevin Flachsmann Avatar answered Nov 15 '22 11:11

Kevin Flachsmann