From 3bc2267f32016604a6630d8ebadbeabc1e4bd151 Mon Sep 17 00:00:00 2001 From: Jaime Sanchez Date: Wed, 2 Apr 2025 14:28:00 +0200 Subject: [PATCH 1/4] Support token relay clientRegistrationId on properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jaime Sánchez --- .../filters/tokenrelay.adoc | 34 ++++++++----------- .../mvc/filter/TokenRelayFilterFunctions.java | 1 + 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/tokenrelay.adoc b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/tokenrelay.adoc index 086bd3eb..ae975662 100644 --- a/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/tokenrelay.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-gateway-server-webmvc/filters/tokenrelay.adoc @@ -6,25 +6,27 @@ forwards the incoming token to outgoing resource requests. The consumer can be a pure Client (like an SSO application) or a Resource Server. -//// -TODO: support TokenRelay clientRegistrationId Spring Cloud Gateway Server MVC can forward OAuth2 access tokens downstream to the services it is proxying using the `TokenRelay` filter. The `TokenRelay` filter takes one optional parameter, `clientRegistrationId`. The following example configures a `TokenRelay` filter: -.App.java +.RouteConfiguration.java [source,java] ---- -@Bean -public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { - return builder.routes() - .route("resource", r -> r.path("/resource") - .filters(f -> f.tokenRelay("myregistrationid")) - .uri("http://localhost:9000")) +@Configuration +class RouteConfiguration { + + @Bean + public RouterFunction gatewayRouterFunctionsTokenRelay() { + return route("resource") + .GET("/resource", http()) + .before(uri("https://localhost:9000")) + .filter(tokenRelay("myregistrationid")) .build(); + } } ---- @@ -46,19 +48,13 @@ spring: ---- The example above specifies a `clientRegistrationId`, which can be used to obtain and forward an OAuth2 access token for any available `ClientRegistration`. -//// Spring Cloud Gateway Server MVC can forward the OAuth2 access token of the currently authenticated user `oauth2Login()` is used to authenticate the user. -//To add this functionality to the gateway, you can omit the `clientRegistrationId` parameter like this: +To add this functionality to the gateway, you can omit the `clientRegistrationId` parameter like this: .RouteConfiguration.java [source,java] ---- -import static org.springframework.cloud.gateway.server.mvc.filter.BeforeFilterFunctions.uri; -import static org.springframework.cloud.gateway.server.mvc.filter.TokenRelayFilterFunctions.tokenRelay; -import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route; -import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http; - @Configuration class RouteConfiguration { @@ -100,9 +96,9 @@ To enable this for Spring Cloud Gateway Server MVC add the following dependencie - `org.springframework.boot:spring-boot-starter-oauth2-client` How does it work? -// The filter extracts an OAuth2 access token from the currently authenticated user for the provided `clientRegistrationId`. -// If no `clientRegistrationId` is provided, -The currently authenticated user's own access token (obtained during login) is used and the extracted access token is placed in a request header for the downstream requests. +The filter extracts an OAuth2 access token from the currently authenticated user for the provided `clientRegistrationId`. +If no `clientRegistrationId` is provided, +the currently authenticated user's own access token (obtained during login) is used and the extracted access token is placed in a request header for the downstream requests. //For a full working sample see https://github.com/spring-cloud-samples/sample-gateway-oauth2login[this project]. diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/TokenRelayFilterFunctions.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/TokenRelayFilterFunctions.java index d2d20a07..c137d602 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/TokenRelayFilterFunctions.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/TokenRelayFilterFunctions.java @@ -39,6 +39,7 @@ public abstract class TokenRelayFilterFunctions { return tokenRelay(null); } + @Shortcut public static HandlerFilterFunction tokenRelay(String defaultClientRegistrationId) { return (request, next) -> { Authentication principal = (Authentication) request.servletRequest().getUserPrincipal(); From 633c9046874d6e770bc3ed54509a20288b1e2f0f Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Thu, 29 May 2025 11:32:39 -0400 Subject: [PATCH 2/4] Add test for token relay configuration --- spring-cloud-gateway-server-mvc/pom.xml | 10 ++ .../server/mvc/ServerMvcIntegrationTests.java | 61 ++++++++---- .../mvc/VanillaRouterFunctionTests.java | 6 +- .../config/FunctionHandlerConfigTests.java | 3 + ...ropertiesBeanDefinitionRegistrarTests.java | 3 + .../mvc/config/StreamHandlerConfigTests.java | 3 + .../mvc/config/TokenRelayConfigTests.java | 97 +++++++++++++++++++ .../mvc/filter/AfterFilterFunctionsTests.java | 3 + .../mvc/filter/BodyFilterFunctionsTests.java | 3 + .../mvc/filter/RetryFilterFunctionTests.java | 3 + .../filter/StripPrefixStaticPortTests.java | 3 + ...eightRequestPredicateIntegrationTests.java | 3 + .../DefaultRouteFunctionHandlerTests.java | 3 + .../mvc/handler/FunctionHandlerTests.java | 3 + .../mvc/handler/StreamHandlerTests.java | 3 + .../test/PermitAllSecurityConfiguration.java | 37 +++++++ .../test/resources/application-tokenrelay.yml | 13 +++ 17 files changed, 237 insertions(+), 20 deletions(-) create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/PermitAllSecurityConfiguration.java create mode 100644 spring-cloud-gateway-server-mvc/src/test/resources/application-tokenrelay.yml diff --git a/spring-cloud-gateway-server-mvc/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 01c47d60..c44dada5 100644 --- a/spring-cloud-gateway-server-mvc/pom.xml +++ b/spring-cloud-gateway-server-mvc/pom.xml @@ -104,6 +104,16 @@ spring-boot-testcontainers test + + org.springframework.boot + spring-boot-starter-security + test + + + org.springframework.security + spring-security-test + test + org.springframework.cloud spring-cloud-starter-stream-rabbit diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index 4efa9b8c..51f4145e 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java @@ -40,6 +40,7 @@ import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import org.assertj.core.api.Assertions; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -61,10 +62,13 @@ import org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPred import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.HttpbinUriResolver; import org.springframework.cloud.gateway.server.mvc.test.LocalServerPortUriResolver; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Lazy; import org.springframework.core.Ordered; import org.springframework.core.io.ClassPathResource; import org.springframework.http.HttpEntity; @@ -83,10 +87,12 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import org.springframework.web.servlet.function.HandlerFunction; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.cloud.gateway.server.mvc.filter.AfterFilterFunctions.DedupeStrategy.RETAIN_FIRST; @@ -142,12 +148,15 @@ import static org.springframework.web.servlet.function.RequestPredicates.POST; import static org.springframework.web.servlet.function.RequestPredicates.path; @SuppressWarnings("unchecked") -@SpringBootTest(properties = { "spring.http.client.factory=jdk", "spring.cloud.gateway.function.enabled=false" }, - webEnvironment = WebEnvironment.RANDOM_PORT) +@SpringBootTest(properties = { "spring.http.client.factory=jdk", "spring.cloud.gateway.function.enabled=false", + "logging.level.org.springframework.security=TRACE" }, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = HttpbinTestcontainers.class) @ExtendWith(OutputCaptureExtension.class) public class ServerMvcIntegrationTests { + public static final MediaType FORM_URL_ENCODED_CONTENT_TYPE = new MediaType(APPLICATION_FORM_URLENCODED, + StandardCharsets.UTF_8); + static { // if set type to autodetect above System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); @@ -162,6 +171,12 @@ public class ServerMvcIntegrationTests { @Autowired TestRestClient restClient; + private static boolean isPNG(byte[] bytes) { + byte[] pngSignature = { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; + byte[] header = Arrays.copyOf(bytes, pngSignature.length); + return Arrays.equals(pngSignature, header); + } + @Test public void nonGatewayRouterFunctionWorks() { restClient.get().uri("/hello").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello"); @@ -317,7 +332,7 @@ public class ServerMvcIntegrationTests { .isEqualTo(HttpStatus.TOO_MANY_REQUESTS) .expectHeader() .valueEquals("x-status", "201"); // .expectBody(String.class).isEqualTo("Failed - // with 201"); + // with 201"); } @Test @@ -588,9 +603,6 @@ public class ServerMvcIntegrationTests { .isOk(); } - public static final MediaType FORM_URL_ENCODED_CONTENT_TYPE = new MediaType(APPLICATION_FORM_URLENCODED, - StandardCharsets.UTF_8); - @Test void formUrlencodedWorks() { LinkedMultiValueMap formData = new LinkedMultiValueMap<>(); @@ -671,12 +683,6 @@ public class ServerMvcIntegrationTests { } } - private static boolean isPNG(byte[] bytes) { - byte[] pngSignature = { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; - byte[] header = Arrays.copyOf(bytes, pngSignature.length); - return Arrays.equals(pngSignature, header); - } - @Test public void removeRequestHeaderWorks() { restClient.get() @@ -1027,6 +1033,8 @@ public class ServerMvcIntegrationTests { @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) protected static class TestConfiguration { + @Import(PermitAllSecurityConfiguration.class) + protected static class TestConfiguration extends WebMvcConfigurationSupport { @Bean StaticPortController staticPortController() { @@ -1043,6 +1051,23 @@ public class ServerMvcIntegrationTests { return new EventController(); } + // TODO This is needed to work around https://github.com/spring-cloud/spring-cloud-gateway/issues/3816 + // which results from Spring Security being on the classpath. Once we can address this issue we should + // remove this bean and no longer extend WebMvcConfigurationSupport in this configuration class + @Bean + @Lazy + @Override + public @NotNull HandlerMappingIntrospector mvcHandlerMappingIntrospector() { + return new HandlerMappingIntrospector() { + @Override + public @NotNull Filter createCacheFilter() { + return (request, response, chain) -> { + chain.doFilter(request, response); + }; + } + }; + } + @Bean public AsyncProxyManager caffeineProxyManager() { Caffeine builder = (Caffeine) Caffeine.newBuilder().maximumSize(100); @@ -1667,6 +1692,12 @@ public class ServerMvcIntegrationTests { private static class MyFilter implements Filter, Ordered { + static boolean isFormPost(HttpServletRequest request) { + String contentType = request.getContentType(); + return (contentType != null && contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE) + && HttpMethod.POST.matches(request.getMethod())); + } + @Override public int getOrder() { return FormFilter.FORM_FILTER_ORDER - 1; @@ -1689,12 +1720,6 @@ public class ServerMvcIntegrationTests { } } - static boolean isFormPost(HttpServletRequest request) { - String contentType = request.getContentType(); - return (contentType != null && contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE) - && HttpMethod.POST.matches(request.getMethod())); - } - } protected record Hello(String message) { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java index 81d1128c..4d22c81e 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/VanillaRouterFunctionTests.java @@ -29,10 +29,12 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.HttpbinUriResolver; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.RouterFunctions; @@ -43,8 +45,7 @@ import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFuncti import static org.springframework.cloud.gateway.server.mvc.predicate.GatewayRequestPredicates.host; @SuppressWarnings("unchecked") -@SpringBootTest(properties = { "spring.http.client.factory=jdk" }, - webEnvironment = WebEnvironment.RANDOM_PORT) +@SpringBootTest(properties = { "spring.http.client.factory=jdk" }, webEnvironment = WebEnvironment.RANDOM_PORT) @ContextConfiguration(initializers = HttpbinTestcontainers.class) public class VanillaRouterFunctionTests { @@ -73,6 +74,7 @@ public class VanillaRouterFunctionTests { @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java index 779bc5bd..a1c4e671 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/FunctionHandlerConfigTests.java @@ -26,8 +26,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.ActiveProfiles; @@ -78,6 +80,7 @@ public class FunctionHandlerConfigTests { @SpringBootConfiguration @EnableAutoConfiguration + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcPropertiesBeanDefinitionRegistrarTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcPropertiesBeanDefinitionRegistrarTests.java index f0d34697..fef64b4b 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcPropertiesBeanDefinitionRegistrarTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcPropertiesBeanDefinitionRegistrarTests.java @@ -34,11 +34,13 @@ import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.cloud.context.refresh.ContextRefresher; import org.springframework.cloud.gateway.server.mvc.common.MvcUtils; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Import; import org.springframework.core.io.Resource; import org.springframework.http.HttpMethod; import org.springframework.test.context.ActiveProfiles; @@ -230,6 +232,7 @@ public class GatewayMvcPropertiesBeanDefinitionRegistrarTests { @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + @Import(PermitAllSecurityConfiguration.class) static class Config { } diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/StreamHandlerConfigTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/StreamHandlerConfigTests.java index 5227cc70..2c49d22e 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/StreamHandlerConfigTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/StreamHandlerConfigTests.java @@ -31,8 +31,10 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.ActiveProfiles; @@ -88,6 +90,7 @@ public class StreamHandlerConfigTests { @SpringBootConfiguration @EnableAutoConfiguration + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java new file mode 100644 index 00000000..86e8c222 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java @@ -0,0 +1,97 @@ +/* + * Copyright 2013-2025 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.server.mvc.config; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.TestAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.http.HttpHeaders; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; +import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * @author Ryan Baxter + */ +@SpringBootTest(webEnvironment = RANDOM_PORT) +@ContextConfiguration(initializers = HttpbinTestcontainers.class) +@ActiveProfiles("tokenrelay") +public class TokenRelayConfigTests { + + @Autowired + private WebApplicationContext context; + + private MockMvc mvc; + + @BeforeEach + public void setup() { + mvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build(); + } + + @Test + @WithMockUser + public void testTokenRelay() throws Exception { + mvc.perform(get("/bearer")) + .andExpect(status().isOk()) + .andExpect(content().json("{\"authenticated\": true, \"token\": \"test\"}")); + } + + @EnableAutoConfiguration + @SpringBootConfiguration + @Import(TestAutoConfiguration.class) + public static class TestConfig { + + @Bean + public OAuth2AuthorizedClientManager authorizedClientManager() { + OAuth2AuthorizedClientManager manager = mock(OAuth2AuthorizedClientManager.class); + OAuth2AuthorizedClient client = mock(OAuth2AuthorizedClient.class); + OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class); + when(accessToken.getTokenValue()).thenReturn("test"); + when(client.getAccessToken()).thenReturn(accessToken); + // The client registration id is set in the token relay filter and must match + when(manager.authorize(argThat( + oAuth2AuthorizeRequest -> "token".equals(oAuth2AuthorizeRequest.getClientRegistrationId())))) + .thenReturn(client); + return manager; + } + + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java index cbb6e0a6..d498544f 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/AfterFilterFunctionsTests.java @@ -27,10 +27,12 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.HttpbinUriResolver; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -117,6 +119,7 @@ class AfterFilterFunctionsTests { @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BodyFilterFunctionsTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BodyFilterFunctionsTests.java index 9479d7fc..180772ac 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BodyFilterFunctionsTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/BodyFilterFunctionsTests.java @@ -26,10 +26,12 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.HttpbinUriResolver; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.web.servlet.function.RouterFunction; @@ -84,6 +86,7 @@ public class BodyFilterFunctionsTests { @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java index d93dfc57..80f29f29 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/RetryFilterFunctionTests.java @@ -32,10 +32,12 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.LocalServerPortUriResolver; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.core.log.LogMessage; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -96,6 +98,7 @@ public class RetryFilterFunctionTests { @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/StripPrefixStaticPortTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/StripPrefixStaticPortTests.java index 4052a3f6..2ef865cd 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/StripPrefixStaticPortTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/StripPrefixStaticPortTests.java @@ -27,10 +27,12 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.TestLoadBalancerConfig; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -108,6 +110,7 @@ public class StripPrefixStaticPortTests { @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/WeightRequestPredicateIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/WeightRequestPredicateIntegrationTests.java index a962711d..7e5070a8 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/WeightRequestPredicateIntegrationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/filter/WeightRequestPredicateIntegrationTests.java @@ -26,8 +26,10 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.HttpbinUriResolver; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.HttpHeaders; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; @@ -90,6 +92,7 @@ public class WeightRequestPredicateIntegrationTests { @EnableAutoConfiguration @SpringBootConfiguration + @Import(PermitAllSecurityConfiguration.class) public static class TestConfig { public TestConfig(WeightCalculatorFilter filter) { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultRouteFunctionHandlerTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultRouteFunctionHandlerTests.java index 14f7c956..b6fa8278 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultRouteFunctionHandlerTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/DefaultRouteFunctionHandlerTests.java @@ -27,8 +27,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import static org.assertj.core.api.Assertions.assertThat; @@ -96,6 +98,7 @@ public class DefaultRouteFunctionHandlerTests { @SpringBootConfiguration @EnableAutoConfiguration + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { static boolean consumerInvoked; diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java index c2090807..8d1e05a3 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/FunctionHandlerTests.java @@ -26,8 +26,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.ServerResponse; @@ -81,6 +83,7 @@ public class FunctionHandlerTests { @SpringBootConfiguration @EnableAutoConfiguration + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/StreamHandlerTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/StreamHandlerTests.java index aa89417d..b189ffc8 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/StreamHandlerTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/handler/StreamHandlerTests.java @@ -31,8 +31,10 @@ import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.cloud.gateway.server.mvc.test.PermitAllSecurityConfiguration; import org.springframework.cloud.gateway.server.mvc.test.client.TestRestClient; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.ServerResponse; @@ -90,6 +92,7 @@ public class StreamHandlerTests { @SpringBootConfiguration @EnableAutoConfiguration + @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration { @Bean diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/PermitAllSecurityConfiguration.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/PermitAllSecurityConfiguration.java new file mode 100644 index 00000000..fec4fc6a --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/test/PermitAllSecurityConfiguration.java @@ -0,0 +1,37 @@ +/* + * Copyright 2013-2025 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.server.mvc.test; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.SecurityFilterChain; + +/** + * @author Ryan Baxter + */ +@Configuration(proxyBeanMethods = false) +public class PermitAllSecurityConfiguration { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll()).csrf(AbstractHttpConfigurer::disable); + return http.build(); + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/resources/application-tokenrelay.yml b/spring-cloud-gateway-server-mvc/src/test/resources/application-tokenrelay.yml new file mode 100644 index 00000000..ad8c1046 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/resources/application-tokenrelay.yml @@ -0,0 +1,13 @@ +spring: + cloud.gateway.server.webmvc.routes: + - id: default_route + uri: https://examplel2.com + predicates: + - Path=/** + filters: + - HttpbinUriResolver= + - TokenRelay=token + - AddResponseHeader=X-Route,weight_high_test +logging: + level: + org.springframework.cloud.gateway.server.mvc: TRACE From a0bf89c54bcde70b05337b6890a23d20926c17ed Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Thu, 29 May 2025 11:33:29 -0400 Subject: [PATCH 3/4] Update ServerMvcIntegrationTests.java --- .../cloud/gateway/server/mvc/ServerMvcIntegrationTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index 51f4145e..7cf533cf 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java @@ -1032,7 +1032,6 @@ public class ServerMvcIntegrationTests { @SpringBootConfiguration @EnableAutoConfiguration @LoadBalancerClient(name = "httpbin", configuration = TestLoadBalancerConfig.Httpbin.class) - protected static class TestConfiguration { @Import(PermitAllSecurityConfiguration.class) protected static class TestConfiguration extends WebMvcConfigurationSupport { From 03b0f4ecfe47caebe1de567e5f938da2b1571d3b Mon Sep 17 00:00:00 2001 From: Ryan Baxter Date: Tue, 3 Jun 2025 11:09:35 -0400 Subject: [PATCH 4/4] Fixing checkstyle --- .../GatewayMvcRuntimeHintsProcessor.java | 2 +- .../server/mvc/ServerMvcIntegrationTests.java | 35 +++++++++---------- .../mvc/config/TokenRelayConfigTests.java | 1 - 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java index 7dd037c6..d9075b4d 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/config/GatewayMvcRuntimeHintsProcessor.java @@ -33,8 +33,8 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContrib import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions; import org.springframework.cloud.gateway.server.mvc.filter.FilterAutoConfiguration; +import org.springframework.cloud.gateway.server.mvc.filter.FilterFunctions; import org.springframework.cloud.gateway.server.mvc.predicate.PredicateAutoConfiguration; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AssignableTypeFilter; diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java index 7cf533cf..2332d5ca 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/ServerMvcIntegrationTests.java @@ -40,7 +40,6 @@ import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import org.assertj.core.api.Assertions; -import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -154,9 +153,6 @@ import static org.springframework.web.servlet.function.RequestPredicates.path; @ExtendWith(OutputCaptureExtension.class) public class ServerMvcIntegrationTests { - public static final MediaType FORM_URL_ENCODED_CONTENT_TYPE = new MediaType(APPLICATION_FORM_URLENCODED, - StandardCharsets.UTF_8); - static { // if set type to autodetect above System.setProperty("sun.net.http.allowRestrictedHeaders", "true"); @@ -171,12 +167,6 @@ public class ServerMvcIntegrationTests { @Autowired TestRestClient restClient; - private static boolean isPNG(byte[] bytes) { - byte[] pngSignature = { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; - byte[] header = Arrays.copyOf(bytes, pngSignature.length); - return Arrays.equals(pngSignature, header); - } - @Test public void nonGatewayRouterFunctionWorks() { restClient.get().uri("/hello").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("Hello"); @@ -603,6 +593,9 @@ public class ServerMvcIntegrationTests { .isOk(); } + private static final MediaType FORM_URL_ENCODED_CONTENT_TYPE = new MediaType(APPLICATION_FORM_URLENCODED, + StandardCharsets.UTF_8); + @Test void formUrlencodedWorks() { LinkedMultiValueMap formData = new LinkedMultiValueMap<>(); @@ -683,6 +676,12 @@ public class ServerMvcIntegrationTests { } } + private static boolean isPNG(byte[] bytes) { + byte[] pngSignature = { (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; + byte[] header = Arrays.copyOf(bytes, pngSignature.length); + return Arrays.equals(pngSignature, header); + } + @Test public void removeRequestHeaderWorks() { restClient.get() @@ -1056,10 +1055,10 @@ public class ServerMvcIntegrationTests { @Bean @Lazy @Override - public @NotNull HandlerMappingIntrospector mvcHandlerMappingIntrospector() { + public HandlerMappingIntrospector mvcHandlerMappingIntrospector() { return new HandlerMappingIntrospector() { @Override - public @NotNull Filter createCacheFilter() { + public Filter createCacheFilter() { return (request, response, chain) -> { chain.doFilter(request, response); }; @@ -1691,12 +1690,6 @@ public class ServerMvcIntegrationTests { private static class MyFilter implements Filter, Ordered { - static boolean isFormPost(HttpServletRequest request) { - String contentType = request.getContentType(); - return (contentType != null && contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE) - && HttpMethod.POST.matches(request.getMethod())); - } - @Override public int getOrder() { return FormFilter.FORM_FILTER_ORDER - 1; @@ -1719,6 +1712,12 @@ public class ServerMvcIntegrationTests { } } + static boolean isFormPost(HttpServletRequest request) { + String contentType = request.getContentType(); + return (contentType != null && contentType.contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE) + && HttpMethod.POST.matches(request.getMethod())); + } + } protected record Hello(String message) { diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java index 86e8c222..ee293289 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java @@ -27,7 +27,6 @@ import org.springframework.cloud.gateway.server.mvc.test.HttpbinTestcontainers; import org.springframework.cloud.gateway.server.mvc.test.TestAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.http.HttpHeaders; import org.springframework.security.oauth2.client.OAuth2AuthorizedClient; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; import org.springframework.security.oauth2.core.OAuth2AccessToken;