Ajax login with spring security and CORS

Viewed 600

I followed this guide in order to implement an api with spring-security. It works well locally, but when i'm deploying it on a distant server, the login end point is unreachable because of cors policy (server:80 try to reach server:8080).

I added cors filters to deal with it, but it seems that the login method (and maybe protected methods, I can't test it since I can't log in) doesn't use my custom filter. End points available for not logged in users works well

The request is preflighted, but the server doesn't add correct headers on the distant server.

First, here is request and response for the preflighted request before reaching a public end point

Request:

Host: 01.02.03.04:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: GET
Access-Control-Request-Headers: x-requested-with
Origin: http://01.02.03.04
Connection: keep-alive
Cache-Control: max-age=0

Response:

Access-Control-Allow-Methods: GET,HEAD,POST
Access-Control-Allow-Origin: http://01.02.03.04
Access-Control-Max-Age: 1800
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 0
Date: Mon, 10 Jul 2017 10:40:32 GMT
Vary: Origin
access-control-allow-credentials: true
access-control-allow-headers: x-requested-with

Here is request and response for the preflighted request before reaching the login endpoint:

Request :

Host: 01.02.03.04:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-requested-with
Origin: http://01.02.03.04
Connection: keep-alive

Response :

Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 20
Date: Mon, 10 Jul 2017 11:18:40 GMT

We easily see that, when trying to reach /login, the server doesn't answer correctly.

Here is an ajax test to reach /login :

Login.prototype.login = function(){
  var self = this;
  return function(){
    $.ajax({
      url:properties.serverUrl+'login',
      beforeSend:function(xhr) {
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
      },
      type : 'POST',
      dataType:"json",
      contentType: 'application/json',
      data:JSON.stringify({
        username:"username",
        password:"password"
      }),
      success:self.handleToken(),
      error:utils.displayError
    });
  }
}

Here is the WebSecurityConfigurerAdapter configure method:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
        .csrf().disable() // We don't need CSRF for JWT based authentication
        .exceptionHandling()
        .authenticationEntryPoint(this.authenticationEntryPoint)

        .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

        .and()
            .authorizeRequests()
                .antMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
                .antMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
        .and()
            .authorizeRequests()
                .antMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points
        .and()
            .addFilterBefore(new CustomCorsFilter(), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(buildAjaxLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(buildJwtTokenAuthenticationProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
    }

And here is the custom cors filter:

public class CustomCorsFilter extends CorsFilter {

public CustomCorsFilter() {
    super(configurationSource());
}

private static UrlBasedCorsConfigurationSource configurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.setMaxAge(36000L);
    config.setAllowedMethods(Arrays.asList("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}
}

Thank you for your answers,

Emmanuel

0 Answers
Related