[ 
https://issues.apache.org/jira/browse/CAMEL-23070?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Reto Peter updated CAMEL-23070:
-------------------------------
    Description: 
The async MDN receiver ({{{}AS2AsyncMDNServerConnection{}}}) uses 
{{RequestValidateHost}} in its HttpProcessor, which enforces strict host header 
validation per HttpCore 5.3+. This causes incoming async MDN requests to be 
rejected with HTTP 421 "Not authoritative"
   when the {{Host}} header doesn't exactly match the server's expected 
hostname.

  The main AS2 receiver ({{{}AS2ServerConnection{}}}) does not use 
{{{}RequestValidateHost{}}}, so it accepts any {{Host}} header. This is an 
inconsistency — async MDNs are rejected while regular AS2 messages are accepted.
  \{panel}

  h3. Root Cause

  In {{AS2AsyncMDNServerConnection.RequestListenerThread}} constructor (line 
~105):

  \{code:java|title=AS2AsyncMDNServerConnection.java (Camel 4.18.0)}
  public RequestListenerThread(int port, SSLContext sslContext) throws 
IOException

{       setName(REQUEST_LISTENER_THREAD_NAME_PREFIX + port);       // ...       
HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
RequestValidateHost());  // <-- STRICT       registry = new 
RequestHandlerRegistry<>();       handler = new 
BasicHttpServerRequestHandler(registry);       httpService = new 
HttpService(httpProcessor, handler);   }

  \{code}

  But in {{AS2ServerConnection.initProtocolProcessor()}} (line ~655):

  \{code:java|title=AS2ServerConnection.java (Camel 4.18.0)}
  protected HttpProcessor initProtocolProcessor(
          String as2Version, String originServer, String serverFqdn, String 
mdnMessageTemplate)

{       return HttpProcessorBuilder.create()               .addFirst(new 
AS2ConsumerConfigInterceptor())               .add(new ResponseContent(true))   
            .add(new ResponseServer(originServer))               .add(new 
ResponseDate())               .add(new ResponseConnControl())               
.add(new ResponseMDN(as2Version, serverFqdn, mdnMessageTemplate))               
.build();                                                          // <-- NO 
RequestValidateHost   }

  \{code}

  The main AS2 server uses {{HttpProcessorBuilder}} with response interceptors 
only — no {{{}RequestValidateHost{}}}. The async MDN server uses 
{{DefaultHttpProcessor}} with only {{RequestValidateHost}} and no response 
interceptors at all.

  h3. Impact

  - Partners that send async MDNs with a {{Host}} header that doesn't match the 
server's configured hostname get HTTP 421 "Not authoritative"
  - This is common in production environments with load balancers, reverse 
proxies, or NAT where the external hostname differs from the internal one
  - The sender thinks the MDN delivery failed and may retry or flag the 
transmission as unconfirmed
  - Meanwhile, the original AS2 message was received successfully (because 
{{AS2ServerConnection}} has no host validation)

  h3. Steps to Reproduce

  Configure a Camel AS2 server with async MDN enabled on a separate port

  Have a partner send an AS2 message requesting async MDN delivery

  Partner sends the async MDN to the callback URL

  If the {{Host}} header in the MDN request doesn't exactly match the server's 
hostname: HTTP 421 "Not authoritative"

  This is easy to trigger in environments with:
  - Load balancers or reverse proxies (external hostname differs from internal)
  - Docker/Kubernetes (container hostname differs from service hostname)
  - NAT configurations
  - Partners that set {{Host}} header to the IP address instead of the hostname

  h3. Proposed Fix

  Remove {{RequestValidateHost}} from the async MDN server and add the same 
response interceptors as the main AS2 server:

  \{code:diff|title=Fix in AS2AsyncMDNServerConnection.java}
   public RequestListenerThread(int port, SSLContext sslContext) throws 
IOException

{        setName(REQUEST_LISTENER_THREAD_NAME_PREFIX + port);        // ...   - 
HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
RequestValidateHost());   - HttpProcessor httpProcessor = 
HttpProcessorBuilder.create()          .add(new ResponseContent(true))          
.add(new ResponseDate())          .add(new ResponseServer(null))          
.add(new ResponseConnControl())          .build();   -    registry = new 
RequestHandlerRegistry<>();      handler = new 
BasicHttpServerRequestHandler(registry);      httpService = new 
HttpService(httpProcessor, handler);    }

  \{code}

  This makes the async MDN receiver consistent with the main AS2 receiver:
  - No strict host validation (same as {{{}AS2ServerConnection{}}})
  - Standard response interceptors are added ({{{}ResponseContent{}}}, 
{{{}ResponseDate{}}}, etc.) — the current code has none, which means async MDN 
responses may also be missing standard HTTP headers

  h3. Additional Issue: Missing Response Interceptors

  Note that the current {{AS2AsyncMDNServerConnection}} creates the 
