spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

Unable to use X-Forwarded-Prefix

Open Saljack opened this issue 1 year ago • 9 comments

Describe the bug I think that I have a normal widespread use case of Spring Cloud Gateway (WebFlux version) with a combination of proxy (ingress). I have a proxy (Nginx ingress in Kubernetes) that has a path prefix /api. This prefix is removed from the path and sent as X-Forwarded-Prefix to SCG. SCG has routes without this prefix and striping the next prefix which is an id of another service. See SCG configuration:

spring
  cloud:
    gateway:
      routes:
      - id: users
        uri: http://localhost:8089
        predicates:
          - Path= /users/**
        filters:
          - StripPrefix=1

Then another services (Spring Boot applications) maps the path without these two prefixes e.g. @GetMapping("/foo").

So I have an url /api/users/foo

User /api/users/foo => proxy /users/foo + X-Forwarded-Prefix: /api => SCG /foo + X-Forwarded-Prefix: /api,/users => service SCG X-Forwarded-Prefix

I used server.forward-headers-strategy: NATIVE but the last release updated Reactor Netty that supports X-Forwarded-Prefix https://github.com/reactor/reactor-netty/pull/3436 and it totally broke my configuration.

I would expect that setting server.forward-headers-strategy to NATIVE or FRAMEWORK does not affect routing matching. So if I have the route with the predicate /users it would ignore everything from X-Forwarded-Prefix. But it is not right now. Currently, if there is the forwarded headers strategy then also the matching predicate must contain the prefix /api/users. It looks like it is similar to this ticket https://github.com/spring-projects/spring-framework/issues/25270#issuecomment-654411776 where WebFlux behaved differently for mapping annotations and router functions but it was already fixed and aligned.

The whole problem is with the unsupported context path (base path) in SCG WebFlux https://github.com/spring-cloud/spring-cloud-gateway/issues/1759 because ForwardedHeaderTransformer sets X-Forwarded-Prefix to contextPath. Then there is also a problem with some filters that are not able to strip the context path: https://github.com/spring-cloud/spring-cloud-gateway/issues/1935

I need to set server.forward-headers-strategy because of Spring Security and correct redirections (in my case I use OAuth2 Login). So I tried these configuration for this properties and none of them worked:

  • NONE - SCG works but Spring Security redirecting does not work and error responses from SCG do not contain the correct path (because the header is not processed). It correctly sends an additional X-Forwarded-Prefix that was striped by the strip prefix filter.
  • FRAMEWORK - I had to change routing predicates and add the prefix and also use custom strip prefix filter with support of removing contextPath
  • NATIVE - similar to FRAMEWORK but Spring Security does not handle redirects (it is not issue in SCG) so it is unusable.

Sample If possible, please provide a test case or sample application that reproduces the problem. This makes it much easier for us to diagnose the problem and to verify that we have fixed it.

Saljack avatar Dec 10 '24 11:12 Saljack

The whole problem is with the unsupported context path (base path) in SCG WebFlux https://github.com/spring-cloud/spring-cloud-gateway/issues/1759 because ForwardedHeaderTransformer sets X-Forwarded-Prefix to contextPath. Then there is also a problem with some filters that are not able to strip the context path: https://github.com/spring-cloud/spring-cloud-gateway/issues/1935

So, can I close this as duplicates of those others?

spencergibb avatar Dec 10 '24 15:12 spencergibb

I would not close it. I see three issues connected to contextPath:

  • Unsupported base path https://github.com/spring-cloud/spring-cloud-gateway/issues/1759
  • Unsupported contextPath in filters https://github.com/spring-cloud/spring-cloud-gateway/issues/1935
  • Problems with X-Forwarded-Prefix this issue

All of them can be (more or less) superseded by a new ticket with support contextPath and aligning SCG WebFlux with MVC (I have not tested it yet but I think SCG MVC would work with contextPath). Without the support of contextPath is SCG very limited in these use cases. Or is my setup something uncommon and other developers do not strip any prefix on their proxy? I do not think so.

I would like to help with it but you have already claimed https://github.com/spring-cloud/spring-cloud-gateway/issues/1759#issuecomment-653073449 that you do not want to support it. And I am not sure that I am able to see all possible problems.

Saljack avatar Dec 11 '24 13:12 Saljack

I'm facing similar problem on the Gateway. x-forwarded-prefix header is not sent anymore since the upgrade: Spring Boot - 3.4.5 to 3.5.5 Cloud Release Train - 2024.0.0 to 2025.0.0

I have tested configs to force this, but nothing works. Like: spring.cloud.gateway.forwarded-headers-strategy=framework spring.cloud.gateway.server.webmvc.x-forwarded.prefix-enabled=true spring.cloud.gateway.x-forwarded.prefix-enabled=true

It was required to revert the image to previous version since this is critical. Now we have to live with existing CVEs in the old version.

EDIT: Request is re-write with some code. .route("xxx", r -> r .path("/prefix/**") .filters(f -> f.rewritePath("/prefix/", "/") .removeRequestHeader(EXPECT) ) .uri(apiUri) )

shumy avatar Sep 29 '25 15:09 shumy

I'm facing similar problem on the Gateway. x-forwarded-prefix header is not sent anymore since the upgrade: Spring Boot - 3.4.5 to 3.5.5 Cloud Release Train - 2024.0.0 to 2025.0.0

I have tested configs to force this, but nothing works. Like: spring.cloud.gateway.forwarded-headers-strategy=framework spring.cloud.gateway.server.webmvc.x-forwarded.prefix-enabled=true spring.cloud.gateway.x-forwarded.prefix-enabled=true

It was required to revert the image to previous version since this is critical. Now we have to live with existing CVEs in the old version.

EDIT: Request is re-write with some code. .route("xxx", r -> r .path("/prefix/**") .filters(f -> f.rewritePath("/prefix/", "/") .removeRequestHeader(EXPECT) ) .uri(apiUri) )

@shumy

Have you tried setting the spring.cloud.gateway.server.webflux.trusted-proxies? It did the trick for me.

Source: https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webflux/httpheadersfilters.html#xforwarded-headers-filter

surfinbird avatar Sep 30 '25 10:09 surfinbird

@surfinbird I don't have the exact same config. The Nginx is not in my architecture. I suppose the trusted-proxies proxies are for that?

shumy avatar Sep 30 '25 14:09 shumy

@shumy I don't know what it is for, but the docs says that "To activate this filter (that is the XForwarded Headers Filter) set the spring.cloud.gateway.server.webflux.trusted-proxies property to a Java Regular Expression". If you set it to ".*" it should allow all.

surfinbird avatar Sep 30 '25 17:09 surfinbird

@surfinbird Set to spring.cloud.gateway.server.webflux.trusted-proxies=".*" Didn't work.

shumy avatar Oct 01 '25 10:10 shumy

@shumy if you're using mvc and not webflux you must probably use the equivalent property for mvc: spring.cloud.gateway.server.webmvc.trusted-proxies

https://docs.spring.io/spring-cloud-gateway/reference/spring-cloud-gateway-server-webmvc/httpheadersfilters.html#xforwarded-headers-filter

surfinbird avatar Oct 01 '25 12:10 surfinbird

@surfinbird Same for spring.cloud.gateway.server.webmvc.trusted-proxies=".*" This is broken on 3.5.5

shumy avatar Oct 01 '25 14:10 shumy