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);
}
}