Reputation: 2518
I have a Spring Boot / Spring Data REST service allowing access to a number of resources. Some of this resources (eg. /detections
) are freely accessible, other (eg. /users
) require basic HTTP auth. By testing the REST service with CURL everything works as expected. The problems arise when I try to access the service from an Angular2 web application.
In this case I have no problem when accessing the unprotected resources http://api.mydomain.com/detections
:
this.http.get(this.DETECTIONS_API_ENDPOINT).subscribe(
response => {
...
},
error => {
...
}
);
But if I try to access a protected resource http://api.mydomain.com/users
by passing the required headers with the correct username and password:
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', 'Basic ' + btoa(username+':'+password));
return this.http.get(this.USERS_API_ENDPOINT, { body: "", headers: headers }).subscribe(
response => {
...
},
error => {
...
}
);
I get (in Firefox console) an error which saying cross-origin request blocked... Reason: CORS preflight request unsuccessfull
(please note that this is my translation from Italian. I couldn't find the exact corresponding error message in English. The only difference between the two calls seems to be the passing of the headers in the second case, which triggers the sending of an OPTIONS
instead of a GET
request.
This is my spring security configuration:
@Configuration
public class MyAppConfigurationSecurity extends WebSecurityConfigurerAdapter {
private Md5PasswordEncoder md5PasswordEncoder = new Md5PasswordEncoder();
@Autowired
private UserDetailsService myAppUserService;
/**
* HttpSecurity URL configuration settings. Configure authentication necessary for POST but not for GET
*/
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/detections").permitAll()
.antMatchers(HttpMethod.GET, "/detections/search/findTop5ByOrderByTimestampDesc").permitAll()
.antMatchers("/users").hasAuthority("ADMIN")
.antMatchers("/roles").hasAuthority("ADMIN")
.antMatchers("**").authenticated()
.and().httpBasic().and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
/**
* Sets custom MyAppUserService bean as user detail service
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myAppUserService).passwordEncoder(md5PasswordEncoder);
}
}
This is the CORS filter configuration; I added this class following the suggestion at Spring Data Rest and Cors, and it initially solved my CORS-access problem for accessing the unprotected resources. Unfortunately it doesn't seem to work in the case of the protected resource:
@Configuration
public class MyAppConfigurationCors {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // you USUALLY want this
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("GET");
config.addAllowedMethod("OPTIONS"); // I added this in a second phase, but nothing changes
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
Upvotes: 2
Views: 3975
Reputation: 76
You can add the the cors filter before the first Spring Security Filter i.e. ChannelProcessingFilter. The following piece of code will help explain more.
protected void configure(HttpSecurity http) throws Exception {
http.requiresChannel().antMatchers("/*").requires(ANY_CHANNEL).and()
.authorizeRequests().antMatchers("/api/customer/**").permitAll()
.antMatchers("/api/signin").permitAll()
.antMatchers("/api/**").permitAll()
.antMatchers("/**").permitAll().and()
.addFilterBefore(corsFilter(), ChannelProcessingFilter.class)
.and().csrf().disable();
}
If any other info is required visit this -: http://javamusings.com/enabling-cors-support-in-spring-framework/. Note -: I am the author of the post.
Upvotes: 2
Reputation: 51481
Please refer to Spring Documentation on how to integrate CORS and Spring Security.
CORS must be processed first:
@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;
}
}
Upvotes: 4