0

Front end : React 16.12.0 | Back end : Spring 2.2.4.RELEASE

I am currently facing an issue regarding preflight CORS request. From my understanding, each non simple request (eg. GET with Authorization token) will trigger a preflight CORS request that the server has to validate through a response with all allowed parameters the "real" request send after should respect.

The preflight is coming on server side as a OPTION request and should hit my cors filter in order to be validated.

Request send from front end:

export function greeting() {
    const access_token = AuthTokenFromStore().oauthData.access_token;
    const obj = {  
        method: 'GET',
        headers: {

        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        'Accept': 'application/json',
            'Authorization': 'Bearer ' + access_token
        }
    };
    return (fetch('http://localhost:8080/api/v1/greeting', obj)
    .then(res => res.json()));
}

Error message receive:

OPTIONS http://localhost:8080/api/v1/greeting 401
Access to fetch at 'http://localhost:8080/api/v1/greeting' from origin 'http://localhost:3000' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

spring security config:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityServerConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
                .cors() // <-- fetch the corsFilter bean
                .and()
                .csrf().disable()
                .antMatcher("/**")
                .authorizeRequests()
                .antMatchers("/oauth/authorize**", "/login**", "/error**")
                .permitAll()
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll();
    }
//...
}

cors filter config:

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSConfig {
    @Bean
    public CorsFilter corsFilter() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("origin", "x-authorization", "content-type", "accept"));
        configuration.setMaxAge(3600L);
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return new CorsFilter(source);
    }
}

my log :

2020-03-19 17:00:24.993 DEBUG 9452 --- [nio-8080-exec-2] o.a.coyote.http11.Http11InputBuffer      : Received [OPTIONS /api/v1/greeting HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://localhost:3000
Sec-Fetch-Dest: empty
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
Access-Control-Request-Headers: authorization
Accept: */*
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8

]

2020-03-19 17:00:24.994 DEBUG 9452 --- [nio-8080-exec-2] o.a.c.authenticator.AuthenticatorBase    : Security checking request OPTIONS /api/v1/greeting
2020-03-19 17:00:24.994 DEBUG 9452 --- [nio-8080-exec-2] org.apache.catalina.realm.RealmBase      :   No applicable constraints defined
2020-03-19 17:00:24.994 DEBUG 9452 --- [nio-8080-exec-2] o.a.c.authenticator.AuthenticatorBase    : Not subject to any constraint
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/token']
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/greeting'; against '/oauth/token'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/token_key']
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/greeting'; against '/oauth/token_key'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/check_token']
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/greeting'; against '/oauth/check_token'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 1 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 2 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 4 of 10 in additional filter chain; firing Filter: 'LogoutFilter'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', GET]
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'OPTIONS /api/v1/greeting' doesn't match 'GET /logout'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', POST]
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'OPTIONS /api/v1/greeting' doesn't match 'POST /logout'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', PUT]
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'OPTIONS /api/v1/greeting' doesn't match 'PUT /logout'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', DELETE]
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'OPTIONS /api/v1/greeting' doesn't match 'DELETE /logout'
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
2020-03-19 17:00:25.000 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 5 of 10 in additional filter chain; firing Filter: 'OAuth2AuthenticationProcessingFilter'
2020-03-19 17:00:25.001 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.o.p.a.BearerTokenExtractor         : Token not found in headers. Trying request parameters.
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] org.apache.tomcat.util.http.Parameters   : Set encoding to UTF-8
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.o.p.a.BearerTokenExtractor         : Token not found in request parameters.  Not an OAuth2 request.
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] p.a.OAuth2AuthenticationProcessingFilter : No token in request, will continue chain.
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 6 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 7 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 8 of 10 in additional filter chain; firing Filter: 'SessionManagementFilter'
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/greeting at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/greeting'; against '/api/**'
2020-03-19 17:00:25.006 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /api/v1/greeting; Attributes: [#oauth2.throwOnError(authenticated)]
2020-03-19 17:00:25.010 DEBUG 9452 --- [nio-8080-exec-2] o.s.s.w.a.ExceptionTranslationFilter     : Authentication exception occurred; redirecting to authentication entry point

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

During debug, i can see http.cors() get my bean corsFilter properly but why it does not appear in the log ?

I tested a lot of solution (google reasearcg, tutorials, official spring docs, baeldung, stackoverflow... etc) no one worked for me. Also, the framework gives us a way to do it properly so i want to avoid adding filter manually to bypass OPTIONS request (it will be my last resort).

Could someone help me on this issue ? or point out what i did wrong ?

Thanks for your help !

DPheng
  • 21
  • 6
  • 1
    this log output has actually not much to do with cors. it actually tells you that only an oauth2 authenticated user is allowed to perform the preflight request. you are not sending any token in your request and there is no authentication object in your session. hence, you are not allowed to perform such an action. – pero_hero Mar 19 '20 at 17:29
  • the log shows that the request (preflight) is not handle properly by filters, i will edit my question to add more details. – DPheng Mar 19 '20 at 19:15
  • 1
    can you add the log output for the DefaultSecurityFilterChain to see which filters you are actually using and in which order? – pero_hero Mar 19 '20 at 20:35

1 Answers1

1

Find out the issue, i have configured ResourceServerConfigurerAdapter at the same time as my WebSecurityConfigurerAdapter. It seems like ResourceServerConfigurerAdapter has a higher priority so all my custom configuration was not taken into account. The only purpose of WebSecurityConfigurerAdapter is to provide authentication process for OAuth2. So i simplified the configure method to the bear minimum in my security config and move all other configuration to resourceServer config, and more especially the cors filter that was the solution to my original blocking point.

Discussed : ResourceServerConfigurerAdapter vs WebSecurityConfigurerAdapter

DPheng
  • 21
  • 6