I added Spring Security (5.0.0.RELEASE) with JWT Authentication to Spring Boot (1.5.7.RELEASE), but the CORS seems to not work. I added the CORS configuration as described here. I also tried adding @CrossOrigin to the controllers, but it doesn't seem to change anything.
When calling POST
and GET
requests from the front-end (Angular JS 5) there doesn't seem to be any CORS problem, but when calling DELETE
I get CORS error.
Here's the security configuration:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(UserDetailsService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.antMatchers(HttpMethod.GET, ACTIVATE_URL).permitAll()
.antMatchers(AUTH_WHITELIST).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
// this disables session creation on Spring Security
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration configuration = new CorsConfiguration().applyPermitDefaultValues();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.addAllowedMethod(HttpMethod.TRACE);
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
And here are the headers from postman when sending OPTIONS
request:
Allow →DELETE,GET,HEAD,POST
Cache-Control →no-cache, no-store, max-age=0, must-revalidate
Content-Length →0
Date →Fri, 12 Jan 2018 13:22:08 GMT
Expires →0
Pragma →no-cache
X-Content-Type-Options →nosniff
X-Frame-Options →DENY
X-XSS-Protection →1; mode=block
The allow-access-control-origin header is missing, as well as the HTTP TRACE I added to see if the configuration is working.
And the spring security debug logs:
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@7ce27d90
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 5 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', GET]
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /api/stories/7' doesn't match 'GET /logout
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', POST]
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /api/stories/7' doesn't match 'POST /logout
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', PUT]
2018-01-12 14:22:08.621 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /api/stories/7' doesn't match 'PUT /logout
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : Trying to match using Ant [pattern='/logout', DELETE]
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /api/stories/7' doesn't match 'DELETE /logout
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher : No matches found
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 6 of 13 in additional filter chain; firing Filter: 'JWTAuthenticationFilter'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/stories/7'; against '/api/users/login'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 7 of 13 in additional filter chain; firing Filter: 'JWTAuthorizationFilter'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /api/stories/7' doesn't match 'POST /api/users/register
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'OPTIONS /api/stories/7' doesn't match 'GET /api/users/activate/**
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/stories/7'; against '/api/users/login'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/stories/7'; against '/api/users/request-reset-password'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/stories/7'; against '/api/users/reset-password'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/stories/7'; against '/api/stories'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/api/stories/7'; against '/api/stories/*'
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Secure object: FilterInvocation: URL: /api/stories/7; Attributes: [permitAll]
2018-01-12 14:22:08.622 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
2018-01-12 14:22:08.623 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@703f0616, returned: 1
2018-01-12 14:22:08.623 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful
2018-01-12 14:22:08.623 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object
2018-01-12 14:22:08.623 DEBUG 15619 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /api/stories/7 reached end of additional filter chain; proceeding with original chain
2018-01-12 14:22:08.630 DEBUG 15619 --- [nio-8080-exec-3] o.s.s.w.a.ExceptionTranslationFilter : Chain processed normally
2018-01-12 14:22:08.630 DEBUG 15619 --- [nio-8080-exec-3] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
And here are the logs for Invalid CORS request:
2018-01-12 15:47:09.445 DEBUG 17909 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/users/bank-accounts/ at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2018-01-12 15:47:09.445 DEBUG 17909 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/users/bank-accounts/ at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2018-01-12 15:47:09.445 DEBUG 17909 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/users/bank-accounts/ at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2018-01-12 15:47:09.445 DEBUG 17909 --- [nio-8080-exec-2] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@7d9c9d3c
2018-01-12 15:47:09.446 DEBUG 17909 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy : /api/users/bank-accounts/ at position 4 of 13 in additional filter chain; firing Filter: 'CorsFilter'
2018-01-12 15:47:09.446 DEBUG 17909 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
origin
header, I get the response from the question, and when I puthttp://localhost:4200/
in the origin header I get Invalid CORS request – Cokaorigin
header. Your browser adds this header automatically, but I don't know if Postman does it, too. – durallowMethods
isnull
, so addingconfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "DELETE", "OPTIONS"));
to the configuration makes the request valid. Not sure why theallowMethods
is null with theCorsConfiguration#applyPermitDefaultValues
– Coka