Polish "Configure ForwardedHeaderFilter with Tomcat's use relative redirects"

See gh-29333
This commit is contained in:
Andy Wilkinson 2022-02-09 17:27:13 +00:00
parent cec69feb95
commit 64ee54423a
2 changed files with 31 additions and 17 deletions

View File

@ -87,25 +87,21 @@ public class ServletWebServerFactoryAutoConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework") @ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
static class ForwardedHeaderFilterConfiguration { static class ForwardedHeaderFilterConfiguration {
@Bean @Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat") @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class) @ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
public FilterRegistrationBean<ForwardedHeaderFilter> tomcatForwardedHeaderFilter( ForwardedHeaderFilterCustomizer tomcatForwardedHeaderFilterCustomizer(ServerProperties serverProperties) {
ServerProperties serverProperties) { return (filter) -> filter.setRelativeRedirects(serverProperties.getTomcat().isUseRelativeRedirects());
return createForwardedHeaderFilter(serverProperties.getTomcat().isUseRelativeRedirects());
} }
@Bean @Bean
@ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class) FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter(
public FilterRegistrationBean<ForwardedHeaderFilter> defaultForwardedHeaderFilter() { ObjectProvider<ForwardedHeaderFilterCustomizer> customizerProvider) {
return createForwardedHeaderFilter(false);
}
private FilterRegistrationBean<ForwardedHeaderFilter> createForwardedHeaderFilter(boolean relativeRedirects) {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter(); ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
filter.setRelativeRedirects(relativeRedirects); customizerProvider.ifAvailable((customizer) -> customizer.customize(filter));
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter); FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR); registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE); registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
@ -114,6 +110,12 @@ public class ServletWebServerFactoryAutoConfiguration {
} }
interface ForwardedHeaderFilterCustomizer {
void customize(ForwardedHeaderFilter filter);
}
/** /**
* Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
* {@link ImportBeanDefinitionRegistrar} for early registration. * {@link ImportBeanDefinitionRegistrar} for early registration.

View File

@ -57,7 +57,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.filter.ForwardedHeaderFilter; import org.springframework.web.filter.ForwardedHeaderFilter;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet; import org.springframework.web.servlet.FrameworkServlet;
@ -353,6 +352,7 @@ class ServletWebServerFactoryAutoConfigurationTests {
assertThat(context).hasSingleBean(FilterRegistrationBean.class); assertThat(context).hasSingleBean(FilterRegistrationBean.class);
Filter filter = context.getBean(FilterRegistrationBean.class).getFilter(); Filter filter = context.getBean(FilterRegistrationBean.class).getFilter();
assertThat(filter).isInstanceOf(ForwardedHeaderFilter.class); assertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);
assertThat(filter).extracting("relativeRedirects").isEqualTo(false);
}); });
} }
@ -376,11 +376,24 @@ class ServletWebServerFactoryAutoConfigurationTests {
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class)) .withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class))
.withPropertyValues("server.forward-headers-strategy=framework", .withPropertyValues("server.forward-headers-strategy=framework",
"server.tomcat.use-relative-redirects=true"); "server.tomcat.use-relative-redirects=true");
runner.run((context) -> { runner.run((context) -> {
Filter filter = context.getBean(FilterRegistrationBean.class).getFilter(); Filter filter = context.getBean(FilterRegistrationBean.class).getFilter();
Boolean relativeRedirects = (Boolean) ReflectionTestUtils.getField(filter, "relativeRedirects"); assertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);
assertThat(relativeRedirects).isTrue(); assertThat(filter).extracting("relativeRedirects").isEqualTo(true);
});
}
@Test
void relativeRedirectsShouldNotBeEnabledWhenUsingTomcatContainerAndNotUsingRelativeRedirects() {
WebApplicationContextRunner runner = new WebApplicationContextRunner(
AnnotationConfigServletWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class))
.withPropertyValues("server.forward-headers-strategy=framework",
"server.tomcat.use-relative-redirects=false");
runner.run((context) -> {
Filter filter = context.getBean(FilterRegistrationBean.class).getFilter();
assertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);
assertThat(filter).extracting("relativeRedirects").isEqualTo(false);
}); });
} }
@ -391,11 +404,10 @@ class ServletWebServerFactoryAutoConfigurationTests {
.withClassLoader(new FilteredClassLoader(Tomcat.class)) .withClassLoader(new FilteredClassLoader(Tomcat.class))
.withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class)) .withConfiguration(AutoConfigurations.of(ServletWebServerFactoryAutoConfiguration.class))
.withPropertyValues("server.forward-headers-strategy=framework"); .withPropertyValues("server.forward-headers-strategy=framework");
runner.run((context) -> { runner.run((context) -> {
Filter filter = context.getBean(FilterRegistrationBean.class).getFilter(); Filter filter = context.getBean(FilterRegistrationBean.class).getFilter();
Boolean relativeRedirects = (Boolean) ReflectionTestUtils.getField(filter, "relativeRedirects"); assertThat(filter).isInstanceOf(ForwardedHeaderFilter.class);
assertThat(relativeRedirects).isFalse(); assertThat(filter).extracting("relativeRedirects").isEqualTo(false);
}); });
} }