I'm having an issue with spring boot application authenticated using keycloak, I have this application sitting behind a haproxy and have tried to completely disable cors on the spring app and manage this on the proxy side, however Im still having issues with cors. "It does not have HTTP ok status"
Note I'm using an older version of the spring boot keycloak plugin due to the original application using spring boot version 1.5.10 Please find attached some of the configuration options I have explored:
Case no 1: Disable cors on spring app -------------------------------------------------
This setup returns http status ok not present on response preflight header
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
public SecurityWithoutCsrfConfig() {
super();
}
// Submits the KeycloakAuthenticationProvider to the AuthenticationManager
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
// Specifies the session authentication strategy
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**",
"/v2/api-docs",
"/swagger-ui.html",
"/swagger2-ui.html",
"/springfox/**",
"/v2/swagger.json",
"/_twilio/**",
"/webjars/**",
"/configuration/**",
"/swagger-resources/**");
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/mypath/**").hasAnyRole("USER")
.antMatchers("/mypath_admin/**").hasAnyRole("USER_ADMIN", "ADMIN")
.anyRequest().fullyAuthenticated()
.and().httpBasic().and().cors().disable();
http.headers().cacheControl();
}
Case no 2 : set the headers on spring app side -----------------------------------------------
SecurityConfig
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
public SecurityWithoutCsrfConfig() {
super();
}
// Submits the KeycloakAuthenticationProvider to the AuthenticationManager
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
// Specifies the session authentication strategy
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Override
public void configure(final WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**",
"/v2/api-docs",
"/swagger-ui.html",
"/swagger2-ui.html",
"/springfox/**",
"/v2/swagger.json",
"/_twilio/**",
"/webjars/**",
"/configuration/**",
"/swagger-resources/**");
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/mypath/**").hasAnyRole("USER")
.antMatchers("/mypath_admin/**").hasAnyRole("USER_ADMIN", "ADMIN")
.anyRequest().fullyAuthenticated()
.and().httpBasic();
http.headers().cacheControl();
}
WebConfig
public class WebConfig extends WebMvcConfigurerAdapter {
/**
* Adds Cross Origin Resource Sharing filter
* @return CorsFilter
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
For case 2 i encounter problems with the allowed origin headers. My haproxy config is standard setup you would find on any of the official haproxy site. Any solutions or suggestions to the above is much appreciated... Preferably a solution to the http status on the preflight response.
To debug the situation fuuther I added a logger to the configure method in my securityconfig class, as this is where I suspected the requests were breaking down
LOG.info(" --executing: configure(HttpSecurity)");
The factI had a logger in this class now meant that more config details would be printed to the output of the application, so I built the jar, copied it to the server and ran my jar file. When I reloaded the request that originally gave me the cors error (http okay status not present on pre-flight) the logs printed out an SSL handshake exception, this told me that somewhere in my app configuration it was set to only expect connections via https or a secure port. However this was not the case, I was using haproxy exposed on a secure port, forwarding the connections to the port the jar was listening on (8080). So I double checked all of the configs for security throughout the app, and in my application properties I discovered I had the wrong setting for
keycloak.ssl-required=all
So I removed this setting, deployed the app and voila, issue averted. Hope this comes in as a help to anyone who has similar issues.