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

oscerd pushed a commit to branch camel-4.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.18.x by this push:
     new 64459b6299c0 [backport camel-4.18.x] CAMEL-24417: camel-as2 - validate 
the asynchronous MDN delivery address and scope the MDN credentials (#25764)
64459b6299c0 is described below

commit 64459b6299c07364eb9a225ee02fa2153da526e2
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Aug 27 06:40:55 2026 +0200

    [backport camel-4.18.x] CAMEL-24417: camel-as2 - validate the asynchronous 
MDN delivery address and scope the MDN credentials (#25764)
    
    CAMEL-24417: camel-as2 - validate the asynchronous MDN delivery address and 
scope the MDN credentials
    
    The delivery address for an asynchronous MDN comes from the 
Receipt-Delivery-Option
    header of the received AS2 message, so it is chosen by the sender. The 
server passed it
    straight to a socket and attached the configured MDN credentials to 
whatever host it
    named, with no scheme check.
    
    A new asyncMdnAllowedHosts option names the hosts an asynchronous MDN may 
be delivered
    to. Credentials are attached only for a host on the list, and an address 
naming a host
    outside it is refused. With the option unset the MDN is still delivered, as 
before, but
    no credentials are attached.
    
    Independently of the option the scheme must now be http. https is refused 
rather than
    attempted: this class delivers over a plain socket and has no TLS, so an 
https address
    wrote the request - including the Authorization header - in cleartext to 
the TLS port.
    IPv6 hosts are unbracketed before the allow-list match.
    
    Public API stays source and binary compatible; the previous constructors 
delegate. Real
    TLS delivery via SSLContextParameters is tracked as CAMEL-24474.
    
    Closes #25637
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 .../org/apache/camel/catalog/components/as2.json   |  31 ++++---
 .../as2/api/AS2AsynchronousMDNManager.java         |  84 ++++++++++++++++-
 .../component/as2/api/AS2ServerConnection.java     |  26 +++++-
 ...2AsynchronousMDNManagerDeliveryAddressTest.java | 102 +++++++++++++++++++++
 ...rverManagerEndpointConfigurationConfigurer.java |   7 ++
 ...ientManagerEndpointConfigurationConfigurer.java |   7 ++
 .../component/as2/AS2ConfigurationConfigurer.java  |   7 ++
 .../camel/component/as2/AS2EndpointConfigurer.java |   7 ++
 .../camel/component/as2/AS2EndpointUriFactory.java |   3 +-
 ...rverManagerEndpointConfigurationConfigurer.java |   7 ++
 .../org/apache/camel/component/as2/as2.json        |  31 ++++---
 .../camel/component/as2/AS2Configuration.java      |  18 ++++
 .../as2/internal/AS2ConnectionHelper.java          |   3 +-
 .../as2/AS2AsyncMdnBasicAuthHeaderTest.java        |   5 +-
 .../as2/AS2AsyncMdnTokenAuthHeaderTest.java        |   5 +-
 .../as2/AS2ServerBasicAuthHeaderTest.java          |   3 +
 .../as2/AS2ServerBearerAuthHeaderTest.java         |   3 +
 .../endpoint/dsl/AS2EndpointBuilderFactory.java    |  63 +++++++++++++
 18 files changed, 375 insertions(+), 37 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
index 4e0f84179c00..5713cb8a636e 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
@@ -67,21 +67,22 @@
     "exchangePattern": { "index": 31, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
     "lazyStartProducer": { "index": 32, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
     "accessToken": { "index": 33, "kind": "parameter", "displayName": "Access 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The access token that is used by the client 
for bearer authentication." },
-    "decryptingPrivateKey": { "index": 34, "kind": "parameter", "displayName": 
"Decrypting Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to encrypt the EDI message." },
-    "encryptingAlgorithm": { "index": 35, "kind": "parameter", "displayName": 
"Encrypting Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2EncryptionAlgorithm", "enum": [ 
"AES128_CBC", "AES192_CBC", "AES256_CBC", "AES128_CCM", "AES192_CCM", 
"AES256_CCM", "AES128_GCM", "AES192_GCM", "AES256_GCM", "CAMELLIA128_CBC", 
"CAMELLIA192_CBC", "CAMELLIA256_CBC", "CAST5_CBC", "DES_CBC", "DES_EDE3_CBC", 
"GOST28 [...]
-    "encryptingCertificateChain": { "index": 36, "kind": "parameter", 
"displayName": "Encrypting Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to encrypt EDI 
message." },
-    "hostnameVerifier": { "index": 37, "kind": "parameter", "displayName": 
"Hostname Verifier", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "javax.net.ssl.HostnameVerifier", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set hostname verifier for SSL session." },
-    "mdnAccessToken": { "index": 38, "kind": "parameter", "displayName": "Mdn 
Access Token", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The access token that is used by the server 
when it sends an async MDN." },
-    "mdnPassword": { "index": 39, "kind": "parameter", "displayName": "Mdn 
Password", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the server for 
basic authentication when it sends an async MDN." },
-    "mdnUserName": { "index": 40, "kind": "parameter", "displayName": "Mdn 
User Name", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the server for 
basic authentication when it sends an async MDN. If options for  [...]
-    "password": { "index": 41, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the client for 
basic authentication." },
-    "signedReceiptMicAlgorithms": { "index": 42, "kind": "parameter", 
"displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "The list of algorithms, 
in order of preference, requested to generate a messa [...]
-    "signingAlgorithm": { "index": 43, "kind": "parameter", "displayName": 
"Signing Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ 
"SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", 
"MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", 
"SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", 
"RIPEMD256 [...]
-    "signingCertificateChain": { "index": 44, "kind": "parameter", 
"displayName": "Signing Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to sign EDI 
message." },
-    "signingPrivateKey": { "index": 45, "kind": "parameter", "displayName": 
"Signing Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to sign the EDI message." },
-    "sslContext": { "index": 46, "kind": "parameter", "displayName": "Ssl 
Context", "group": "security", "label": "security", "required": false, "type": 
"object", "javaType": "javax.net.ssl.SSLContext", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set SSL context for connection to remote 
server." },
-    "userName": { "index": 47, "kind": "parameter", "displayName": "User 
Name", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the client for 
basic authentication. If options for basic authentication and bearer au [...]
-    "validateSigningCertificateChain": { "index": 48, "kind": "parameter", 
"displayName": "Validate Signing Certificate Chain", "group": "security", 
"label": "security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Certificates to validate the message's 
signature ag [...]
+    "asyncMdnAllowedHosts": { "index": 34, "kind": "parameter", "displayName": 
"Async Mdn Allowed Hosts", "group": "security", "label": "security", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Comma separated list of host names an 
asynchronous MDN may be delivered to. The delivery  [...]
+    "decryptingPrivateKey": { "index": 35, "kind": "parameter", "displayName": 
"Decrypting Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to encrypt the EDI message." },
+    "encryptingAlgorithm": { "index": 36, "kind": "parameter", "displayName": 
"Encrypting Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2EncryptionAlgorithm", "enum": [ 
"AES128_CBC", "AES192_CBC", "AES256_CBC", "AES128_CCM", "AES192_CCM", 
"AES256_CCM", "AES128_GCM", "AES192_GCM", "AES256_GCM", "CAMELLIA128_CBC", 
"CAMELLIA192_CBC", "CAMELLIA256_CBC", "CAST5_CBC", "DES_CBC", "DES_EDE3_CBC", 
"GOST28 [...]
+    "encryptingCertificateChain": { "index": 37, "kind": "parameter", 
"displayName": "Encrypting Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to encrypt EDI 
message." },
+    "hostnameVerifier": { "index": 38, "kind": "parameter", "displayName": 
"Hostname Verifier", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "javax.net.ssl.HostnameVerifier", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set hostname verifier for SSL session." },
+    "mdnAccessToken": { "index": 39, "kind": "parameter", "displayName": "Mdn 
Access Token", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The access token that is used by the server 
when it sends an async MDN." },
+    "mdnPassword": { "index": 40, "kind": "parameter", "displayName": "Mdn 
Password", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the server for 
basic authentication when it sends an async MDN." },
+    "mdnUserName": { "index": 41, "kind": "parameter", "displayName": "Mdn 
User Name", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the server for 
basic authentication when it sends an async MDN. If options for  [...]
+    "password": { "index": 42, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the client for 
basic authentication." },
+    "signedReceiptMicAlgorithms": { "index": 43, "kind": "parameter", 
"displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "The list of algorithms, 
in order of preference, requested to generate a messa [...]
+    "signingAlgorithm": { "index": 44, "kind": "parameter", "displayName": 
"Signing Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ 
"SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", 
"MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", 
"SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", 
"RIPEMD256 [...]
+    "signingCertificateChain": { "index": 45, "kind": "parameter", 
"displayName": "Signing Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to sign EDI 
message." },
+    "signingPrivateKey": { "index": 46, "kind": "parameter", "displayName": 
"Signing Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to sign the EDI message." },
+    "sslContext": { "index": 47, "kind": "parameter", "displayName": "Ssl 
Context", "group": "security", "label": "security", "required": false, "type": 
"object", "javaType": "javax.net.ssl.SSLContext", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set SSL context for connection to remote 
server." },
+    "userName": { "index": 48, "kind": "parameter", "displayName": "User 
Name", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the client for 
basic authentication. If options for basic authentication and bearer au [...]
+    "validateSigningCertificateChain": { "index": 49, "kind": "parameter", 
"displayName": "Validate Signing Certificate Chain", "group": "security", 
"label": "security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Certificates to validate the message's 
signature ag [...]
   },
   "apis": {
     "client": { "consumerOnly": false, "producerOnly": true, "description": 
"Sends EDI Messages over HTTP", "methods": { "send": { "description": "Send 
ediMessage to trading partner", "signatures": [ 
"org.apache.hc.core5.http.protocol.HttpCoreContext send(Object ediMessage, 
String requestUri, String subject, String from, String as2From, String as2To, 
org.apache.camel.component.as2.api.AS2MessageStructure as2MessageStructure, 
String ediMessageContentType, String ediMessageCharset, String  [...]
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2AsynchronousMDNManager.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2AsynchronousMDNManager.java
index 3a922227d4ac..ed8b3b2e709f 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2AsynchronousMDNManager.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2AsynchronousMDNManager.java
@@ -21,6 +21,7 @@ import java.net.Socket;
 import java.net.URI;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
+import java.util.Locale;
 
 import org.apache.camel.component.as2.api.entity.MultipartMimeEntity;
 import org.apache.camel.component.as2.api.protocol.RequestAsynchronousMDN;
@@ -46,9 +47,13 @@ import org.apache.hc.core5.http.protocol.RequestContent;
 import org.apache.hc.core5.http.protocol.RequestDate;
 import org.apache.hc.core5.http.protocol.RequestTargetHost;
 import org.apache.hc.core5.http.protocol.RequestUserAgent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class AS2AsynchronousMDNManager {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(AS2AsynchronousMDNManager.class);
+
     //
     // AS2 HTTP Context Attribute Keys
     //
@@ -92,7 +97,15 @@ public class AS2AsynchronousMDNManager {
     private String userName;
     private String password;
     private String accessToken;
+    private String allowedHosts;
 
+    /**
+     * @deprecated use
+     *             {@link #AS2AsynchronousMDNManager(String, String, String, 
Certificate[], PrivateKey, String, String, String, String)}
+     *             which also takes the allowed delivery hosts. This 
constructor delivers the MDN without attaching the
+     *             configured credentials, because no allow-list is supplied.
+     */
+    @Deprecated
     public AS2AsynchronousMDNManager(String as2Version,
                                      String userAgent,
                                      String senderFQDN,
@@ -101,6 +114,20 @@ public class AS2AsynchronousMDNManager {
                                      String userName,
                                      String password,
                                      String accessToken) {
+        this(as2Version, userAgent, senderFQDN, signingCertificateChain, 
signingPrivateKey, userName, password,
+             accessToken, null);
+    }
+
+    public AS2AsynchronousMDNManager(String as2Version,
+                                     String userAgent,
+                                     String senderFQDN,
+                                     Certificate[] signingCertificateChain,
+                                     PrivateKey signingPrivateKey,
+                                     String userName,
+                                     String password,
+                                     String accessToken,
+                                     String allowedHosts) {
+        this.allowedHosts = allowedHosts;
         this.signingCertificateChain = signingCertificateChain;
         this.signingPrivateKey = signingPrivateKey;
         this.userName = userName;
@@ -124,7 +151,29 @@ public class AS2AsynchronousMDNManager {
         ObjectHelper.notNull(contentType, "contentType");
         ObjectHelper.notNull(recipientDeliveryAddress, 
"recipientDeliveryAddress");
 
+        // The delivery address is chosen by the sender of the AS2 message 
(the Receipt-Delivery-Option
+        // header), so it is untrusted input that selects an outbound 
destination.
         URI uri = URI.create(recipientDeliveryAddress);
+        String scheme = uri.getScheme() == null ? null : 
uri.getScheme().toLowerCase(Locale.US);
+        // Only http. This class delivers over a plain Socket and has no TLS 
of any kind, so accepting https
+        // would mean writing the request - including the Authorization header 
- in cleartext to the TLS port.
+        // https delivery has never worked here for that reason, so refusing 
it removes nothing that functioned.
+        if (!"http".equals(scheme)) {
+            throw new HttpException(
+                    "Refusing to deliver the asynchronous MDN: the delivery 
address must use http."
+                                    + " TLS delivery of asynchronous MDNs is 
not supported");
+        }
+        String host = normalizeHost(uri.getHost());
+        if (host == null) {
+            throw new HttpException("Refusing to deliver the asynchronous MDN: 
the delivery address has no host");
+        }
+        int port = uri.getPort() != -1 ? uri.getPort() : 80;
+
+        boolean hostIsAllowed = isAllowedHost(host);
+        if (allowedHosts != null && !allowedHosts.isBlank() && !hostIsAllowed) 
{
+            throw new HttpException(
+                    "Refusing to deliver the asynchronous MDN: the delivery 
address host is not in asyncMdnAllowedHosts");
+        }
 
         int buffSize = 8 * 1024;
 
@@ -132,7 +181,7 @@ public class AS2AsynchronousMDNManager {
         HttpConnectionFactory<ManagedHttpClientConnection> connFactory
                 = 
ManagedHttpClientConnectionFactory.builder().http1Config(h1Config).build();
 
-        try (HttpClientConnection httpConnection = 
connFactory.createConnection(new Socket(uri.getHost(), uri.getPort()))) {
+        try (HttpClientConnection httpConnection = 
connFactory.createConnection(new Socket(host, port))) {
 
             // Add Context attributes
             HttpCoreContext httpContext = HttpCoreContext.create();
@@ -140,7 +189,15 @@ public class AS2AsynchronousMDNManager {
 
             ClassicHttpRequest request = new BasicClassicHttpRequest("POST", 
uri);
             request.setHeader(AS2Header.CONTENT_TYPE, contentType);
-            AS2HeaderUtils.addAuthorizationHeader(request, userName, password, 
accessToken);
+            // Credentials are only attached to a host the operator has 
vouched for. Without an allow-list the
+            // destination is entirely sender-chosen, so the MDN is still 
delivered but without them.
+            if (hostIsAllowed) {
+                AS2HeaderUtils.addAuthorizationHeader(request, userName, 
password, accessToken);
+            } else if (userName != null || accessToken != null) {
+                LOG.warn("Asynchronous MDN credentials not sent to 
sender-supplied host {}:"
+                         + " set asyncMdnAllowedHosts to authorise it",
+                        host);
+            }
             httpContext.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
             multipartMimeEntity.setMainBody(true);
             EntityUtils.setMessageEntity(request, multipartMimeEntity);
@@ -160,6 +217,29 @@ public class AS2AsynchronousMDNManager {
         }
     }
 
+    /**
+     * {@link URI#getHost()} returns an IPv6 literal in its bracketed form 
({@code [::1]}), which would never match an
+     * allow-list entry written the way an operator writes it. Compare the 
address itself.
+     */
+    private static String normalizeHost(String host) {
+        if (host != null && host.length() > 1 && host.charAt(0) == '[' && 
host.charAt(host.length() - 1) == ']') {
+            return host.substring(1, host.length() - 1);
+        }
+        return host;
+    }
+
+    private boolean isAllowedHost(String host) {
+        if (allowedHosts == null || allowedHosts.isBlank()) {
+            return false;
+        }
+        for (String allowed : allowedHosts.split(",")) {
+            if (allowed.trim().equalsIgnoreCase(host)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private HttpResponse send(HttpClientConnection httpConnection, 
ClassicHttpRequest request, HttpCoreContext httpContext)
             throws HttpException, IOException {
 
diff --git 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
index cf4b5c79ebc5..895cf21af273 100644
--- 
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
+++ 
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ServerConnection.java
@@ -90,6 +90,7 @@ public class AS2ServerConnection {
     private final String userName;
     private final String password;
     private final String accessToken;
+    private final String asyncMdnAllowedHosts;
 
     /**
      * Stores the configuration for each consumer endpoint path (e.g., 
"/consumerA"). Uses LinkedHashMap to preserve
@@ -496,7 +497,8 @@ public class AS2ServerConnection {
                                 config.getSigningPrivateKey(),
                                 AS2ServerConnection.this.userName,
                                 AS2ServerConnection.this.password,
-                                AS2ServerConnection.this.accessToken);
+                                AS2ServerConnection.this.accessToken,
+                                AS2ServerConnection.this.asyncMdnAllowedHosts);
 
                         HttpRequest request = 
coreContext.getAttribute(HttpCoreContext.HTTP_REQUEST, HttpRequest.class);
                         AS2SignedDataGenerator gen = 
ResponseMDN.createSigningGenerator(
@@ -556,6 +558,28 @@ public class AS2ServerConnection {
                                String password,
                                String accessToken)
                                                    throws IOException {
+        this(as2Version, originServer, serverFqdn, serverPortNumber, 
signingAlgorithm, signingCertificateChain,
+             signingPrivateKey, decryptingPrivateKey, mdnMessageTemplate, 
validateSigningCertificateChain, sslContext,
+             userName, password, accessToken, null);
+    }
+
+    public AS2ServerConnection(String as2Version,
+                               String originServer,
+                               String serverFqdn,
+                               Integer serverPortNumber,
+                               AS2SignatureAlgorithm signingAlgorithm,
+                               Certificate[] signingCertificateChain,
+                               PrivateKey signingPrivateKey,
+                               PrivateKey decryptingPrivateKey,
+                               String mdnMessageTemplate,
+                               Certificate[] validateSigningCertificateChain,
+                               SSLContext sslContext,
+                               String userName,
+                               String password,
+                               String accessToken,
+                               String asyncMdnAllowedHosts)
+                                                            throws IOException 
{
+        this.asyncMdnAllowedHosts = asyncMdnAllowedHosts;
         this.as2Version = ObjectHelper.notNull(as2Version, "as2Version");
         this.originServer = ObjectHelper.notNull(originServer, "userAgent");
         this.serverFqdn = ObjectHelper.notNull(serverFqdn, "serverFqdn");
diff --git 
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2AsynchronousMDNManagerDeliveryAddressTest.java
 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2AsynchronousMDNManagerDeliveryAddressTest.java
new file mode 100644
index 000000000000..09ea7b6cca42
--- /dev/null
+++ 
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2AsynchronousMDNManagerDeliveryAddressTest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.as2.api;
+
+import org.apache.camel.component.as2.api.entity.MultipartMimeEntity;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.HttpException;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The delivery address for an asynchronous MDN comes from the {@code 
Receipt-Delivery-Option} header of the received
+ * AS2 message, so it is chosen by the sender. It selects an outbound 
destination and, before this was constrained, the
+ * configured MDN credentials went with it.
+ */
+class AS2AsynchronousMDNManagerDeliveryAddressTest {
+
+    private static final String ALLOWED = "partner.example";
+
+    /**
+     * https in particular: this class delivers over a plain {@link 
java.net.Socket} and has no TLS, so accepting an
+     * https address would write the request - including the Authorization 
header - in cleartext to the TLS port. Before
+     * the delivery address was validated at all, an https address without an 
explicit port failed closed on
+     * {@code new Socket(host, -1)}; resolving it to 443 instead would have 
been a regression.
+     */
+    @Test
+    void aSchemeOtherThanHttpIsRefused() {
+        for (String address : new String[] {
+                "https://partner.example/receipts";, 
"https://partner.example:443/receipts";,
+                "file:///etc/passwd", "ftp://partner.example/x";, 
"gopher://partner.example:70/x";, "//partner.example/x" }) {
+            HttpException e = assertThrows(HttpException.class, () -> 
deliver(address, ALLOWED),
+                    "expected " + address + " to be refused");
+            assertTrue(e.getMessage().contains("must use http") || 
e.getMessage().contains("no host"),
+                    "unexpected message for " + address + ": " + 
e.getMessage());
+        }
+    }
+
+    @Test
+    void aHostOutsideTheAllowListIsRefused() {
+        HttpException e = assertThrows(HttpException.class,
+                () -> deliver("http://attacker.example/receipts";, ALLOWED));
+        assertTrue(e.getMessage().contains("asyncMdnAllowedHosts"), 
"unexpected message: " + e.getMessage());
+    }
+
+    /**
+     * With no allow-list the MDN is still delivered, so this gets past the 
address checks and fails on the connection
+     * instead - which is what tells us the address itself was accepted.
+     */
+    @Test
+    void withNoAllowListTheAddressIsStillAccepted() {
+        Exception e = assertThrows(Exception.class,
+                () -> deliver("http://localhost:1/receipts";, null));
+        assertTrue(!(e instanceof HttpException) || 
!e.getMessage().contains("asyncMdnAllowedHosts"),
+                "the address must not be refused when no allow-list is 
configured: " + e.getMessage());
+    }
+
+    @Test
+    void anIpv6AllowListEntryIsMatchedWithoutItsBrackets() {
+        // URI.getHost() yields "[::1]", but an operator writes "::1" in the 
allow-list
+        Exception e = assertThrows(Exception.class, () -> 
deliver("http://[::1]:1/receipts";, "::1"));
+        assertTrue(!(e instanceof HttpException) || 
!e.getMessage().contains("asyncMdnAllowedHosts"),
+                "an IPv6 literal should match its unbracketed allow-list 
entry: " + e.getMessage());
+    }
+
+    private static void deliver(String deliveryAddress, String allowedHosts) 
throws Exception {
+        AS2AsynchronousMDNManager manager = new AS2AsynchronousMDNManager(
+                "1.1", "Camel", "sender.example.com", null, null, "user", 
"password", null, allowedHosts);
+        manager.send(new TestEntity(), AS2MimeType.MULTIPART_REPORT, 
deliveryAddress);
+    }
+
+    /**
+     * The manager null-checks its entity before it looks at the delivery 
address, so the address checks need a real
+     * one. Its content is irrelevant here - none of these cases reach the 
point of writing it.
+     */
+    private static final class TestEntity extends MultipartMimeEntity {
+
+        private TestEntity() {
+            super(ContentType.create(AS2MimeType.MULTIPART_REPORT), "7bit");
+        }
+
+        @Override
+        public void close() {
+            // nothing to release
+        }
+    }
+}
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2AsyncMDNServerManagerEndpointConfigurationConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2AsyncMDNServerManagerEndpointConfigurationConfigurer.java
index 214852589959..b5d43287bf4d 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2AsyncMDNServerManagerEndpointConfigurationConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2AsyncMDNServerManagerEndpointConfigurationConfigurer.java
@@ -28,6 +28,7 @@ public class 
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
         map.put("As2MessageStructure", 
org.apache.camel.component.as2.api.AS2MessageStructure.class);
         map.put("As2To", java.lang.String.class);
         map.put("As2Version", java.lang.String.class);
+        map.put("AsyncMdnAllowedHosts", java.lang.String.class);
         map.put("AsyncMdnPortNumber", java.lang.Integer.class);
         map.put("AttachedFileName", java.lang.String.class);
         map.put("ClientFqdn", java.lang.String.class);
@@ -87,6 +88,8 @@ public class 
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
         case "as2To": target.setAs2To(property(camelContext, 
java.lang.String.class, value)); return true;
         case "as2version":
         case "as2Version": target.setAs2Version(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": 
target.setAsyncMdnAllowedHosts(property(camelContext, java.lang.String.class, 
value)); return true;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": 
target.setAsyncMdnPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
         case "attachedfilename":
@@ -187,6 +190,8 @@ public class 
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
         case "as2To": return java.lang.String.class;
         case "as2version":
         case "as2Version": return java.lang.String.class;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return java.lang.String.class;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return java.lang.Integer.class;
         case "attachedfilename":
@@ -283,6 +288,8 @@ public class 
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
         case "as2To": return target.getAs2To();
         case "as2version":
         case "as2Version": return target.getAs2Version();
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return target.getAsyncMdnAllowedHosts();
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return target.getAsyncMdnPortNumber();
         case "attachedfilename":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ClientManagerEndpointConfigurationConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ClientManagerEndpointConfigurationConfigurer.java
index f24e86349b8d..6712d20d0868 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ClientManagerEndpointConfigurationConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ClientManagerEndpointConfigurationConfigurer.java
@@ -28,6 +28,7 @@ public class AS2ClientManagerEndpointConfigurationConfigurer 
extends org.apache.
         map.put("As2MessageStructure", 
org.apache.camel.component.as2.api.AS2MessageStructure.class);
         map.put("As2To", java.lang.String.class);
         map.put("As2Version", java.lang.String.class);
+        map.put("AsyncMdnAllowedHosts", java.lang.String.class);
         map.put("AsyncMdnPortNumber", java.lang.Integer.class);
         map.put("AttachedFileName", java.lang.String.class);
         map.put("ClientFqdn", java.lang.String.class);
@@ -88,6 +89,8 @@ public class AS2ClientManagerEndpointConfigurationConfigurer 
extends org.apache.
         case "as2To": target.setAs2To(property(camelContext, 
java.lang.String.class, value)); return true;
         case "as2version":
         case "as2Version": target.setAs2Version(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": 
target.setAsyncMdnAllowedHosts(property(camelContext, java.lang.String.class, 
value)); return true;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": 
target.setAsyncMdnPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
         case "attachedfilename":
@@ -190,6 +193,8 @@ public class 
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
         case "as2To": return java.lang.String.class;
         case "as2version":
         case "as2Version": return java.lang.String.class;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return java.lang.String.class;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return java.lang.Integer.class;
         case "attachedfilename":
@@ -288,6 +293,8 @@ public class 
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
         case "as2To": return target.getAs2To();
         case "as2version":
         case "as2Version": return target.getAs2Version();
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return target.getAsyncMdnAllowedHosts();
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return target.getAsyncMdnPortNumber();
         case "attachedfilename":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ConfigurationConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ConfigurationConfigurer.java
index ae58d63e5403..44315e8155e5 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ConfigurationConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ConfigurationConfigurer.java
@@ -28,6 +28,7 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         map.put("As2MessageStructure", 
org.apache.camel.component.as2.api.AS2MessageStructure.class);
         map.put("As2To", java.lang.String.class);
         map.put("As2Version", java.lang.String.class);
+        map.put("AsyncMdnAllowedHosts", java.lang.String.class);
         map.put("AsyncMdnPortNumber", java.lang.Integer.class);
         map.put("AttachedFileName", java.lang.String.class);
         map.put("ClientFqdn", java.lang.String.class);
@@ -86,6 +87,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "as2To": target.setAs2To(property(camelContext, 
java.lang.String.class, value)); return true;
         case "as2version":
         case "as2Version": target.setAs2Version(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": 
target.setAsyncMdnAllowedHosts(property(camelContext, java.lang.String.class, 
value)); return true;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": 
target.setAsyncMdnPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
         case "attachedfilename":
@@ -184,6 +187,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "as2To": return java.lang.String.class;
         case "as2version":
         case "as2Version": return java.lang.String.class;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return java.lang.String.class;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return java.lang.Integer.class;
         case "attachedfilename":
@@ -278,6 +283,8 @@ public class AS2ConfigurationConfigurer extends 
org.apache.camel.support.compone
         case "as2To": return target.getAs2To();
         case "as2version":
         case "as2Version": return target.getAs2Version();
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return target.getAsyncMdnAllowedHosts();
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return target.getAsyncMdnPortNumber();
         case "attachedfilename":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointConfigurer.java
index 4de2c44bd707..0eab1fb6e4b0 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointConfigurer.java
@@ -56,6 +56,7 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         map.put("ExchangePattern", org.apache.camel.ExchangePattern.class);
         map.put("LazyStartProducer", boolean.class);
         map.put("AccessToken", java.lang.String.class);
+        map.put("AsyncMdnAllowedHosts", java.lang.String.class);
         map.put("DecryptingPrivateKey", java.security.PrivateKey.class);
         map.put("EncryptingAlgorithm", 
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class);
         map.put("EncryptingCertificateChain", 
java.security.cert.Certificate[].class);
@@ -88,6 +89,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "as2To": 
target.getConfiguration().setAs2To(property(camelContext, 
java.lang.String.class, value)); return true;
         case "as2version":
         case "as2Version": 
target.getConfiguration().setAs2Version(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": 
target.getConfiguration().setAsyncMdnAllowedHosts(property(camelContext, 
java.lang.String.class, value)); return true;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": 
target.getConfiguration().setAsyncMdnPortNumber(property(camelContext, 
java.lang.Integer.class, value)); return true;
         case "attachedfilename":
@@ -190,6 +193,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "as2To": return java.lang.String.class;
         case "as2version":
         case "as2Version": return java.lang.String.class;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return java.lang.String.class;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return java.lang.Integer.class;
         case "attachedfilename":
@@ -288,6 +293,8 @@ public class AS2EndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "as2To": return target.getConfiguration().getAs2To();
         case "as2version":
         case "as2Version": return target.getConfiguration().getAs2Version();
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return 
target.getConfiguration().getAsyncMdnAllowedHosts();
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return 
target.getConfiguration().getAsyncMdnPortNumber();
         case "attachedfilename":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointUriFactory.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointUriFactory.java
index 96060d107c99..0d45c9920fff 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointUriFactory.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2EndpointUriFactory.java
@@ -23,13 +23,14 @@ public class AS2EndpointUriFactory extends 
org.apache.camel.support.component.En
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(52);
+        Set<String> props = new HashSet<>(53);
         props.add("accessToken");
         props.add("apiName");
         props.add("as2From");
         props.add("as2MessageStructure");
         props.add("as2To");
         props.add("as2Version");
+        props.add("asyncMdnAllowedHosts");
         props.add("asyncMdnPortNumber");
         props.add("attachedFileName");
         props.add("clientFqdn");
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ServerManagerEndpointConfigurationConfigurer.java
 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ServerManagerEndpointConfigurationConfigurer.java
index dafc031b2986..da0d11a61f11 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ServerManagerEndpointConfigurationConfigurer.java
+++ 
b/components/camel-as2/camel-as2-component/src/generated/java/org/apache/camel/component/as2/AS2ServerManagerEndpointConfigurationConfigurer.java
@@ -28,6 +28,7 @@ public class AS2ServerManagerEndpointConfigurationConfigurer 
extends org.apache.
         map.put("As2MessageStructure", 
org.apache.camel.component.as2.api.AS2MessageStructure.class);
         map.put("As2To", java.lang.String.class);
         map.put("As2Version", java.lang.String.class);
+        map.put("AsyncMdnAllowedHosts", java.lang.String.class);
         map.put("AsyncMdnPortNumber", java.lang.Integer.class);
         map.put("AttachedFileName", java.lang.String.class);
         map.put("ClientFqdn", java.lang.String.class);
@@ -87,6 +88,8 @@ public class AS2ServerManagerEndpointConfigurationConfigurer 
extends org.apache.
         case "as2To": target.setAs2To(property(camelContext, 
java.lang.String.class, value)); return true;
         case "as2version":
         case "as2Version": target.setAs2Version(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": 
target.setAsyncMdnAllowedHosts(property(camelContext, java.lang.String.class, 
value)); return true;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": 
target.setAsyncMdnPortNumber(property(camelContext, java.lang.Integer.class, 
value)); return true;
         case "attachedfilename":
@@ -187,6 +190,8 @@ public class 
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
         case "as2To": return java.lang.String.class;
         case "as2version":
         case "as2Version": return java.lang.String.class;
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return java.lang.String.class;
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return java.lang.Integer.class;
         case "attachedfilename":
@@ -283,6 +288,8 @@ public class 
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
         case "as2To": return target.getAs2To();
         case "as2version":
         case "as2Version": return target.getAs2Version();
+        case "asyncmdnallowedhosts":
+        case "asyncMdnAllowedHosts": return target.getAsyncMdnAllowedHosts();
         case "asyncmdnportnumber":
         case "asyncMdnPortNumber": return target.getAsyncMdnPortNumber();
         case "attachedfilename":
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
 
b/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
index 4e0f84179c00..5713cb8a636e 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
+++ 
b/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
@@ -67,21 +67,22 @@
     "exchangePattern": { "index": 31, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
     "lazyStartProducer": { "index": 32, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
     "accessToken": { "index": 33, "kind": "parameter", "displayName": "Access 
Token", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The access token that is used by the client 
for bearer authentication." },
-    "decryptingPrivateKey": { "index": 34, "kind": "parameter", "displayName": 
"Decrypting Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to encrypt the EDI message." },
-    "encryptingAlgorithm": { "index": 35, "kind": "parameter", "displayName": 
"Encrypting Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2EncryptionAlgorithm", "enum": [ 
"AES128_CBC", "AES192_CBC", "AES256_CBC", "AES128_CCM", "AES192_CCM", 
"AES256_CCM", "AES128_GCM", "AES192_GCM", "AES256_GCM", "CAMELLIA128_CBC", 
"CAMELLIA192_CBC", "CAMELLIA256_CBC", "CAST5_CBC", "DES_CBC", "DES_EDE3_CBC", 
"GOST28 [...]
-    "encryptingCertificateChain": { "index": 36, "kind": "parameter", 
"displayName": "Encrypting Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to encrypt EDI 
message." },
-    "hostnameVerifier": { "index": 37, "kind": "parameter", "displayName": 
"Hostname Verifier", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "javax.net.ssl.HostnameVerifier", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set hostname verifier for SSL session." },
-    "mdnAccessToken": { "index": 38, "kind": "parameter", "displayName": "Mdn 
Access Token", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The access token that is used by the server 
when it sends an async MDN." },
-    "mdnPassword": { "index": 39, "kind": "parameter", "displayName": "Mdn 
Password", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the server for 
basic authentication when it sends an async MDN." },
-    "mdnUserName": { "index": 40, "kind": "parameter", "displayName": "Mdn 
User Name", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the server for 
basic authentication when it sends an async MDN. If options for  [...]
-    "password": { "index": 41, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the client for 
basic authentication." },
-    "signedReceiptMicAlgorithms": { "index": 42, "kind": "parameter", 
"displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "The list of algorithms, 
in order of preference, requested to generate a messa [...]
-    "signingAlgorithm": { "index": 43, "kind": "parameter", "displayName": 
"Signing Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ 
"SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", 
"MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", 
"SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", 
"RIPEMD256 [...]
-    "signingCertificateChain": { "index": 44, "kind": "parameter", 
"displayName": "Signing Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to sign EDI 
message." },
-    "signingPrivateKey": { "index": 45, "kind": "parameter", "displayName": 
"Signing Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to sign the EDI message." },
-    "sslContext": { "index": 46, "kind": "parameter", "displayName": "Ssl 
Context", "group": "security", "label": "security", "required": false, "type": 
"object", "javaType": "javax.net.ssl.SSLContext", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set SSL context for connection to remote 
server." },
-    "userName": { "index": 47, "kind": "parameter", "displayName": "User 
Name", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the client for 
basic authentication. If options for basic authentication and bearer au [...]
-    "validateSigningCertificateChain": { "index": 48, "kind": "parameter", 
"displayName": "Validate Signing Certificate Chain", "group": "security", 
"label": "security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Certificates to validate the message's 
signature ag [...]
+    "asyncMdnAllowedHosts": { "index": 34, "kind": "parameter", "displayName": 
"Async Mdn Allowed Hosts", "group": "security", "label": "security", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Comma separated list of host names an 
asynchronous MDN may be delivered to. The delivery  [...]
+    "decryptingPrivateKey": { "index": 35, "kind": "parameter", "displayName": 
"Decrypting Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to encrypt the EDI message." },
+    "encryptingAlgorithm": { "index": 36, "kind": "parameter", "displayName": 
"Encrypting Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2EncryptionAlgorithm", "enum": [ 
"AES128_CBC", "AES192_CBC", "AES256_CBC", "AES128_CCM", "AES192_CCM", 
"AES256_CCM", "AES128_GCM", "AES192_GCM", "AES256_GCM", "CAMELLIA128_CBC", 
"CAMELLIA192_CBC", "CAMELLIA256_CBC", "CAST5_CBC", "DES_CBC", "DES_EDE3_CBC", 
"GOST28 [...]
+    "encryptingCertificateChain": { "index": 37, "kind": "parameter", 
"displayName": "Encrypting Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to encrypt EDI 
message." },
+    "hostnameVerifier": { "index": 38, "kind": "parameter", "displayName": 
"Hostname Verifier", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "javax.net.ssl.HostnameVerifier", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set hostname verifier for SSL session." },
+    "mdnAccessToken": { "index": 39, "kind": "parameter", "displayName": "Mdn 
Access Token", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The access token that is used by the server 
when it sends an async MDN." },
+    "mdnPassword": { "index": 40, "kind": "parameter", "displayName": "Mdn 
Password", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the server for 
basic authentication when it sends an async MDN." },
+    "mdnUserName": { "index": 41, "kind": "parameter", "displayName": "Mdn 
User Name", "group": "security", "label": "security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the server for 
basic authentication when it sends an async MDN. If options for  [...]
+    "password": { "index": 42, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The password that is used by the client for 
basic authentication." },
+    "signedReceiptMicAlgorithms": { "index": 43, "kind": "parameter", 
"displayName": "Signed Receipt Mic Algorithms", "group": "security", "label": 
"security", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.as2.AS2Configuration", 
"configurationField": "configuration", "description": "The list of algorithms, 
in order of preference, requested to generate a messa [...]
+    "signingAlgorithm": { "index": 44, "kind": "parameter", "displayName": 
"Signing Algorithm", "group": "security", "label": "security", "required": 
false, "type": "enum", "javaType": 
"org.apache.camel.component.as2.api.AS2SignatureAlgorithm", "enum": [ 
"SHA3_224WITHRSA", "SHA3_256WITHRSA", "SHA3_384withRSA", "SHA3_512WITHRSA", 
"MD5WITHRSA", "SHA1WITHRSA", "MD2WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", 
"SHA384WITHRSA", "SHA512WITHRSA", "RIPEMD128WITHRSA", "RIPEMD160WITHRSA", 
"RIPEMD256 [...]
+    "signingCertificateChain": { "index": 45, "kind": "parameter", 
"displayName": "Signing Certificate Chain", "group": "security", "label": 
"security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The chain of certificates used to sign EDI 
message." },
+    "signingPrivateKey": { "index": 46, "kind": "parameter", "displayName": 
"Signing Private Key", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": "java.security.PrivateKey", "deprecated": 
false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The key used to sign the EDI message." },
+    "sslContext": { "index": 47, "kind": "parameter", "displayName": "Ssl 
Context", "group": "security", "label": "security", "required": false, "type": 
"object", "javaType": "javax.net.ssl.SSLContext", "deprecated": false, 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Set SSL context for connection to remote 
server." },
+    "userName": { "index": 48, "kind": "parameter", "displayName": "User 
Name", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "The user-name that is used by the client for 
basic authentication. If options for basic authentication and bearer au [...]
+    "validateSigningCertificateChain": { "index": 49, "kind": "parameter", 
"displayName": "Validate Signing Certificate Chain", "group": "security", 
"label": "security", "required": false, "type": "object", "javaType": 
"java.security.cert.Certificate[]", "deprecated": false, "autowired": false, 
"secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "Certificates to validate the message's 
signature ag [...]
   },
   "apis": {
     "client": { "consumerOnly": false, "producerOnly": true, "description": 
"Sends EDI Messages over HTTP", "methods": { "send": { "description": "Send 
ediMessage to trading partner", "signatures": [ 
"org.apache.hc.core5.http.protocol.HttpCoreContext send(Object ediMessage, 
String requestUri, String subject, String from, String as2From, String as2To, 
org.apache.camel.component.as2.api.AS2MessageStructure as2MessageStructure, 
String ediMessageContentType, String ediMessageCharset, String  [...]
diff --git 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
index 1baa79db7eda..e03d3d8a38f2 100644
--- 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
+++ 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Configuration.java
@@ -116,6 +116,8 @@ public class AS2Configuration {
     private Certificate[] validateSigningCertificateChain;
     @UriParam(label = "security")
     private SSLContext sslContext;
+    @UriParam(label = "security")
+    private String asyncMdnAllowedHosts;
     // If you use localhost-based AS2 server, you don't need to specify a 
hostnameVerifier
     @UriParam(label = "security")
     private HostnameVerifier hostnameVerifier;
@@ -653,4 +655,20 @@ public class AS2Configuration {
     public void setMdnAccessToken(String accessToken) {
         this.mdnAccessToken = accessToken;
     }
+
+    public String getAsyncMdnAllowedHosts() {
+        return asyncMdnAllowedHosts;
+    }
+
+    /**
+     * Comma separated list of host names an asynchronous MDN may be delivered 
to. The delivery address is chosen by the
+     * sender of the AS2 message, so this is the list of hosts the operator 
vouches for.
+     *
+     * When set, an asynchronous MDN whose delivery address names a host 
outside the list is refused, and the configured
+     * mdnUserName/mdnPassword/mdnAccessToken are attached only to a host on 
the list. When not set, the MDN is still
+     * delivered to the sender-supplied address but no credentials are 
attached.
+     */
+    public void setAsyncMdnAllowedHosts(String asyncMdnAllowedHosts) {
+        this.asyncMdnAllowedHosts = asyncMdnAllowedHosts;
+    }
 }
diff --git 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/internal/AS2ConnectionHelper.java
 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/internal/AS2ConnectionHelper.java
index c8d405f9982e..15474412e8df 100644
--- 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/internal/AS2ConnectionHelper.java
+++ 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/internal/AS2ConnectionHelper.java
@@ -110,7 +110,8 @@ public final class AS2ConnectionHelper {
                                     
configuration.getValidateSigningCertificateChain(),
                                     configuration.getSslContext(),
                                     configuration.getMdnUserName(), 
configuration.getMdnPassword(),
-                                    configuration.getMdnAccessToken());
+                                    configuration.getMdnAccessToken(),
+                                    configuration.getAsyncMdnAllowedHosts());
                         } catch (IOException e) {
                             throw new UncheckedIOException(e);
                         }
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2AsyncMdnBasicAuthHeaderTest.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2AsyncMdnBasicAuthHeaderTest.java
index 28311799b012..52cf5658acf0 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2AsyncMdnBasicAuthHeaderTest.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2AsyncMdnBasicAuthHeaderTest.java
@@ -195,7 +195,10 @@ public class AS2AsyncMdnBasicAuthHeaderTest extends 
AbstractAS2ITSupport {
                 null, null, null,
                 "TBD", null, null,
                 // server authorization config
-                MDN_USER_NAME, MDN_PASSWORD, MDN_ACCESS_TOKEN);
+                MDN_USER_NAME, MDN_PASSWORD, MDN_ACCESS_TOKEN,
+                // the MDN delivery address comes from the 
receiptDeliveryOption header, so the host it names
+                // has to be authorised before the credentials above are 
attached to it
+                "localhost");
         serverConnection.listen("/", new 
AS2AsyncMDNServerManagerIT.RequestHandler());
     }
 }
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2AsyncMdnTokenAuthHeaderTest.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2AsyncMdnTokenAuthHeaderTest.java
index 152aef0bd191..62685a588c05 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2AsyncMdnTokenAuthHeaderTest.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2AsyncMdnTokenAuthHeaderTest.java
@@ -147,7 +147,10 @@ public class AS2AsyncMdnTokenAuthHeaderTest extends 
AbstractAS2ITSupport {
                 null, null, null,
                 "TBD", null, null,
                 // server authorization config
-                null, null, MDN_ACCESS_TOKEN);
+                null, null, MDN_ACCESS_TOKEN,
+                // the MDN delivery address comes from the 
receiptDeliveryOption header, so the host it names
+                // has to be authorised before the credentials above are 
attached to it
+                "localhost");
         serverConnection.listen("/", new 
AS2AsyncMDNServerManagerIT.RequestHandler());
     }
 }
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerBasicAuthHeaderTest.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerBasicAuthHeaderTest.java
index 62d99d7caab6..8114e3d7476c 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerBasicAuthHeaderTest.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerBasicAuthHeaderTest.java
@@ -125,5 +125,8 @@ public class AS2ServerBasicAuthHeaderTest extends 
AbstractAS2ITSupport {
     @Override
     protected void customizeConfiguration(AS2Configuration configuration) {
         configuration.setServerPortNumber(TARGET_PORT);
+        // The MDN credentials are only attached to a delivery host the 
operator has authorised, and the
+        // delivery address here comes from the receiptDeliveryOption header, 
so localhost has to be listed.
+        configuration.setAsyncMdnAllowedHosts("localhost");
     }
 }
diff --git 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerBearerAuthHeaderTest.java
 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerBearerAuthHeaderTest.java
index 6033e621f080..4d338a81279b 100644
--- 
a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerBearerAuthHeaderTest.java
+++ 
b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerBearerAuthHeaderTest.java
@@ -122,5 +122,8 @@ public class AS2ServerBearerAuthHeaderTest extends 
AbstractAS2ITSupport {
     @Override
     protected void customizeConfiguration(AS2Configuration configuration) {
         configuration.setServerPortNumber(TARGET_PORT);
+        // The MDN credentials are only attached to a delivery host the 
operator has authorised, and the
+        // delivery address here comes from the receiptDeliveryOption header, 
so localhost has to be listed.
+        configuration.setAsyncMdnAllowedHosts("localhost");
     }
 }
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AS2EndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AS2EndpointBuilderFactory.java
index 4cc6029c1070..efd829f154eb 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AS2EndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/AS2EndpointBuilderFactory.java
@@ -622,6 +622,27 @@ public interface AS2EndpointBuilderFactory {
             doSetProperty("accessToken", accessToken);
             return this;
         }
+        /**
+         * Comma separated list of host names an asynchronous MDN may be
+         * delivered to. The delivery address is chosen by the sender of the 
AS2
+         * message, so this is the list of hosts the operator vouches for. When
+         * set, an asynchronous MDN whose delivery address names a host outside
+         * the list is refused, and the configured
+         * mdnUserName/mdnPassword/mdnAccessToken are attached only to a host 
on
+         * the list. When not set, the MDN is still delivered to the
+         * sender-supplied address but no credentials are attached.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: security
+         * 
+         * @param asyncMdnAllowedHosts the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointConsumerBuilder asyncMdnAllowedHosts(String 
asyncMdnAllowedHosts) {
+            doSetProperty("asyncMdnAllowedHosts", asyncMdnAllowedHosts);
+            return this;
+        }
         /**
          * The key used to encrypt the EDI message.
          * 
@@ -1653,6 +1674,27 @@ public interface AS2EndpointBuilderFactory {
             doSetProperty("accessToken", accessToken);
             return this;
         }
+        /**
+         * Comma separated list of host names an asynchronous MDN may be
+         * delivered to. The delivery address is chosen by the sender of the 
AS2
+         * message, so this is the list of hosts the operator vouches for. When
+         * set, an asynchronous MDN whose delivery address names a host outside
+         * the list is refused, and the configured
+         * mdnUserName/mdnPassword/mdnAccessToken are attached only to a host 
on
+         * the list. When not set, the MDN is still delivered to the
+         * sender-supplied address but no credentials are attached.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: security
+         * 
+         * @param asyncMdnAllowedHosts the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointProducerBuilder asyncMdnAllowedHosts(String 
asyncMdnAllowedHosts) {
+            doSetProperty("asyncMdnAllowedHosts", asyncMdnAllowedHosts);
+            return this;
+        }
         /**
          * The key used to encrypt the EDI message.
          * 
@@ -2665,6 +2707,27 @@ public interface AS2EndpointBuilderFactory {
             doSetProperty("accessToken", accessToken);
             return this;
         }
+        /**
+         * Comma separated list of host names an asynchronous MDN may be
+         * delivered to. The delivery address is chosen by the sender of the 
AS2
+         * message, so this is the list of hosts the operator vouches for. When
+         * set, an asynchronous MDN whose delivery address names a host outside
+         * the list is refused, and the configured
+         * mdnUserName/mdnPassword/mdnAccessToken are attached only to a host 
on
+         * the list. When not set, the MDN is still delivered to the
+         * sender-supplied address but no credentials are attached.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: security
+         * 
+         * @param asyncMdnAllowedHosts the value to set
+         * @return the dsl builder
+         */
+        default AS2EndpointBuilder asyncMdnAllowedHosts(String 
asyncMdnAllowedHosts) {
+            doSetProperty("asyncMdnAllowedHosts", asyncMdnAllowedHosts);
+            return this;
+        }
         /**
          * The key used to encrypt the EDI message.
          * 

Reply via email to