Skip to content

Commit 0d3b692

Browse files
committed
Add group RemoteIpValve for ServerProperties.Tomcat
See gh-18302
1 parent 8b9890e commit 0d3b692

File tree

3 files changed

+145
-18
lines changed

3 files changed

+145
-18
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
* @author Rafiullah Hamedy
6464
* @author Dirk Deyne
6565
* @author HaiTao Zhang
66+
* @author Victor Mandujano
6667
* @since 1.0.0
6768
*/
6869
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
@@ -424,6 +425,11 @@ public static class Tomcat {
424425
*/
425426
private final Mbeanregistry mbeanregistry = new Mbeanregistry();
426427

428+
/**
429+
* Remote Ip Valve configuration.
430+
*/
431+
private final RemoteIpValve remoteIpValve = new RemoteIpValve();
432+
427433
public int getMaxThreads() {
428434
return this.maxThreads;
429435
}
@@ -468,36 +474,40 @@ public void setBasedir(File basedir) {
468474
this.basedir = basedir;
469475
}
470476

477+
@DeprecatedConfigurationProperty(replacement = "server.tomcat.remote-ip-valve.internal-proxies")
471478
public String getInternalProxies() {
472-
return this.internalProxies;
479+
return this.remoteIpValve.getInternalProxies();
473480
}
474481

475482
public void setInternalProxies(String internalProxies) {
476-
this.internalProxies = internalProxies;
483+
this.remoteIpValve.setInternalProxies(internalProxies);
477484
}
478485

486+
@DeprecatedConfigurationProperty(replacement = "server.tomcat.remote-ip-valve.protocol-header")
479487
public String getProtocolHeader() {
480-
return this.protocolHeader;
488+
return this.remoteIpValve.getProtocolHeader();
481489
}
482490

483491
public void setProtocolHeader(String protocolHeader) {
484-
this.protocolHeader = protocolHeader;
492+
this.remoteIpValve.setProtocolHeader(protocolHeader);
485493
}
486494

495+
@DeprecatedConfigurationProperty(replacement = "server.tomcat.remote-ip-valve.protocol-header-https-value")
487496
public String getProtocolHeaderHttpsValue() {
488-
return this.protocolHeaderHttpsValue;
497+
return this.remoteIpValve.getProtocolHeaderHttpsValue();
489498
}
490499

491500
public void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValue) {
492-
this.protocolHeaderHttpsValue = protocolHeaderHttpsValue;
501+
this.remoteIpValve.setProtocolHeaderHttpsValue(protocolHeaderHttpsValue);
493502
}
494503

504+
@DeprecatedConfigurationProperty(replacement = "server.tomcat.remote-ip-valve.port-header")
495505
public String getPortHeader() {
496-
return this.portHeader;
506+
return this.remoteIpValve.getPortHeader();
497507
}
498508

499509
public void setPortHeader(String portHeader) {
500-
this.portHeader = portHeader;
510+
this.remoteIpValve.setPortHeader(portHeader);
501511
}
502512

