From 77621cecd72ac5552b49d0f3f5116ffae6272386 Mon Sep 17 00:00:00 2001 From: Pierre De Rop Date: Tue, 4 Apr 2023 11:00:05 +0200 Subject: [PATCH] Parse X-Forwarded-Port header even if X-Forwarded-Host is not present (#2761) Always takes into account any available X-Forwarded-Port header even if the X-Forwarded-Host header is missing. Fixes #2751 --- .../DefaultHttpForwardedHeaderHandler.java | 36 +++++++++++-------- .../http/server/ConnectionInfoTests.java | 26 ++++++++++++++ 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java b/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java index 4cd24e7864..10972f863f 100644 --- a/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java +++ b/reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java @@ -98,25 +98,31 @@ private ConnectionInfo parseXForwardedInfo(ConnectionInfo connectionInfo, HttpRe } String hostHeader = request.headers().get(X_FORWARDED_HOST_HEADER); if (hostHeader != null) { - String scheme = connectionInfo.getScheme(); - int port = scheme.equalsIgnoreCase("https") || scheme.equalsIgnoreCase("wss") ? - DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT; connectionInfo = connectionInfo.withHostAddress( - AddressUtils.parseAddress(hostHeader.split(",", 2)[0].trim(), port, DEFAULT_FORWARDED_HEADER_VALIDATION)); - String portHeader = request.headers().get(X_FORWARDED_PORT_HEADER); - if (portHeader != null && !portHeader.isEmpty()) { - String portStr = portHeader.split(",", 2)[0].trim(); - if (portStr.chars().allMatch(Character::isDigit)) { - port = Integer.parseInt(portStr); - } - else if (DEFAULT_FORWARDED_HEADER_VALIDATION) { - throw new IllegalArgumentException("Failed to parse a port from " + portHeader); - } - connectionInfo = connectionInfo.withHostAddress( - AddressUtils.createUnresolved(connectionInfo.getHostAddress().getHostString(), port)); + AddressUtils.parseAddress(hostHeader.split(",", 2)[0].trim(), + getDefaultHostPort(connectionInfo), DEFAULT_FORWARDED_HEADER_VALIDATION)); + } + + String portHeader = request.headers().get(X_FORWARDED_PORT_HEADER); + if (portHeader != null && !portHeader.isEmpty()) { + String portStr = portHeader.split(",", 2)[0].trim(); + if (portStr.chars().allMatch(Character::isDigit)) { + int port = Integer.parseInt(portStr); + connectionInfo = new ConnectionInfo( + AddressUtils.createUnresolved(connectionInfo.getHostAddress().getHostString(), port), + connectionInfo.getHostName(), port, connectionInfo.getRemoteAddress(), connectionInfo.getScheme()); + } + else if (DEFAULT_FORWARDED_HEADER_VALIDATION) { + throw new IllegalArgumentException("Failed to parse a port from " + portHeader); } } return connectionInfo; } + private int getDefaultHostPort(ConnectionInfo connectionInfo) { + String scheme = connectionInfo.getScheme(); + return scheme.equalsIgnoreCase("https") || scheme.equalsIgnoreCase("wss") ? + DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT; + } + } diff --git a/reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java b/reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java index 6669d7fa07..d9163bcf68 100644 --- a/reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java +++ b/reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java @@ -367,6 +367,32 @@ void xForwardedForMultipleHostAndPortAndProto() { }); } + @Test + void xForwardedForAndHostOnly() throws SSLException { + SslContext clientSslContext = SslContextBuilder.forClient() + .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); + SslContext serverSslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build(); + + testClientRequest( + clientRequestHeaders -> { + clientRequestHeaders.add("Host", "a.example.com"); + clientRequestHeaders.add("X-Forwarded-For", "192.168.0.1"); + clientRequestHeaders.add("X-Forwarded-Port", "8443"); + clientRequestHeaders.add("X-Forwarded-Proto", "https"); + }, + serverRequest -> { + Assertions.assertThat(serverRequest.remoteAddress().getHostString()).isEqualTo("192.168.0.1"); + Assertions.assertThat(serverRequest.hostAddress().getHostString()) + .containsPattern("^0:0:0:0:0:0:0:1(%\\w*)?|127.0.0.1$"); + Assertions.assertThat(serverRequest.hostPort()).isEqualTo(8443); + Assertions.assertThat(serverRequest.hostName()).isEqualTo("a.example.com"); + Assertions.assertThat(serverRequest.scheme()).isEqualTo("https"); + }, + httpClient -> httpClient.secure(ssl -> ssl.sslContext(clientSslContext)), + httpServer -> httpServer.secure(ssl -> ssl.sslContext(serverSslContext)), + true); + } + @Test void customForwardedHandlerForMultipleHost() { testClientRequest(