This is an automated email from the ASF dual-hosted git repository.

pvillard31 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new fda655bc333 NIFI-16018: Handle port number in header validator
fda655bc333 is described below

commit fda655bc333640b2e9b8d8a0adefc40f05992f44
Author: Zoltan Kornel Torok <[email protected]>
AuthorDate: Sat Jun 13 00:59:33 2026 +0200

    NIFI-16018: Handle port number in header validator
    
    Signed-off-by: Pierre Villard <[email protected]>
    
    This closes #11335.
---
 .../connector/FrameworkServerConnectorFactory.java |  2 +-
 .../connector/ProxyHeaderValidatorCustomizer.java  | 34 ++++++++++++++++++++--
 .../web/server/StandardServerProviderTest.java     | 30 +++++++++++++++++++
 3 files changed, 63 insertions(+), 3 deletions(-)

diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
index e085cc0face..c3cd71d3693 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/FrameworkServerConnectorFactory.java
@@ -107,7 +107,7 @@ public class FrameworkServerConnectorFactory extends 
StandardServerConnectorFact
         // Add HostHeaderCustomizer to set Host Header for HTTP/2
         httpConfiguration.addCustomizer(new HostHeaderCustomizer());
 
-        final ProxyHeaderValidatorCustomizer proxyHeaderValidatorCustomizer = 
new ProxyHeaderValidatorCustomizer(validProxyHosts);
+        final ProxyHeaderValidatorCustomizer proxyHeaderValidatorCustomizer = 
new ProxyHeaderValidatorCustomizer(validProxyHosts, validPorts);
         httpConfiguration.addCustomizer(proxyHeaderValidatorCustomizer);
 
         final HostPortValidatorCustomizer hostPortValidatorCustomizer = new 
HostPortValidatorCustomizer(validPorts);
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/ProxyHeaderValidatorCustomizer.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/ProxyHeaderValidatorCustomizer.java
index 34c149c0877..87fa3100da2 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/ProxyHeaderValidatorCustomizer.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/main/java/org/apache/nifi/web/server/connector/ProxyHeaderValidatorCustomizer.java
@@ -31,12 +31,16 @@ import org.eclipse.jetty.server.Request;
 import java.security.cert.X509Certificate;
 import java.util.Objects;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 /**
  * Jetty Request Customizer implementing validation for supported Proxy 
Request Headers
  */
 public class ProxyHeaderValidatorCustomizer implements 
