Adds remove request param filter.

This removes a request parameter before sending downstream request.

Fixes gh-1137
This commit is contained in:
Thirunavukkarasu Ravichandran
2019-07-14 09:35:09 +02:00
committed by Spencer Gibb
parent 0501c7a1c8
commit c8a693b50a
6 changed files with 308 additions and 0 deletions

View File

@@ -803,6 +803,24 @@ To remove any kind of sensitive header you should configure this filter for any
want to do so. In addition you can configure this filter once using `spring.cloud.gateway.default-filters`
and have it applied to all routes.
=== RemoveRequestParameter GatewayFilter Factory
The RemoveRequestParameter GatewayFilter Factory takes a `name` parameter. It is the name of the query parameter to be removed.
.application.yml
[source,yaml]
----
spring:
cloud:
gateway:
routes:
- id: removerequestparameter_route
uri: https://example.org
filters:
- RemoveRequestParameter=foo
----
This will remove the `foo` parameter before it is sent downstream.
=== RewritePath GatewayFilter Factory
The RewritePath GatewayFilter Factory takes a path `regexp` parameter and a `replacement` parameter. This uses Java regular expressions for a flexible way to rewrite the request path.

View File

@@ -72,6 +72,7 @@ import org.springframework.cloud.gateway.filter.factory.PrefixPathGatewayFilterF
import org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RedirectToGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RemoveRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RemoveRequestParameterGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RemoveResponseHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RequestHeaderToRequestUriGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory;
@@ -440,6 +441,11 @@ public class GatewayAutoConfiguration {
return new RemoveRequestHeaderGatewayFilterFactory();
}
@Bean
public RemoveRequestParameterGatewayFilterFactory removeRequestParameterGatewayFilterFactory() {
return new RemoveRequestParameterGatewayFilterFactory();
}
@Bean
public RemoveResponseHeaderGatewayFilterFactory removeResponseHeaderGatewayFilterFactory() {
return new RemoveResponseHeaderGatewayFilterFactory();

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.gateway.filter.factory;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap;
/**
* @author Thirunavukkarasu Ravichandran
*/
public class RemoveRequestParameterGatewayFilterFactory
extends AbstractGatewayFilterFactory<AbstractGatewayFilterFactory.NameConfig> {
public RemoveRequestParameterGatewayFilterFactory() {
super(NameConfig.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(NAME_KEY);
}
@Override
public GatewayFilter apply(NameConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>(
request.getQueryParams());
queryParams.remove(config.getName());
URI newUri = UriComponentsBuilder.fromUri(request.getURI())
.replaceQueryParams(unmodifiableMultiValueMap(queryParams))
.build(true).toUri();
ServerHttpRequest updatedRequest = exchange.getRequest().mutate()
.uri(newUri).build();
return chain.filter(exchange.mutate().request(updatedRequest).build());
}
@Override
public String toString() {
return filterToStringCreator(
RemoveRequestParameterGatewayFilterFactory.this)
.append("name", config.getName()).toString();
}
};
}
}

View File