503513
public Boolean getRedirectContextRoot() {
@@ -516,20 +526,22 @@ public void setUseRelativeRedirects(Boolean useRelativeRedirects) {
516526
this.useRelativeRedirects = useRelativeRedirects;
517527
}
518528

529+
@DeprecatedConfigurationProperty(replacement = "server.tomcat.remote-ip-valve.remote-ip-header")
519530
public String getRemoteIpHeader() {
520-
return this.remoteIpHeader;
531+
return this.remoteIpValve.getRemoteIpHeader();
521532
}
522533

523534
public void setRemoteIpHeader(String remoteIpHeader) {
524-
this.remoteIpHeader = remoteIpHeader;
535+
this.remoteIpValve.setRemoteIpHeader(remoteIpHeader);
525536
}
526537

538+
@DeprecatedConfigurationProperty(replacement = "server.tomcat.remote-ip-valve.host-header")
527539
public String getHostHeader() {
528-
return this.hostHeader;
540+
return this.remoteIpValve.getHostHeader() == null ? this.hostHeader : this.remoteIpValve.getHostHeader();
529541
}
530542

531543
public void setHostHeader(String hostHeader) {
532-
this.hostHeader = hostHeader;
544+
this.remoteIpValve.setHostHeader(hostHeader);
533545
}
534546

535547
public Charset getUriEncoding() {
@@ -604,6 +616,10 @@ public Mbeanregistry getMbeanregistry() {
604616
return this.mbeanregistry;
605617
}
606618

619+
public RemoteIpValve getRemoteIpValve() {
620+
return this.remoteIpValve;
621+
}
622+
607623
/**
608624
* Tomcat access log properties.
609625
*/
@@ -890,6 +906,96 @@ public void setEnabled(boolean enabled) {
890906

891907
}
892908

909+
public static class RemoteIpValve {
910+
911+
/**
912+
* Name of the HTTP header from which the remote host is extracted.
913+
*/
914+
private String hostHeader = "X-Forwarded-Host";
915+
916+
/**
917+
* Regular expression that matches proxies that are to be trusted.
918+
*/
919+
private String internalProxies = "10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 10/8
920+
+ "192\\.168\\.\\d{1,3}\\.\\d{1,3}|" // 192.168/16
921+
+ "169\\.254\\.\\d{1,3}\\.\\d{1,3}|" // 169.254/16
922+
+ "127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|" // 127/8
923+
+ "172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" // 172.16/12
924+
+ "172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}|" //
925+
+ "0:0:0:0:0:0:0:1|::1";
926+
927+
/**
928+
* Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
929+
*/
930+
private String protocolHeader;
931+
932+
/**
933+
* Value of the protocol header indicating whether the incoming request uses
934+
* SSL.
935+
*/
936+
private String protocolHeaderHttpsValue = "https";
937+
938+
/**
939+
* Name of the HTTP header used to override the original port value.
940+
*/
941+
private String portHeader = "X-Forwarded-Port";
942+
943+
/**
944+
* Name of the HTTP header from which the remote IP is extracted. For
945+
* instance, `X-FORWARDED-FOR`.
946+
*/
947+
private String remoteIpHeader;
948+
949+
public String getHostHeader() {
950+
return this.hostHeader;
951+
}
952+
953+
public void setHostHeader(String hostHeader) {
954+
this.hostHeader = hostHeader;
955+
}
956+
957+
public String getInternalProxies() {
958+
return this.internalProxies;
959+
}
960+
961+
public void setInternalProxies(String internalProxies) {
962+
this.internalProxies = internalProxies;
963+
}
964+
965+
public String getProtocolHeader() {
966+
return this.protocolHeader;
967+
}
968+
969+
public void setProtocolHeader(String protocolHeader) {
970+
this.protocolHeader = protocolHeader;
971+
}
972+
973+
public String getProtocolHeaderHttpsValue() {
974+
return this.protocolHeaderHttpsValue;
975+
}
976+
977+
public void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValue) {
978+
this.protocolHeaderHttpsValue = protocolHeaderHttpsValue;
979+
}
980+
981+
public String getPortHeader() {
982+
return this.portHeader;
983+
}
984+
985+
public void setPortHeader(String portHeader) {
986+
this.portHeader = portHeader;
987+
}
988+
989+
public String getRemoteIpHeader() {
990+
return this.remoteIpHeader;
991+
}
992+
993+
public void setRemoteIpHeader(String remoteIpHeader) {
994+
this.remoteIpHeader = remoteIpHeader;
995+
}
996+
997+
}
998+
893999
}
8941000

