2

I currently want to secure my microservice architecture with a Spring Cloud Gateway. There is FrontEnd which authenticates itself to a Keycloak server and then sends the token with every request. Now it is the case that only the gateway should be exposed to the outside and the individual services will not be accessible from the outside.

How can I validate the bearer token at the keycloak server?

I have searched the internet for some time but have not found anything yet where the token has been validated. Everywhere the authentication was done via the gateway and then the token was validated by the individual services. However, when I declare the gateway as an OAuth2 resource server, the whole thing does not work.

Nimal
  • 149
  • 14
  • in your case, I think it should be the services (your actual resource servers) that validate the token, and not the gateway. In a more traditional scenario of spring oauth2 (Authorization code flow), the gateway should be responsible of generating the token with keycloak and refresh it when needed – Leo G. Sep 08 '21 at 07:50
  • @LeoG. but why would I need to validate it from the actual resource servers when they are not exposed publicly and how do I manage request between these services when there is no active user like when I have service where that run a task every 10 minutes and need data from a different service. – Nimal Sep 08 '21 at 08:40
  • normally it's the role of the resource server to validate and authenticate the user: https://www.oauth.com/oauth2-servers/the-resource-server/ But with a gateway, responsibilites are indeed more difficult to identity. communication service to service can be done with the client-credential flow: https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/ It's supported by Spring Oauth2 and you can find some examples on SO – Leo G. Sep 08 '21 at 08:50
  • @LeoG. thanks I will look at the links later today and will report back – Nimal Sep 08 '21 at 09:35
  • @LeoG. So I get the concept, but I currently don't really know how to implement this. Every tutorial I find uses the gateway to authenticate. But In my case the front end has already done the authentication. Have you any tutorial to my scenario – Nimal Sep 08 '21 at 21:51
  • @Nimal Did you manage to find a way to do this? I'm having the same issue. – Nalyd Sep 22 '21 at 22:05
  • @Nalyd I added my solution as an answer – Nimal Sep 29 '21 at 15:12

1 Answers1

0

I managed to get It to work.

My security config look as follows:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        http.authorizeExchange(exchanges -> exchanges.anyExchange().authenticated())
                .oauth2ResourceServer().jwt();
        http.csrf().disable();
        return http.build();
    }

}

Moreover but don't necessary I added a CorsFilter:

@Configuration
public class PreFlightCorsConfiguration {

    @Bean
    public CorsWebFilter corsFilter() {
        return new CorsWebFilter(corsConfigurationSource());
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
        config.addAllowedMethod( HttpMethod.GET);
        config.addAllowedMethod( HttpMethod.PUT);
        config.addAllowedMethod( HttpMethod.POST);
        config.addAllowedMethod( HttpMethod.OPTIONS);
        config.addAllowedMethod(HttpMethod.DELETE);
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}

And the security dependencys I use are:

  <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-oauth2-client</artifactId>
  </dependency>
  <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
  </dependency>
  <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-security</artifactId>
     <version>2.2.5.RELEASE</version>
  </dependency>
Nimal
  • 149
  • 14
  • Yeah, this is the direction I took too. Out of curiosity, how are you managing role based access to specific endpoints? Because I think not using the keycloak-spring-boot-starter, Spring Security assumes the granted authorities are those contained within "scope" inside the token. – Nalyd Sep 30 '21 at 17:35
  • Actually, this answer and the one above it present a pretty good solution for mapping to granted authorities: https://stackoverflow.com/a/65898374/5468652 – Nalyd Sep 30 '21 at 19:01