9

I'm trying to configure Spring for CORS in order to use Angular web UI:

I tried this:

@Configuration
@ComponentScan("org.datalis.admin.config")
public class AppConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
        PropertySourcesPlaceholderConfigurer conf = new PropertySourcesPlaceholderConfigurer();
        conf.setLocation(new ClassPathResource("application.properties"));
        return conf;
    }

    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("127.0.0.1");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source));
        bean.setOrder(0);
        return bean;
    }
}

Apache server with Angular FE is running with Wildly server on the same server so I configured 127.0.0.1 for source.

But still I get:

Access to XMLHttpRequest at 'http://123.123.123.123:8080/api/oauth/token' from origin 'http://123.123.123.123' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
auth:1 Failed to load resource: the server responded with a status of 404 (Not Found)

Do you know how I can fix this issue?

Second way that I tried:

@Configuration
@EnableResourceServer
public class ResourceSecurityConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId("resource_id").stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/users/**").permitAll()
                .anyRequest().authenticated()
                .and()
        .cors().disable()
        .authorizeRequests()
        .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
        .anyRequest()
        .fullyAuthenticated()
        .and()
        .httpBasic()
        .and()
        .csrf().disable();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSources() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
        configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

With the second configuration I get has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status. auth:1 Failed to load resource: the server responded with a status of 404 (Not Found)

What is the best way to achieve this result?

Milad
  • 27,506
  • 11
  • 76
  • 85
Peter Penzov
  • 1,126
  • 134
  • 430
  • 808

6 Answers6

6

Your allowed origin is 127.0.0.1 but your client side has the ip 123.123.123.123. Try to change this:

config.addAllowedOrigin("127.0.0.1");

To this:

config.addAllowedOrigin("123.123.123.123");
Roddy of the Frozen Peas
  • 14,380
  • 9
  • 49
  • 99
Raphael Alves
  • 169
  • 1
  • 3
  • Hi Raphael! Welcome to StackOverflow. I editted your post to format the code -- for future reference, code blocks are formatted by indenting them with four spaces. – Roddy of the Frozen Peas Jan 18 '19 at 16:34
  • You can try to add on your client the header "with credentials: true". You can do it on angular adding a interceptor on the http client. See https://stackoverflow.com/questions/38615205/angular-2-http-withcredentials – Raphael Alves Jan 18 '19 at 21:19
5

You need to tell Spring Security to use the CORS Configuration you created.

In my project I configured Spring Security in this way:

@Override
protected void configure(HttpSecurity http) throws Exception
{
    http
        .authorizeRequests()
        .antMatchers("/rest/protected/**")
        .authenticated()
     //Other spring sec configruation and then:
    .and()
        .cors()
        .configurationSource(corsConfigurationSource())

}

Where corsConfigurationSource() is:

@Bean
    CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        boolean abilitaCors = new Boolean(env.getProperty("templating.oauth.enable.cors"));
        if( abilitaCors )
        {
            if( logger.isWarnEnabled() )
            {
                logger.warn("CORS ABILITATI! Si assume ambiente di sviluppo");
            }
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200","http://localhost:8080", "http://localhost:8180"));
            configuration.setAllowedMethods(Arrays.asList(  RequestMethod.GET.name(),
                    RequestMethod.POST.name(), 
                    RequestMethod.OPTIONS.name(), 
                    RequestMethod.DELETE.name(),
                    RequestMethod.PUT.name()));
            configuration.setExposedHeaders(Arrays.asList("x-auth-token", "x-requested-with", "x-xsrf-token"));
            configuration.setAllowedHeaders(Arrays.asList("X-Auth-Token","x-auth-token", "x-requested-with", "x-xsrf-token"));
            source.registerCorsConfiguration("/**", configuration);
        }
        return source;
    }

I hope it's useful

Angelo

Angelo Immediata
  • 6,635
  • 4
  • 33
  • 65
3

This is my working @Configuration class to handle CORS requests used only in dev environment.

@Configuration
//@Profile(PROFILE_DEV)
  public class CorsConfiguration {

  @Bean
  public WebMvcConfigurer corsConfigurer() {
      return new WebMvcConfigurer() {
          @Override
          public void addCorsMappings(CorsRegistry registry) {
              registry.addMapping("/**")
                  .allowedOrigins("*")
                  .allowedHeaders("*")
                  .allowedMethods("*");
          }
      };
  }
}

You have also to configure Spring Security to ignore HttpMethod.OPTIONS used by preflight request (as the exception you mentioned)

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  //...
    @Override
    public void configure(WebSecurity web) throws Exception {
      web.ignoring()
            //others if you need
            .antMatchers(HttpMethod.OPTIONS, "/**");

    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
            .disable()
            .exceptionHandling()
            .and()
            .headers()
            .frameOptions()
            .disable()
            .and()
            .authorizeRequests()
            .antMatchers("/api/register").permitAll()
            .antMatchers("/api/activate").permitAll()
            .antMatchers("/api/authenticate").permitAll()
            .antMatchers("/api/**").authenticated();
    }

}

Because when you use cors you have Simple Request and Preflighted Request that triggers an HttpMethod.OPTIONS

ValerioMC
  • 2,926
  • 13
  • 24
  • I use also Spring security. Is this going to work for Spring Security? – Peter Penzov Jan 21 '19 at 09:13
  • updated answer with spring security OPTIONS configuration – ValerioMC Jan 21 '19 at 09:38
  • I tried your proposal combined wit the proposal from @Angelo Immediata but still I get the same issue. Any additional idea how to solve it? – Peter Penzov Jan 21 '19 at 10:49
  • My solution doesn't need to add other stuff. Try to leave the code as i explained, just be sure `@Configuration` classes are correctly loaded. Tell me if you still have exception – ValerioMC Jan 21 '19 at 11:01
  • I tested only your code. Unfortunately the issue is not fixed. – Peter Penzov Jan 21 '19 at 11:06
  • can i see your configuration classes? – ValerioMC Jan 21 '19 at 11:13
  • Today I will upload on GitHub minimal working example. – Peter Penzov Jan 21 '19 at 11:22
  • I added my configuration here: https://github.com/rcbandit111/Spring_test – Peter Penzov Jan 21 '19 at 13:47
  • this is good because now CORS configuration is working but for some reason ` web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");` is not taken... Now you have a 403 FORBIDDEN on preflight request. You need to allow in spring security all your OPTIONS method – ValerioMC Jan 21 '19 at 20:16
  • I tried to add this: `http .csrf().disable() .authorizeRequests() .antMatchers(HttpMethod.OPTIONS,"/**").permitAll()` But now I get `Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.` – Peter Penzov Jan 21 '19 at 20:47
  • remove `.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()` and leave OPTIONS configuration only in `CorsConfiguration` class – ValerioMC Jan 21 '19 at 21:31
  • I get during deployment: `Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalStateException: At least one mapping is required (i.e. authorizeRequests().anyRequest().authenticated())` Can you extend a little bit what I need to set for HttpSecurity http – Peter Penzov Jan 21 '19 at 21:40
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/187072/discussion-between-valeriomc-and-peter-penzov). – ValerioMC Jan 21 '19 at 21:49
2

You need to add @CrossOrigin class level in your controller class like below

@CrossOrigin
public class SampleController {
    // Your code goes here
}

annotation to your rest controller class

Sasikumar Murugesan
  • 4,412
  • 10
  • 51
  • 74
2

I recommend you to use a WebMvcConfigurer, and in the addCorsMappings method set the CORS configuration.

Somethingo like this

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOrigins("http://localhost:9798")
            .allowedMethods("POST", "GET")
            //.allowedHeaders("header1", "header2", "header3")
            //.exposedHeaders("header1", "header2")
            .allowCredentials(true).maxAge(3600);
    }
}

Here there is a link with a fully functional Spring with CORS project, just download and run it.

https://github.com/reos79/spring-cors

It has a html page (person.html) this page does nothing but call the service on the port (9797). So you need to load this project twice, once on port 9797 to load the service and the other on port (9798). Then on you browser you call the page person on the server localhost:9798 and it will call the service on localhost:9797, in the file application.properties I configured the port.

reos
  • 8,766
  • 6
  • 28
  • 34
  • do you know do I need to add some configuration in Apache and Angular? – Peter Penzov Jan 21 '19 at 17:25
  • Here is the Wildfly config file using your configuration: https://pastebin.com/TzXPsNwt – Peter Penzov Jan 21 '19 at 18:48
  • Did you remove the Bean public CorsConfigurationSource corsConfigurationSources() ? and Bean public FilterRegistrationBean corsFilter() ? – reos Jan 21 '19 at 19:26
  • Yes, I did. But I will try again with clean setup later. – Peter Penzov Jan 21 '19 at 19:27
  • Here is the result from the second attempt: https://pastebin.com/q5eRqSz8 – Peter Penzov Jan 21 '19 at 20:56
  • I missed this in my code: `http .cors().and() .csrf().disable() .authorizeRequests().anyRequest().permitAll() .and().authorizeRequests() .antMatchers("/users/**").permitAll() .anyRequest().authenticated();` – Peter Penzov Jan 21 '19 at 21:06
  • That is due to authentication problems, replace your method with this, just to try Override protected void configure(HttpSecurity http) throws Exception { http .cors().and() .csrf().disable() .authorizeRequests().anyRequest().permitAll(); } – reos Jan 21 '19 at 21:44
  • No positive result. – Peter Penzov Jan 21 '19 at 21:53
  • it's difficult because I dont have your complete project. The project I gave you it's just to run, you dont need an appserver or something else, it just work. I suggest you that compare both projects and see whats is different – reos Jan 21 '19 at 21:56
0

Try changing your bean name to corsConfigurationSource removing the "s"

Documentation https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors

// by default uses a Bean by the name of corsConfigurationSource

Code Junkie
  • 7,602
  • 26
  • 79
  • 141