HttpProcessor with only {{RequestValidateHost}} and no response interceptors:

  \{code:java}
  HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
RequestValidateHost());
  \{code}

  This means HTTP responses from the async MDN receiver may be missing standard 
headers like {{{}Content-Length{}}}, {{{}Date{}}}, and {{{}Connection{}}}. The 
proposed fix addresses both issues.

  h3. Our Workaround

  We use reflection after endpoint initialization to replace the 
{{HttpProcessor}} on the async MDN server's {{HttpService}} with a permissive 
processor built via {{HttpProcessorBuilder}} (with standard response 
interceptors but no {{{}RequestValidateHost{}}}).

  h3. Test Scenario

  Tested with OpenAS2 sending async MDNs.

  Before fix: Async MDNs rejected with HTTP 421 when Host header doesn't match.
  After replacing HttpProcessor: Async MDNs accepted regardless of Host header 
value.

  was:
The async MDN receiver (\{{AS2AsyncMDNServerConnection}}) uses 
\{{RequestValidateHost}} in its HttpProcessor, which enforces strict host 
header validation per HttpCore 5.3+. This causes incoming async MDN requests to 
be rejected with HTTP 421 "Not authoritative"
   when the \{{Host}} header doesn't exactly match the server's expected 
hostname.

  The main AS2 receiver (\{{AS2ServerConnection}}) does not use 
\{{RequestValidateHost}}, so it accepts any \{{Host}} header. This is an 
inconsistency — async MDNs are rejected while regular AS2 messages are accepted.
  \{panel}

  h3. Root Cause

  In \{{AS2AsyncMDNServerConnection.RequestListenerThread}} constructor (line 
~105):

  \{code:java|title=AS2AsyncMDNServerConnection.java (Camel 4.18.0)}
  public RequestListenerThread(int port, SSLContext sslContext) throws 
IOException {
      setName(REQUEST_LISTENER_THREAD_NAME_PREFIX + port);
      // ...
      HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
RequestValidateHost());  // <-- STRICT
      registry = new RequestHandlerRegistry<>();
      handler = new BasicHttpServerRequestHandler(registry);
      httpService = new HttpService(httpProcessor, handler);
  }
  \{code}

  But in \{{AS2ServerConnection.initProtocolProcessor()}} (line ~655):

  \{code:java|title=AS2ServerConnection.java (Camel 4.18.0)}
  protected HttpProcessor initProtocolProcessor(
          String as2Version, String originServer, String serverFqdn, String 
mdnMessageTemplate) {
      return HttpProcessorBuilder.create()
              .addFirst(new AS2ConsumerConfigInterceptor())
              .add(new ResponseContent(true))
              .add(new ResponseServer(originServer))
              .add(new ResponseDate())
              .add(new ResponseConnControl())
              .add(new ResponseMDN(as2Version, serverFqdn, mdnMessageTemplate))
              .build();                                                         
 // <-- NO RequestValidateHost
  }
  \{code}

  The main AS2 server uses \{{HttpProcessorBuilder}} with response interceptors 
only — no \{{RequestValidateHost}}. The async MDN server uses 
\{{DefaultHttpProcessor}} with only \{{RequestValidateHost}} and no response 
interceptors at all.

  h3. Impact

  - Partners that send async MDNs with a \{{Host}} header that doesn't match 
the server's configured hostname get HTTP 421 "Not authoritative"
  - This is common in production environments with load balancers, reverse 
proxies, or NAT where the external hostname differs from the internal one
  - The sender thinks the MDN delivery failed and may retry or flag the 
transmission as unconfirmed
  - Meanwhile, the original AS2 message was received successfully (because 
\{{AS2ServerConnection}} has no host validation)

  h3. Steps to Reproduce

  Configure a Camel AS2 server with async MDN enabled on a separate port

  Have a partner send an AS2 message requesting async MDN delivery

  Partner sends the async MDN to the callback URL

  If the \{{Host}} header in the MDN request doesn't exactly match the server's 
