Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CORS issue - No 'Access-Control-Allow-Origin' header is present on the requested resource

Tags:

I have created two web applications - client and service apps.
The interaction between client and service apps goes fine when they are deployed in same Tomcat instance.
But when the apps are deployed into seperate Tomcat instances (different machines), I get the below error when request to sent service app.

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 401

My Client application uses JQuery, HTML5 and Bootstrap.

AJAX call is made to service as shown below:

var auth = "Basic " + btoa({usname} + ":" + {password});
var service_url = {serviceAppDomainName}/services;

if($("#registrationForm").valid()){
    var formData = JSON.stringify(getFormData(registrationForm));
    $.ajax({
        url: service_url+action,
        dataType: 'json',
        async: false,
        type: 'POST',
        headers:{
            "Authorization":auth
        },
        contentType: 'application/json',
        data: formData,
        success: function(data){
            //success code
        },
        error: function( jqXhr, textStatus, errorThrown ){
            alert( errorThrown );
        });
}

My service application uses Spring MVC, Spring Data JPA and Spring Security.

I have included CorsConfiguration class as shown below:

CORSConfig.java:

@Configuration
@EnableWebMvc
public class CORSConfig extends WebMvcConfigurerAdapter  {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("*");
    }
}

SecurityConfig.java:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@ComponentScan(basePackages = "com.services", scopedProxy = ScopedProxyMode.INTERFACES)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("authenticationService")
    private UserDetailsService userDetailsService;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
                .authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().fullyAuthenticated();
        http.httpBasic();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.csrf().disable();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        return authenticationProvider;
    }
}

Spring Security dependencies:

 <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>3.2.3.RELEASE</version>
</dependency>
<dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>3.2.3.RELEASE</version>
</dependency>

I am using Apache Tomcat server for deployment.

like image 599
JavaDeveloper Avatar asked Feb 03 '17 03:02

JavaDeveloper


People also ask

How do I fix CORS header Access-Control allow Origin missing?

If the server is under your control, add the origin of the requesting site to the set of domains permitted access by adding it to the Access-Control-Allow-Origin header's value. You can also configure a site to allow any site to access it by using the * wildcard. You should only use this for public APIs.


1 Answers

CORS' preflight request uses HTTP OPTIONS without credentials, see Cross-Origin Resource Sharing:

Otherwise, make a preflight request. Fetch the request URL from origin source origin using referrer source as override referrer source with the manual redirect flag and the block cookies flag set, using the method OPTIONS, and with the following additional constraints:

  • Include an Access-Control-Request-Method header with as header field value the request method (even when that is a simple method).
  • If author request headers is not empty include an Access-Control-Request-Headers header with as header field value a comma-separated list of the header field names from author request headers in lexicographical order, each converted to ASCII lowercase (even when one or more are a simple header).
  • Exclude the author request headers.
  • Exclude user credentials.
  • Exclude the request entity body.

You have to allow anonymous access for HTTP OPTIONS.

Spring Security 3

Your modified (and simplified) code:

@Override
protected void configure(HttpSecurity http) throws Exception {
   http
       .authorizeRequests()
           .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
           .antMatchers("/login").permitAll()
           .anyRequest().fullyAuthenticated()
           .and()
       .httpBasic()
           .and()
       .sessionManagement()
           .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
           .and()
       .csrf().disable();
}

You still need your CORS configuration (probably with some additional values):

@Configuration
@EnableWebMvc
public class CORSConfig extends WebMvcConfigurerAdapter  {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("*");
    }
}

Spring Security 4

Since Spring Security 4.2.0 you can use the built-in support, see Spring Security Reference:

19. CORS

Spring Framework provides first class support for CORS. CORS must be processed before Spring Security because the pre-flight request will not contain any cookies (i.e. the JSESSIONID). If the request does not contain any cookies and Spring Security is first, the request will determine the user is not authenticated (since there are no cookies in the request) and reject it.

The easiest way to ensure that CORS is handled first is to use the CorsFilter. Users can integrate the CorsFilter with Spring Security by providing a CorsConfigurationSource using the following:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
      http
          // by default uses a Bean by the name of corsConfigurationSource
          .cors().and()
          ...
  }

  @Bean
  CorsConfigurationSource corsConfigurationSource() {
      CorsConfiguration configuration = new CorsConfiguration();
      configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
      configuration.setAllowedMethods(Arrays.asList("GET","POST"));
      UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
      source.registerCorsConfiguration("/**", configuration);
      return source;
  }
}
like image 149
dur Avatar answered Sep 20 '22 16:09

dur