8951001
/**

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizer.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
* @author Chentao Qu
5555
* @author Andrew McGhie
5656
* @author Dirk Deyne
57+
* @author Victor Mandujano
5758
* @since 2.0.0
5859
*/
5960
public class TomcatWebServerFactoryCustomizer
@@ -170,8 +171,8 @@ private String joinCharacters(List<Character> content) {
170171

171172
private void customizeRemoteIpValve(ConfigurableTomcatWebServerFactory factory) {
172173
Tomcat tomcatProperties = this.serverProperties.getTomcat();
173-
String protocolHeader = tomcatProperties.getProtocolHeader();
174-
String remoteIpHeader = tomcatProperties.getRemoteIpHeader();
174+
String protocolHeader = tomcatProperties.getRemoteIpValve().getProtocolHeader();
175+
String remoteIpHeader = tomcatProperties.getRemoteIpValve().getRemoteIpHeader();
175176
// For back compatibility the valve is also enabled if protocol-header is set
176177
if (StringUtils.hasText(protocolHeader) || StringUtils.hasText(remoteIpHeader)
177178
|| getOrDeduceUseForwardHeaders()) {
@@ -182,10 +183,10 @@ private void customizeRemoteIpValve(ConfigurableTomcatWebServerFactory factory)
182183
}
183184
// The internal proxies default to a white list of "safe" internal IP
184185
// addresses
185-
valve.setInternalProxies(tomcatProperties.getInternalProxies());
186-
valve.setHostHeader(tomcatProperties.getHostHeader());
187-
valve.setPortHeader(tomcatProperties.getPortHeader());
188-
valve.setProtocolHeaderHttpsValue(tomcatProperties.getProtocolHeaderHttpsValue());
186+
valve.setInternalProxies(tomcatProperties.getRemoteIpValve().getInternalProxies());
187+
valve.setHostHeader(tomcatProperties.getRemoteIpValve().getHostHeader());
188+
valve.setPortHeader(tomcatProperties.getRemoteIpValve().getPortHeader());
189+
valve.setProtocolHeaderHttpsValue(tomcatProperties.getRemoteIpValve().getProtocolHeaderHttpsValue());
189190
// ... so it's safe to add this valve by default.
190191
factory.addEngineValves(valve);
191192
}

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/embedded/TomcatWebServerFactoryCustomizerTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
* @author Artsiom Yudovin
5353
* @author Stephane Nicoll
5454
* @author Andrew McGhie
55+
* @author Victor Mandujano
5556
*/
5657
class TomcatWebServerFactoryCustomizerTests {
5758

@@ -178,6 +179,25 @@ void customRemoteIpValve() {
178179
assertThat(remoteIpValve.getInternalProxies()).isEqualTo("192.168.0.1");
179180
}
180181

182+
@Test
183+
void customNewPropertiesForRemoteIpValve() {
184+
bind("server.tomcat.remote-ip-valve.remote-ip-header=x-my-remote-ip-header",
185+
"server.tomcat.remote-ip-valve.protocol-header=x-my-protocol-header",
186+
"server.tomcat.remote-ip-valve.internal-proxies=192.168.0.1",
187+
"server.tomcat.remote-ip-valve.port-header=x-my-forward-port",
188+
"server.tomcat.remote-ip-valve.protocol-header-https-value=On");
189+
TomcatServletWebServerFactory factory = customizeAndGetFactory();
190+
assertThat(factory.getEngineValves()).hasSize(1);
191+
Valve valve = factory.getEngineValves().iterator().next();
192+
assertThat(valve).isInstanceOf(RemoteIpValve.class);
193+
RemoteIpValve remoteIpValve = (RemoteIpValve) valve;
194+
assertThat(remoteIpValve.getProtocolHeader()).isEqualTo("x-my-protocol-header");
195+
assertThat(remoteIpValve.getProtocolHeaderHttpsValue()).isEqualTo("On");
196+
assertThat(remoteIpValve.getRemoteIpHeader()).isEqualTo("x-my-remote-ip-header");
197+
assertThat(remoteIpValve.getPortHeader()).isEqualTo("x-my-forward-port");
198+
assertThat(remoteIpValve.getInternalProxies()).isEqualTo("192.168.0.1");
199+
}
200+
181201
@Test
182202
void customStaticResourceAllowCaching() {
183203
bind("server.tomcat.resource.allow-caching=false");

0 commit comments

Comments
 (0)