Search code examples
angularjsjakarta-eespring-securitycorsbasic-authentication

Cross Domain HTTP request fails in AngularJS


I have a REST backend with Spring (CORS enabled running on Apache Tomcat 7) and an AngularJS client. Both running on different domains (as far as CORS is concerned).

I'm trying to implement Basic Auth but it only works when both the client and the service are on the same host/port number even after I verified that CORS is working fine on the server side. (I tested it by disabling basic auth impl and simply checking if the client is able to pull data from service. It works as long as the CORS filter on the service is working - as expected).

Here is the client configuration

Enabling Cross domain request for Angular (I heard that it's not needed for Angular 1.2+ but it doesn't seem to work either way)

myApp.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
 }]);

HTTP Call

 $http({method: 'GET', url: url + userId, headers: {'Authorization': 'Basic ' + Base64.encode('admin' + ':' + 'password')}}).
    success(function(data, status, headers, config) {
//
    }).
    error(function(data, status, headers, config) {
//
    });

Backend CORS Filter

FilterRegistration corsFilter = container.addFilter("CORS", CORSFilter.class);
corsFilter.setInitParameter("cors.supportedMethods", "GET, HEAD, POST, PUT, DELETE, OPTIONS");
corsFilter.setInitParameter("cors.supportedHeaders", "Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
corsFilter.setInitParameter("cors.supportsCredentials ", "false");
corsFilter.setInitParameter("cors.allowOrigin ", "*");
corsFilter.addMappingForUrlPatterns(null, false, "/*");

Spring Security for Basic Auth

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("admin").password("password").roles("USER", "ADMIN");
    }


     @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/**").hasRole("USER")
        .anyRequest().anonymous()
        .and()
        .httpBasic();
  }    
}

Error I get (The whole error as-is per request made by the client to the service while running on another domain)

Failed to load resource: the server responded with a status of 403 (Forbidden) (11:53:44:206 | error, network)
  at http://localhost:8081/myApp-service/user/6
Failed to load resource: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8383' is therefore not allowed access. (11:53:44:209 | error, network)
  at http://localhost:8081/myApp-service/user/6
XMLHttpRequest cannot load http://localhost:8081/myApp-service/user/6. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8383' is therefore not allowed access. (11:53:44:211 | error, javascript)
  at app/index.html

Chrome Request header

Request URL:http://localhost:8081/myApp-service/user/6
Request Method:OPTIONS
Status Code:403 Forbidden
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, authorization
Access-Control-Request-Method:GET
Connection:keep-alive
Host:localhost:8081
Origin:http://localhost:8383
Referer:http://localhost:8383/myApp-client/app/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
Response Headersview source
Content-Length:93
Content-Type:text/plain;charset=ISO-8859-1
Date:Wed, 26 Feb 2014 18:55:00 GMT
Server:Apache-Coyote/1.1

So as you can see, Angular is unable to deal with the CORS pre-flight OPTIONS even afte the appropriate config is written. Everything works fine in the same domain and the CORS filter in the backend is tested to work independently. So not sure what I'm missing here. Thanks!


Solution

  • I assumed that the problem was with my client but as Ray pointed out, it was with my Service.

    Once I knew that I need to debug my service, I downloaded the sources of CORSFilter, put break points appropriately to study the server response.

    Doing so, I found out that the CORS filter is throwing an exception when it encountered "Authorization" in the request Headers. This is because I did not add it to the list of supported headers. The problem was resolved soon after I added it to the list.

    corsFilter.setInitParameter("cors.supportedHeaders", "Accept, Origin, X-Requested-With, Content-Type, Last-Modified, Authorization");