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/pom.xml b/spring-cloud-gateway-server-mvc/pom.xml index 5203b300..0991c38b 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/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(); 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 3b731d2d..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 @@ -61,10 +61,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 +86,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,8 +147,8 @@ 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 { @@ -317,7 +322,7 @@ public class ServerMvcIntegrationTests { .isEqualTo(HttpStatus.TOO_MANY_REQUESTS) .expectHeader() .valueEquals("x-status", "201"); // .expectBody(String.class).isEqualTo("Failed - // with 201"); + // with 201"); } @Test @@ -1026,7 +1031,8 @@ 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 { @Bean StaticPortController staticPortController() { @@ -1043,6 +1049,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 HandlerMappingIntrospector mvcHandlerMappingIntrospector() { + return new HandlerMappingIntrospector() { + @Override + public Filter createCacheFilter() { + return (request, response, chain) -> { + chain.doFilter(request, response); + }; + } + }; + } + @Bean public AsyncProxyManager caffeineProxyManager() { Caffeine builder = (Caffeine) Caffeine.newBuilder().maximumSize(100); 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 180b3d9a..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; @@ -72,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..ee293289 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/config/TokenRelayConfigTests.java @@ -0,0 +1,96 @@ +/* + * 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.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