0

I have an old project with Java backend on Spring version 4.3.4.RELEASE and Spring security version 4.2.2.RELEASE. There is no way to update the libraries, I have to work with what there is. The project is not REST API, does not have RestController nor WebMvcConfigurer. So, I configured cors as was suggested here :

@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    protected SecurityConfiguration() {
        super();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
                // we don't need CSRF because our token is invulnerable
                .csrf().disable()

                // don't create session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

                .authorizeRequests()

                // allow anonymous resource requests
                .antMatchers(HttpMethod.GET,
                        "/",
                        "/*.html",
                        "/favicon.ico",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js")
                .permitAll()
                .antMatchers(HttpMethod.POST, "/rpc/*").permitAll()
                .anyRequest().permitAll();

        httpSecurity.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);

        // disable page caching
        httpSecurity.headers().cacheControl();
    }
}

The Cors filter:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter extends OncePerRequestFilter {

    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CorsFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        logger.error("CORS filter: " + request.getMethod());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, xsrf-token");
        response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            filterChain.doFilter(request, response);
        }
    }
}

In web.xml after all context-param and before listerenrs (that is the only filter in the app):

   <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>web.servlet.response.CorsFilter
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

I run the back end on localhost:8080 and front end on localhost:8081 However, when I try to send a POST request with application/json inside, there is an error in the browser console

Access to XMLHttpRequest at 'http://localhost:8080/rpc' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Also, I would expect to see log "CORS filter: POST" on the back end, which I put there to check if it would make it to the filter, but there is no such log.

Please, any suggestions on why is it not working? I need to stick to application/json in requests, and there is also an Authorization header sometimes in the app, so can't avoid cors completely. Can this be an Angular 2 issue?

Katrikken
  • 113
  • 1
  • 1
  • 9

2 Answers2

0

I'm not familiar with spring or java, but I think I understand the problem.

I assume that your logging filter does not work because spring framework short circuit that request before your filter is being executed.

The issue here is probably somewhere in config, but I believe that the approach to the given problem is not right in general.

CORS is created for some purposes, and by allowing requests from browser from all other origins you actually creating some potential security issues.

Ideally, if both: server and client are your apps, from the client side you should make requests only to the same origin which the client app is hosted on. So in your case locally it should make requests to localhost:8081, you can do that by omitting host base address on client side when making requests.

To have it working, for development environment the best option is to set up proxy for angular (to proxy requests from localhost:8081 to localhost:8080), detailed setup info is here.

For production environment you need to host backend-server/client apps on the same origin. You can do that by having some proxy server in front of your backend-server/client web servers, or by hosting client app (angular static output files) directly on your backend-server.

Another option, is to do what you have tried to do, but do not allow requests from all origins (not .permitAll()), instead - list specific allowed origins (like localhost:8081). But it's not that clean and also you will need to have different origins specified for development environment and for production.

Amir Arbabian
  • 2,306
  • 1
  • 3
  • 9
  • Thank you for the suggestion. I tried configuring it but run into problems. If you are familiar with Angular, could you take a look at this question too? https://stackoverflow.com/q/64681061/6834824 – Katrikken Nov 04 '20 at 13:31
0

This error is a result of denying OPTION web method, so you should add the following statement in the configure method:

.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

like so:

httpSecurity
            // we don't need CSRF because our token is invulnerable
            .csrf().disable()

            // don't create session
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

            .authorizeRequests()

            // allow anonymous resource requests
            .antMatchers(HttpMethod.GET,
                    "/",
                    "/*.html",
                    "/favicon.ico",
                    "/**/*.html",
                    "/**/*.css",
                    "/**/*.js")
            .permitAll()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers(HttpMethod.POST, "/rpc/*").permitAll()
            .anyRequest().permitAll();
Bassem Adas
  • 246
  • 2
  • 8