Problem
If we use webmvc version of gateway we have ProxyExchange object that forwards the requests to downstream. It removes two headers "cookie" and "authorization" as default. If we compare this behavior with simple yaml routes config - nothing is removed and all sent to downstream as-is.
I have a downstream service that needs basic authentication, and intentionally I don't want (in this case) to do anything in gateway and trying to simply delegate request to downstream. But I want to use webmvc way of gateway because I need to manipulate a bit on response.
Describe the solution you'd like
At the moment ProxyExchange.DEFAULT_SENSITIVES is public. That means you do expect people to play with it. I made it work by removing the "authorization" from the map.
But it looks ugly. public static access outside (not nice).
I was expecting ProxyExchange defaults to be overridden by config. Like ZUUL we can set our own defined list of sensitive headers. Spring Cloud Gateway just adds sensitive headers from config on top of existing defaults.
Describe alternatives you've considered
I have used public access...
But thinking to configure other way and use filters to play with response.
Additional context
IMO - Both ways we should have same behavior. If there is a need to remove default sensitives then why just ProxyExchange?
There is also ProxyExchange.sensitive()
.
Yes but that is additive on top of defaults.
Using this I cannot say that "authorization" is not sensitive... because that is default sensitive and it will stay sensitive unless I change the default static sensitive list by using public access.
spring.cloud.gateway.proxy.sensitive
I looked at that... it is also using the same method underneath.
ProxyExchange.sensitive
Technically same as calling that method to add more sensitive headers on top of defaults.
I also thought this property should be to define your list of sensitive headers... but this is to add your list of sensitives on top of defaults.
I might be wrong but I can check again the source code of gateway that handles this property...
Bumping this issue
ProxyExchange is created with "sensitive" set to DEFAULT_SENSITIVE (cookie and auth), then there is only a method to add more headers to the list, but no way to remove any
This is exactly I explained to start with.
There should be a way to define own set of sensitive headers like ZUUL we have.
I used proxy with spring-cloud-gateway-mvc for a long time and decided to refactor it to spring-cloud-gateway-webflux. The first thing that stops working is "sensitive" headers manipulation. If compare the source code of ProxyExchange from "mvc" and "webflux" packages the reason can be found quickly.
Working "MVC" class has:
public class ProxyExchange<T> {
public static Set<String> DEFAULT_SENSITIVE = new HashSet(Arrays.asList("cookie", "authorization"));
...
private Set<String> sensitive;
...
public ProxyExchange(RestTemplate rest, NativeWebRequest webRequest, ModelAndViewContainer mavContainer, WebDataBinderFactory binderFactory, Type type) {
this.responseType = type;
this.rest = rest;
this.webRequest = webRequest;
this.mavContainer = mavContainer;
this.binderFactory = binderFactory;
this.delegate = new RequestResponseBodyMethodProcessor(rest.getMessageConverters());
}
Non-working "webflux" code is:
public class ProxyExchange<T> {
public static Set<String> DEFAULT_SENSITIVE = new HashSet(Arrays.asList("cookie", "authorization"));
...
private Set<String> sensitive;
...
public ProxyExchange(WebClient rest, ServerWebExchange exchange, BindingContext bindingContext, Type type) {
this.exchange = exchange;
this.bindingContext = bindingContext;
this.responseType = type;
this.rest = rest;
this.sensitive = new HashSet(DEFAULT_SENSITIVE.size());
this.sensitive.addAll(DEFAULT_SENSITIVE);
this.httpMethod = exchange.getRequest().getMethod();
}
As you can see here default sensitive list is created in the constructor, thus hard-coded and can only be expanded later by adding more headers. You are not able to remove "cookie" or "authentication" from the default list.
In compare to working "mvc" proxy headers are initialized later at the builder:
private BodyBuilder headers(BodyBuilder builder) {
Set<String> sensitive = this.sensitive;
if (sensitive == null) {
sensitive = DEFAULT_SENSITIVE;
}
...
return builder;
}
thus if user doesn't provide sensitive header list - the default ("cookie" and "authorization") is used. If user wants to customize sensitive list he is able to do it. For example by setting spring.cloud.gateway.proxy.sensitive
application configuration property
Webflux proxy has similar piece of code to manipulate sensitive headers list:
public ProxyExchange<T> sensitive(String... names) {
if (this.sensitive == null) {
this.sensitive = new HashSet();
}
}
... but since sensitive variable is already initialized in the constructor and is never null
this predicate never works.
I think this is a bug in PoxyExchange class at org.springframework.cloud.gateway.webflux package. User must have control of the proxy headers. My use case - is proxy for user web session that is implemented using JWT token on backend. I have to "convert" one authentication to another and must replace "cookie" with new "authentication" and pass Bearer token down to web-service. Unfortunately it is not possible with ProxyExchange and Webflux.
Quick workaround at the moment is to use ProxyExchange from MVC package.
Exactly, what I raised to start with. I think I am going to contribute to fix that... More often people finding same issue now, but this is still open ticket.
Thank you, @ilyasjaan for contribution. Let me know if I can help. I am going to fix it locally, but will be waiting for official release to make it available at production
Hello. When this issue be merged with main code? I don't understand where it jammed.
Most helpful comment
I used proxy with spring-cloud-gateway-mvc for a long time and decided to refactor it to spring-cloud-gateway-webflux. The first thing that stops working is "sensitive" headers manipulation. If compare the source code of ProxyExchange from "mvc" and "webflux" packages the reason can be found quickly.
Working "MVC" class has:
Non-working "webflux" code is:
As you can see here default sensitive list is created in the constructor, thus hard-coded and can only be expanded later by adding more headers. You are not able to remove "cookie" or "authentication" from the default list.
In compare to working "mvc" proxy headers are initialized later at the builder:
thus if user doesn't provide sensitive header list - the default ("cookie" and "authorization") is used. If user wants to customize sensitive list he is able to do it. For example by setting
spring.cloud.gateway.proxy.sensitive
application configuration propertyWebflux proxy has similar piece of code to manipulate sensitive headers list:
... but since sensitive variable is already initialized in the constructor and is never
null
this predicate never works.I think this is a bug in PoxyExchange class at org.springframework.cloud.gateway.webflux package. User must have control of the proxy headers. My use case - is proxy for user web session that is implemented using JWT token on backend. I have to "convert" one authentication to another and must replace "cookie" with new "authentication" and pass Bearer token down to web-service. Unfortunately it is not possible with ProxyExchange and Webflux.
Quick workaround at the moment is to use ProxyExchange from MVC package.