hostname: HTTP 421 "Not authoritative"

  This is easy to trigger in environments with:
  - Load balancers or reverse proxies (external hostname differs from internal)
  - Docker/Kubernetes (container hostname differs from service hostname)
  - NAT configurations
  - Partners that set \{{Host}} header to the IP address instead of the hostname

  h3. Proposed Fix

  Remove \{{RequestValidateHost}} from the async MDN server and add the same 
response interceptors as the main AS2 server:

  \{code:diff|title=Fix in AS2AsyncMDNServerConnection.java}
   public RequestListenerThread(int port, SSLContext sslContext) throws 
IOException {
       setName(REQUEST_LISTENER_THREAD_NAME_PREFIX + port);
       // ...
  - HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
RequestValidateHost());
  - HttpProcessor httpProcessor = HttpProcessorBuilder.create()
         .add(new ResponseContent(true))
         .add(new ResponseDate())
         .add(new ResponseServer(null))
         .add(new ResponseConnControl())
         .build();
  -    registry = new RequestHandlerRegistry<>();
     handler = new BasicHttpServerRequestHandler(registry);
     httpService = new HttpService(httpProcessor, handler);
   }
  \{code}

  This makes the async MDN receiver consistent with the main AS2 receiver:
  - No strict host validation (same as \{{AS2ServerConnection}})
  - Standard response interceptors are added (\{{ResponseContent}}, 
\{{ResponseDate}}, etc.) — the current code has none, which means async MDN 
responses may also be missing standard HTTP headers

  h3. Additional Issue: Missing Response Interceptors

  Note that the current \{{AS2AsyncMDNServerConnection}} creates the 
HttpProcessor with only \{{RequestValidateHost}} and no response interceptors:

  \{code:java}
  HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
RequestValidateHost());
  \{code}

  This means HTTP responses from the async MDN receiver may be missing standard 
headers like \{{Content-Length}}, \{{Date}}, and \{{Connection}}. The proposed 
fix addresses both issues.

  h3. Our Workaround

  We use reflection after endpoint initialization to replace the 
\{{HttpProcessor}} on the async MDN server's \{{HttpService}} with a permissive 
processor built via \{{HttpProcessorBuilder}} (with standard response 
interceptors but no \{{RequestValidateHost}}).

  h3. Test Scenario

  Tested with OpenAS2 sending async MDNs.

  Before fix: Async MDNs rejected with HTTP 421 when Host header doesn't match.
  After replacing HttpProcessor: Async MDNs accepted regardless of Host header 
value.