@@ -47,6 +47,7 @@ import org.springframework.cloud.gateway.filter.factory.PrefixPathGatewayFilterF
import org.springframework.cloud.gateway.filter.factory.PreserveHostHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RedirectToGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RemoveRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RemoveRequestParameterGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RemoveResponseHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RequestHeaderToRequestUriGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory;
@@ -424,6 +425,17 @@ public class GatewayFilterSpec extends UriSpec {
.apply(c -> c.setName(headerName)));
}
/**
* A filter that will remove a request param before the request is routed by the
* Gateway.
* @param paramName the name of the header to remove
* @return a {@link GatewayFilterSpec} that can be used to apply additional filters
*/
public GatewayFilterSpec removeRequestParameter(String paramName) {
return filter(getBean(RemoveRequestParameterGatewayFilterFactory.class)
.apply(c -> c.setName(paramName)));
}
/**
* A filter that will remove a response header before the Gateway returns the response
* to the client.

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.gateway.filter.factory;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory.NameConfig;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.test.BaseWebClientTests;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
import static org.springframework.cloud.gateway.test.TestUtils.getMap;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
@DirtiesContext
public class RemoveRequestParameterGatewayFilterFactoryIntegrationTests
extends BaseWebClientTests {
@Test
public void removeResponseHeaderFilterWorks() {
testClient.get().uri("/get?foo=bar&baz=bam")
.header("Host", "www.removerequestparamjava.org").exchange()
.expectStatus().isOk().expectBody(Map.class).consumeWith(result -> {
Map<String, Object> params = getMap(result.getResponseBody(), "args");
assertThat(params).doesNotContainKey("foo");
});
}
@Test
public void toStringFormat() {
NameConfig config = new NameConfig();
config.setName("myname");
GatewayFilter filter = new RemoveRequestParameterGatewayFilterFactory()
.apply(config);
assertThat(filter.toString()).contains("myname");
}
@EnableAutoConfiguration
@SpringBootConfiguration
@Import(DefaultTestConfig.class)
public static class TestConfig {
@Value("${test.uri}")
String uri;
@Bean
public RouteLocator testRouteLocator(RouteLocatorBuilder builder) {
return builder.routes().route("removerequestparam_java_test", r -> r
.path("/get").and().host("**.removerequestparamjava.org")
.filters(f -> f.prefixPath("/httpbin").removeRequestParameter("foo"))
.uri(uri)).build();
}
}
}

View File

@@ -0,0 +1,106 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.gateway.filter.factory;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory.NameConfig;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* @author Thirunavukkarasu Ravichandran
*/
public class RemoveRequestParameterGatewayFilterFactoryTests {
private ServerWebExchange exchange;
private GatewayFilterChain filterChain;
private ArgumentCaptor<ServerWebExchange> captor;
@Before
public void setUp() {
filterChain = mock(GatewayFilterChain.class);
captor = ArgumentCaptor.forClass(ServerWebExchange.class);
when(filterChain.filter(captor.capture())).thenReturn(Mono.empty());
}
@Test
public void removeRequestParameterFilterWorks() {
MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost")
.queryParam("foo", singletonList("bar")).build();
exchange = MockServerWebExchange.from(request);
NameConfig config = new NameConfig();
config.setName("foo");
GatewayFilter filter = new RemoveRequestParameterGatewayFilterFactory()
.apply(config);
filter.filter(exchange, filterChain);
ServerHttpRequest actualRequest = captor.getValue().getRequest();
assertThat(actualRequest.getQueryParams()).doesNotContainKey("foo");
}
@Test
public void removeRequestParameterFilterWorksWhenParamIsNotPresentInRequest() {
MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost")
.build();
exchange = MockServerWebExchange.from(request);
NameConfig config = new NameConfig();
config.setName("foo");
GatewayFilter filter = new RemoveRequestParameterGatewayFilterFactory()
.apply(config);
filter.filter(exchange, filterChain);
ServerHttpRequest actualRequest = captor.getValue().getRequest();
assertThat(actualRequest.getQueryParams()).doesNotContainKey("foo");
}
@Test
public void removeRequestParameterFilterShouldOnlyRemoveSpecifiedParam() {
MockServerHttpRequest request = MockServerHttpRequest.get("http://localhost")
.queryParam("foo", "bar").queryParam("abc", "xyz").build();
exchange = MockServerWebExchange.from(request);
NameConfig config = new NameConfig();
config.setName("foo");
GatewayFilter filter = new RemoveRequestParameterGatewayFilterFactory()
.apply(config);
filter.filter(exchange, filterChain);
ServerHttpRequest actualRequest = captor.getValue().getRequest();
assertThat(actualRequest.getQueryParams()).doesNotContainKey("foo");
assertThat(actualRequest.getQueryParams()).containsEntry("abc",
singletonList("xyz"));
}
}