HttpConfiguration.Customizer {
     private static final String MISDIRECTED_REQUEST_REASON = "Invalid Proxy 
Host Requested";
+    private static final String MISDIRECTED_REQUEST_REASON_INVALID_PORT = 
"Invalid Port Requested";
+
+    private static final Pattern HOST_PORT_SEPARATOR = Pattern.compile(":");
 
     private static final Set<String> SUPPORTED_PROXY_HOST_HEADERS = Set.of(
             ProxyHeader.PROXY_HOST.getHeader(),
@@ -44,9 +48,11 @@ public class ProxyHeaderValidatorCustomizer implements 
HttpConfiguration.Customi
     );
 
     private final Set<String> validProxyHosts;
+    private final Set<Integer> validPorts;
 
-    public ProxyHeaderValidatorCustomizer(final Set<String> validProxyHosts) {
+    public ProxyHeaderValidatorCustomizer(final Set<String> validProxyHosts, 
final Set<Integer> validPorts) {
         this.validProxyHosts = Objects.requireNonNull(validProxyHosts, "Valid 
Proxy Hosts required");
+        this.validPorts = Objects.requireNonNull(validPorts, "Valid Ports 
required");
     }
 
     /**
@@ -95,16 +101,25 @@ public class ProxyHeaderValidatorCustomizer implements 
HttpConfiguration.Customi
 
         final HttpFields requestHeaders = request.getHeaders();
         for (final String proxyHostHeader : SUPPORTED_PROXY_HOST_HEADERS) {
-            final String hostHeader = requestHeaders.get(proxyHostHeader);
+            String hostHeader = requestHeaders.get(proxyHostHeader);
             // Include empty and blank values for enforced validation of 
request headers
             if (hostHeader == null) {
                 continue;
             }
+
+            final String[] hostHeaderParts = 
HOST_PORT_SEPARATOR.split(hostHeader);
+            if (hostHeaderParts.length == 2) {
+                hostHeader = hostHeaderParts[0];
+            }
+
             // Allow proxy host header matching request host header based on 
TLS SNI and DNS SAN requirements
             if (requestHost.equals(hostHeader)) {
+                processProxyHostHeaderPortNumber(hostHeaderParts);
                 continue;
             }
+
             if (validProxyHosts.contains(hostHeader)) {
+                processProxyHostHeaderPortNumber(hostHeaderParts);
                 continue;
             }
 
@@ -112,6 +127,21 @@ public class ProxyHeaderValidatorCustomizer implements 
HttpConfiguration.Customi
         }
     }
 
+    private void processProxyHostHeaderPortNumber(String[] hostHeaderParts) {
+        if (hostHeaderParts.length == 2) {
+            try {
+                final int port = Integer.parseInt(hostHeaderParts[1]);
+                if (validPorts.contains(port)) {
+                    return;
+                } else {
+                    throw new 
HttpException.RuntimeException(HttpStatus.MISDIRECTED_REQUEST_421, 
MISDIRECTED_REQUEST_REASON_INVALID_PORT);
+                }
+            } catch (final NumberFormatException e) {
+                throw new 
HttpException.RuntimeException(HttpStatus.MISDIRECTED_REQUEST_421, 
MISDIRECTED_REQUEST_REASON_INVALID_PORT);
+            }
+        }
+    }
+
     private X509Certificate findPeerCertificate(final Request request) {
         final X509Certificate peerCertificate;
         final ConnectionMetaData connectionMetaData = 
request.getConnectionMetaData();
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/StandardServerProviderTest.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/StandardServerProviderTest.java
index e5740b3bed8..65c815a08a9 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/StandardServerProviderTest.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/StandardServerProviderTest.java
@@ -87,6 +87,12 @@ class StandardServerProviderTest {
 
     private static final String PUBLIC_STAGED_HOST = "nifi.staged.apache.org";
 
+    private static final String PUBLIC_STAGED_HOST_WITH_PORT = 
"nifi.staged.apache.org:8443";
+
+    private static final String PUBLIC_STAGED_HOST_WITH_INVALID_PORT = 
"nifi.staged.apache.org:8444";
+
+    private static final String 
PUBLIC_STAGED_HOST_WITH_A_PORT_WHICH_NOT_NUMBER = "nifi.staged.apache.org:aaa";
+
     private static final String PROXY_HOST_PROPERTY = 
"nifi.apache.org,nifi.staged.apache.org:8443";
 
     private static final String PUBLIC_UNKNOWN_HOST = 
"nifi.unknown.apache.org";
@@ -350,6 +356,12 @@ class StandardServerProviderTest {
                 .header(ProxyHeader.FORWARDED_HOST.getHeader(), 
PUBLIC_STAGED_HOST)
                 .build();
         assertResponseStatusCode(httpClient, forwardedHostRequest, 
HttpStatus.MOVED_TEMPORARILY_302);
+
+        final HttpRequest forwardedHostRequestWithPort = 
HttpRequest.newBuilder(localhostUri)
+                .version(HttpClient.Version.HTTP_1_1)
+                .header(ProxyHeader.FORWARDED_HOST.getHeader(), 
PUBLIC_STAGED_HOST_WITH_PORT)
+                .build();
+        assertResponseStatusCode(httpClient, forwardedHostRequestWithPort, 
HttpStatus.MOVED_TEMPORARILY_302);
     }
 
     void assertBadRequestsCompleted(final HttpClient httpClient, final URI 
localhostUri) throws IOException, InterruptedException {
@@ -384,6 +396,24 @@ class StandardServerProviderTest {
                 .header(ProxyHeader.FORWARDED_HOST.getHeader(), 
PUBLIC_UNKNOWN_HOST)
                 .build();
         assertResponseStatusCode(httpClient, 
publicUnknownForwardedHostRequest, HttpStatus.MISDIRECTED_REQUEST_421);
+
+        final HttpRequest publicStagedHostWithInvalidPort = 
HttpRequest.newBuilder(localhostUri)
+                .version(HttpClient.Version.HTTP_1_1)
+                .header(ProxyHeader.FORWARDED_HOST.getHeader(), 
PUBLIC_STAGED_HOST_WITH_INVALID_PORT)
+                .build();
+        assertResponseStatusCode(httpClient, publicStagedHostWithInvalidPort, 
HttpStatus.MISDIRECTED_REQUEST_421);
+
+        final HttpRequest publicStagedHostWithAPortWhichNotNumber = 
HttpRequest.newBuilder(localhostUri)
+                .version(HttpClient.Version.HTTP_1_1)
+                .header(ProxyHeader.FORWARDED_HOST.getHeader(), 
PUBLIC_STAGED_HOST_WITH_A_PORT_WHICH_NOT_NUMBER)
+                .build();
+        assertResponseStatusCode(httpClient, 
publicStagedHostWithAPortWhichNotNumber, HttpStatus.MISDIRECTED_REQUEST_421);
+
+        final HttpRequest sameHostNameWithInvalidPort = 
HttpRequest.newBuilder(localhostUri)
+                .version(HttpClient.Version.HTTP_1_1)
+                .header(ProxyHeader.FORWARDED_HOST.getHeader(), 
localhostUri.getHost() + ":" + localhostUri.getPort())
+                .build();
+        assertResponseStatusCode(httpClient, sameHostNameWithInvalidPort, 
HttpStatus.MISDIRECTED_REQUEST_421);
     }
 
     void assertStandardResponseHeadersFound(final HttpResponse<Void> response) 
{

Reply via email to