Reto Peter created CAMEL-23070:
----------------------------------
Summary: 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
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)