Search code examples
javaspring-bootoauth-2.0corscloud-security

How do I handle CORS in Spring Boot Oauth2 Resource Server with password grant


Details: I am using spring boot oauth2 resource server which is giving me CORS even after trying different approaches to filter this off.

How do my code look ?

Its a simple resource server with spring boot with spring-cloud-starter-oauth2 and spring-cloud-starter-security as two major dependencies.

I have used java annotations to make this a resource server :

@CrossOrigin(origins = "*", maxAge = 3600, allowedHeaders = "*")
@RestController
@RequestMapping("/api/v1")
@EnableResourceServer

Here is how I tried to resolve this :

I tried to add a custom filter which skips further filter calls with code below. After this I got "Authorization Header not allowed in preflight request on browser". After adding CORS everyehere extension to my browser my requests succeeded.

@EnableWebSecurity(debug = true)
@Order(Ordered.HIGHEST_PRECEDENCE)
public class WebSecurityConfig implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        response.setHeader("Access-Control-Expose-Headers", "Location");
        System.out.println(request.getMethod());
        System.out.println("-----------------");
        if(!request.getMethod().equals("OPTIONS")) {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {}

    @Override
    public void destroy() {}

}

Solution

  • I had the same problem and that was the resolution.

    public class ResourceServerCustom extends ResourceServerConfigurerAdapter {
    
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().cors().disable().authorizeRequests().antMatchers("/oauth/token/**").permitAll()
                .anyRequest().authenticated().and().exceptionHandling()
                .authenticationEntryPoint(new AuthExceptionEntryPoint());
    
        http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
    
    }
    

    }

    And others configs.

    public class WebSecurityCustom extends WebSecurityConfigurerAdapter {
    
    public TokenStore tokenStore;
    
    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
    
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources/**",
                "/configuration/security", "/swagger-ui.html", "/webjars/**");
        web.ignoring().antMatchers(HttpMethod.OPTIONS);
    }
    

    }

    public class CorsFilterCustom extends OncePerRequestFilter {
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods",
                "ACL, CANCELUPLOAD, CHECKIN, CHECKOUT, COPY, DELETE, GET, HEAD, LOCK, MKCALENDAR, MKCOL, MOVE, OPTIONS, POST, PROPFIND, PROPPATCH, PUT, REPORT, SEARCH, UNCHECKOUT, UNLOCK, UPDATE, VERSION-CONTROL");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept, Key, Authorization");
    
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(request, response);
        }
    }
    

    }

    public class AuthorizationServerCustom implements AuthorizationServerConfigurer {
    
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("isAuthenticated()");
    }
    
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager);
    }
    

    }

    public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
    
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2)
            throws ServletException, IOException {
        final Map<String, Object> mapBodyException = new HashMap<>();
    
        mapBodyException.put("error", "Error from AuthenticationEntryPoint");
        mapBodyException.put("message", "Message from AuthenticationEntryPoint");
        mapBodyException.put("exception", "My stack trace exception");
        mapBodyException.put("path", request.getServletPath());
        mapBodyException.put("timestamp", (new Date()).getTime());
    
        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
    
        final ObjectMapper mapper = new ObjectMapper();
        mapper.writeValue(response.getOutputStream(), mapBodyException);
    }
    

    }