Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

keycloak CORS filter spring boot

I am using keycloak to secure my rest service. I am refering to the tutorial given here. I created the rest and front end. Now when I add keycloak on the backend I get CORS error when my front end makes api call.

Application.java file in spring boot looks like

@SpringBootApplication
public class Application 
{
    public static void main( String[] args )
    {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public WebMvcConfigurer corsConfiguration() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/*")
                        .allowedMethods(HttpMethod.GET.toString(), HttpMethod.POST.toString(),
                                HttpMethod.PUT.toString(), HttpMethod.DELETE.toString(), HttpMethod.OPTIONS.toString())
                        .allowedOrigins("*");
            }
        };
    }
} 

The keycloak properties in the application.properties file look like

keycloak.realm = demo
keycloak.auth-server-url = http://localhost:8080/auth
keycloak.ssl-required = external
keycloak.resource = tutorial-backend
keycloak.bearer-only = true
keycloak.credentials.secret = 123123-1231231-123123-1231
keycloak.cors = true
keycloak.securityConstraints[0].securityCollections[0].name = spring secured api
keycloak.securityConstraints[0].securityCollections[0].authRoles[0] = admin
keycloak.securityConstraints[0].securityCollections[0].authRoles[1] = user
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /api/*

The sample REST API that I am calling

@RestController
public class SampleController {    
    @RequestMapping(value ="/api/getSample",method=RequestMethod.GET)
    public string home() {
        return new string("demo");
    }        
}

the front end keycloak.json properties include

{
  "realm": "demo",
  "auth-server-url": "http://localhost:8080/auth",
  "ssl-required": "external",
  "resource": "tutorial-frontend",
  "public-client": true
}

The CORS error that I get

XMLHttpRequest cannot load http://localhost:8090/api/getSample. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 401.
like image 413
krs8888 Avatar asked Dec 14 '16 08:12

krs8888


4 Answers

Try creating your CORS bean like my example. I recently went through the same thing (getting CORS to work) and it was a nightmare because the SpringBoot CORS support is currently not as robust or straightforward as the MVC CORS.

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);

    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;
}

This is how I set it up to accept any origin application-wide, but if you change a few of the parameters you should be able to replicate what you want. ie. if you wanted to add only the methods you mentioned, chain some addAllowedMethod(). Allowed origins would be the same, and then your addMapping("/api/*") would become source.registerCorsConfiguration("/api/*", config);.

Edit:

Spring Data Rest and Cors

Take a look at this. Sebastian is on the Spring engineering team so this is about as good as you're going to get for an official answer.

like image 74
Trevor Bye Avatar answered Nov 05 '22 15:11

Trevor Bye


I know.. the Problem is quite Old. But if you've Problems with the local development with Spring Boot + Keycloak you can use the Config

keycloak.cors=true

in your application.properties.

Cheers :)

like image 5
sti Avatar answered Nov 05 '22 14:11

sti


I came here with the same problem and fix it ommiting authentication for OPTIONS method only, like this:

keycloak.securityConstraints[0].security-collections[0].omitted-methods[0]=OPTIONS

It worked for me because the OPTIONS request Keycloack does, does not include Authentication header.

UPDATE There was something with my browser's cache so I could not see the real impact of a change in my backend code. It looks like what really worked for me was enabling all CORS origins at @RestController level, like this:

@CrossOrigin(origins = "*")
@RestController
public class UsersApi {...}
like image 3
Nelson Garcia Avatar answered Nov 05 '22 15:11

Nelson Garcia


I don't have access to code examples, but based on the code configurations you have included, it looks like a missing configuration is causing spring to exclude CORS headers.

J. West's response is similar to recent issues I encountered with Spring and CORS, I would however caution you to look into which implementation a spring example references, because there are two. Spring Security and Spring MVC Annotations. Both of these implementations work independent of each other, and can not be combined.

When using the filter based approach as you are (even boiled down), the key was to set allow credentials to true, in order for the authentication headers to be sent by the browser across domains. I would also advise using the full code method proposed above, as this will allow you to create a far more configurable web application for deployment across multiple domains or environments by property injection or a service registry.

like image 2
Michael Hibay Avatar answered Nov 05 '22 15:11

Michael Hibay