Reputation: 647
I really would not put it here but I am really confused, I want to achieve the following.
I am running
Spring Cloud Gateway
version: Hoxton.SR3
Spring Boot
version: 2.2.5.RELEASE
Now I want to integrate security to my Gateway and to all the downstream microservices. Eventually, I decided to go with Firebase as an Identity Provider (IDP). My Angular application will get JWT token from Firebase and send it in every request to Cloud Gateway. So, the Gateway will start to act as a resource server ONLY and that is it.
Here how I tried to give it a go.
Set up and Spring Cloud Gateway
to act like Resource Server at the same time.
Quite well explained here Spring Security Docs.
Here what my configuration looks like
@EnableWebFluxSecurity
public class ResourceServerSecurityConfiguration {
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// @formatter:off
http
.authorizeExchange()
.anyExchange().authenticated()
.and()
.oauth2ResourceServer()
.jwt();
return http.build();
// @formatter:on
}
}
And application.yml
spring:
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: https://www.googleapis.com/service_accounts/v1/jwk/[email protected]
issuer-uri: https://securetoken.google.com/{$app.name}
As you see in this YAML I provided the jwk-set-uri and issuer to validate incoming tokens.
At this point, all work quite as accepted. All the requests have to have valid JWT in the Authentication header.
Next,
I want my gateway to use WebClient
and call several services to aggregate data for the frontend.
Here how I am trying to configure my client.
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder()
.filter(new ServletBearerExchangeFilterFunction());
}
As you see It uses ServletBearerExchangeFilterFunction
this is where my real problem comes in.
I already checked that when Spring configuring oauth2ResourceServer it uses NoOpServerSecurityContextRepository
. From what I understand so far that this is exactly a repository that used to register context per request. Also, I understand that it makes sense to use NoOp as we want to be stateless. However what I do not understand how to make ServletBearerExchangeFilterFunction
to work properly and pass downstream my tokens.
I spend now quite a lot of time trying to figure out the correct way of doing this.
Found this: Spring Boot 2 OIDC (OAuth2) client / resource server not propagating the access token in the WebClient
Github: https://github.com/spring-projects/spring-security/issues/7771
And even according to this what I try to do should be legit and possible. Not sure where I am mistaken.
Upvotes: 2
Views: 13684
Reputation: 647
I figured this, the thing is that ReactiveSecurityContext is available only when you are within the reactive flow and ServletBearerExchangeFilterFunction meant to be for Servlet calls.
Eventually, I just wrote my own filter function which listens to ReactiveSecurity context and sets the Authorization header. Here it is.
public class BearerExchangeFilterFunction implements ExchangeFilterFunction {
@Override
@NonNull
public Mono<ClientResponse> filter(@NonNull ClientRequest request, ExchangeFunction next) {
return ReactiveSecurityContextHolder.getContext()
.map(c -> (c.getAuthentication().getCredentials()))
.cast(AbstractOAuth2Token.class)
.checkpoint()
.map(token -> bearer(request, token))
.defaultIfEmpty(request)
.flatMap(next::exchange);
}
private ClientRequest bearer(ClientRequest request, AbstractOAuth2Token token) {
return ClientRequest.from(request)
.headers(headers -> headers.setBearerAuth(token.getTokenValue()))
.build();
}
}
Upvotes: 3
Reputation:
Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.
If you set up SCG(Spring Cloud Gateway) as oauth2 resource server you must do more custom,Maybe like this. I think you should not do that.
You can use gateway use as route,and send access token header to SCG,and SCG will take access token to oauth2 resource server,and check permission on oauth2 resource server side.
Spring Cloud Gateway Token Relay GatewayFilter Factory say:
The {githubmaster}/src/main/java/org/springframework/cloud/gateway/security/TokenRelayGatewayFilterFactory.java[filter] extracts an access token from the currently authenticated user, and puts it in a request header for the downstream requests.
So that can keep oauth2 clearness in you app.
Upvotes: 1