You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2026/08/27 04:41:01 UTC
(camel) branch camel-4.18.x updated: [backport camel-4.18.x] CAMEL-24417: camel-as2 - validate the asynchronous MDN delivery address and scope the MDN credentials (#25764)
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 <an...@gmail.com>
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) <no...@anthropic.com>
---
.../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.
*