> AS2AsyncMDNServerConnection uses strict RequestValidateHost — async MDNs 
> rejected with HTTP 421
> -----------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-23070
>                 URL: https://issues.apache.org/jira/browse/CAMEL-23070
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-as2
>    Affects Versions: 4.18.0
>            Reporter: Reto Peter
>            Priority: Major
>
> The async MDN receiver ({{{}AS2AsyncMDNServerConnection{}}}) uses 
> {{RequestValidateHost}} in its HttpProcessor, which enforces strict host 
> header validation per HttpCore 5.3+. This causes incoming async MDN requests 
> to be rejected with HTTP 421 "Not authoritative"
>    when the {{Host}} header doesn't exactly match the server's expected 
> hostname.
>   The main AS2 receiver ({{{}AS2ServerConnection{}}}) does not use 
> {{{}RequestValidateHost{}}}, so it accepts any {{Host}} header. This is an 
> inconsistency — async MDNs are rejected while regular AS2 messages are 
> accepted.
>   \{panel}
>   h3. Root Cause
>   In {{AS2AsyncMDNServerConnection.RequestListenerThread}} constructor (line 
> ~105):
>   \{code:java|title=AS2AsyncMDNServerConnection.java (Camel 4.18.0)}
>   public RequestListenerThread(int port, SSLContext sslContext) throws 
> IOException
> {       setName(REQUEST_LISTENER_THREAD_NAME_PREFIX + port);       // ...     
>   HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
> RequestValidateHost());  // <-- STRICT       registry = new 
> RequestHandlerRegistry<>();       handler = new 
> BasicHttpServerRequestHandler(registry);       httpService = new 
> HttpService(httpProcessor, handler);   }
>   \{code}
>   But in {{AS2ServerConnection.initProtocolProcessor()}} (line ~655):
>   \{code:java|title=AS2ServerConnection.java (Camel 4.18.0)}
>   protected HttpProcessor initProtocolProcessor(
>           String as2Version, String originServer, String serverFqdn, String 
> mdnMessageTemplate)
> {       return HttpProcessorBuilder.create()               .addFirst(new 
> AS2ConsumerConfigInterceptor())               .add(new ResponseContent(true)) 
>               .add(new ResponseServer(originServer))               .add(new 
> ResponseDate())               .add(new ResponseConnControl())               
> .add(new ResponseMDN(as2Version, serverFqdn, mdnMessageTemplate))             
>   .build();                                                          // <-- 
> NO RequestValidateHost   }
>   \{code}
>   The main AS2 server uses {{HttpProcessorBuilder}} with response 
> interceptors only — no {{{}RequestValidateHost{}}}. The async MDN server uses 
> {{DefaultHttpProcessor}} with only {{RequestValidateHost}} and no response 
> interceptors at all.
>   h3. Impact
>   - Partners that send async MDNs with a {{Host}} header that doesn't match 
> the server's configured hostname get HTTP 421 "Not authoritative"
>   - This is common in production environments with load balancers, reverse 
> proxies, or NAT where the external hostname differs from the internal one
>   - The sender thinks the MDN delivery failed and may retry or flag the 
> transmission as unconfirmed
>   - Meanwhile, the original AS2 message was received successfully (because 
> {{AS2ServerConnection}} has no host validation)
>   h3. Steps to Reproduce
>   Configure a Camel AS2 server with async MDN enabled on a separate port
>   Have a partner send an AS2 message requesting async MDN delivery
>   Partner sends the async MDN to the callback URL
>   If the {{Host}} header in the MDN request doesn't exactly match the 
> server's hostname: HTTP 421 "Not authoritative"
>   This is easy to trigger in environments with:
>   - Load balancers or reverse proxies (external hostname differs from 
> internal)
>   - Docker/Kubernetes (container hostname differs from service hostname)
>   - NAT configurations
>   - Partners that set {{Host}} header to the IP address instead of the 
> hostname
>   h3. Proposed Fix
>   Remove {{RequestValidateHost}} from the async MDN server and add the same 
> response interceptors as the main AS2 server:
>   \{code:diff|title=Fix in AS2AsyncMDNServerConnection.java}
>    public RequestListenerThread(int port, SSLContext sslContext) throws 
> IOException
> {        setName(REQUEST_LISTENER_THREAD_NAME_PREFIX + port);        // ...   
> - HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
> RequestValidateHost());   - HttpProcessor httpProcessor = 
> HttpProcessorBuilder.create()          .add(new ResponseContent(true))        
>   .add(new ResponseDate())          .add(new ResponseServer(null))          
> .add(new ResponseConnControl())          .build();   -    registry = new 
> RequestHandlerRegistry<>();      handler = new 
> BasicHttpServerRequestHandler(registry);      httpService = new 
> HttpService(httpProcessor, handler);    }
>   \{code}
>   This makes the async MDN receiver consistent with the main AS2 receiver:
>   - No strict host validation (same as {{{}AS2ServerConnection{}}})
>   - Standard response interceptors are added ({{{}ResponseContent{}}}, 
> {{{}ResponseDate{}}}, etc.) — the current code has none, which means async 
> MDN responses may also be missing standard HTTP headers
>   h3. Additional Issue: Missing Response Interceptors
>   Note that the current {{AS2AsyncMDNServerConnection}} creates the 
> HttpProcessor with only {{RequestValidateHost}} and no response interceptors:
>   \{code:java}
>   HttpProcessor httpProcessor = new DefaultHttpProcessor(new 
> RequestValidateHost());
>   \{code}
>   This means HTTP responses from the async MDN receiver may be missing 
> standard headers like {{{}Content-Length{}}}, {{{}Date{}}}, and 
> {{{}Connection{}}}. The proposed fix addresses both issues.
>   h3. Our Workaround
>   We use reflection after endpoint initialization to replace the 
> {{HttpProcessor}} on the async MDN server's {{HttpService}} with a permissive 
> processor built via {{HttpProcessorBuilder}} (with standard response 
> interceptors but no {{{}RequestValidateHost{}}}).
>   h3. Test Scenario
>   Tested with OpenAS2 sending async MDNs.
>   Before fix: Async MDNs rejected with HTTP 421 when Host header doesn't 
> match.
>   After replacing HttpProcessor: Async MDNs accepted regardless of Host 
> header value.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to