This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 4c099102e6d6 Fix multiple AS2 component issues (#21854)
4c099102e6d6 is described below
commit 4c099102e6d62f40bd0a0ae4a72647018a58f529
Author: Guillaume Nodet <[email protected]>
AuthorDate: Tue Mar 10 07:51:20 2026 +0100
Fix multiple AS2 component issues (#21854)
* CAMEL-23064: Support non-standard content types in AS2 EDI payload
Add GenericApplicationEntity to handle EDI payloads with content types
not explicitly mapped (e.g. text/plain, application/octet-stream).
Previously, unknown content types threw a CamelException. Also fix
missing return statement in HttpMessageUtils.getEntity() for response
branch.
* CAMEL-23065: Fix MIC computation for compress-before-sign scenarios
Navigate the entity hierarchy to find the correct entity for MIC
computation per RFC 5402. For compress-before-sign, the MIC must cover
the compressed entity (what was signed), not the decompressed EDI
payload.
* CAMEL-23066: Use UUID for globally unique AS2 Message-IDs
Replace System.nanoTime() + SecureRandom with UUID.randomUUID() for
Message-ID generation. UUID v4 provides 122 random bits (vs 64 from
a single SecureRandom long) and is the standard Java approach for
globally unique identifiers.
* CAMEL-23067: Capture raw request body for signature verification
Store the raw (unparsed) request body bytes in AS2BHttpServerConnection
before MIME parsing. This allows downstream handlers to verify
signatures against the original bytes, which may differ from
re-serialized entities due to header folding and whitespace
normalization.
* CAMEL-23068: Fix CRLF line endings in MDN message template
Change DEFAULT_MDN_MESSAGE_TEMPLATE from Java text block (LF line
endings) to string concatenation with explicit CRLF. This ensures
consistent digest computation for signed MDNs, where headers are
written through CanonicalOutputStream (CRLF) but body content was
written directly with LF-only line endings.
* CAMEL-23070: Remove strict Host header validation in async MDN server
Remove RequestValidateHost interceptor from AS2AsyncMDNServerConnection
HTTP processor. AS2 async MDN requests may arrive with Host headers that
don't match the server's hostname, causing HTTP 421 rejections. Add
standard response interceptors (ResponseContent, ResponseDate,
ResponseConnControl) for proper HTTP response handling.
* CAMEL-23071: Add expectContinue endpoint parameter for AS2 client
Add boolean expectContinue parameter to AS2Configuration. When enabled,
the client sends Expect: 100-continue header before transmitting the
request body, allowing the server to reject the request early.
* CAMEL-23072: Handle Expect 100-continue on AS2 server side
Wrap the request handler with BasicHttpServerExpectationDecorator in
AS2ServerConnection. This properly handles clients sending
Expect: 100-continue by responding with 100 Continue before the client
transmits the request body.
* CAMEL-23064: Regenerate AS2 catalog and endpoint DSL
Co-Authored-By: Claude Opus 4.6 <[email protected]>
---------
Co-authored-by: Claude Opus 4.6 <[email protected]>
---
.../org/apache/camel/catalog/components/as2.json | 35 ++++----
.../as2/api/AS2AsyncMDNServerConnection.java | 16 +++-
.../component/as2/api/AS2ClientConnection.java | 18 +++-
.../component/as2/api/AS2ServerConnection.java | 7 +-
.../component/as2/api/entity/EntityParser.java | 3 +
.../as2/api/entity/GenericApplicationEntity.java | 39 ++++++++
.../as2/api/io/AS2BHttpServerConnection.java | 38 ++++++++
.../component/as2/api/protocol/ResponseMDN.java | 22 ++---
.../camel/component/as2/api/util/AS2Utils.java | 7 +-
.../camel/component/as2/api/util/EntityUtils.java | 5 +-
.../component/as2/api/util/HttpMessageUtils.java | 59 +++++++++---
.../camel/component/as2/api/util/MicUtils.java | 96 +++++++++++++++++++-
.../as2/api/AS2AsyncMDNServerConnectionTest.java | 83 +++++++++++++++++
.../api/entity/GenericApplicationEntityTest.java | 100 +++++++++++++++++++++
.../as2/api/protocol/ResponseMDNTest.java | 79 ++++++++++++++++
.../camel/component/as2/api/util/AS2UtilsTest.java | 51 +++++++++++
...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 | 35 ++++----
.../camel/component/as2/AS2Configuration.java | 16 ++++
.../as2/internal/AS2ConnectionHelper.java | 2 +-
.../endpoint/dsl/AS2EndpointBuilderFactory.java | 40 +++++++++
26 files changed, 714 insertions(+), 75 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 7caadd208337..e101116dd91f 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
@@ -65,23 +65,24 @@
"userAgent": { "index": 29, "kind": "parameter", "displayName": "User
Agent", "group": "common", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "Camel AS2 Client Endpoint",
"configurationClass": "org.apache.camel.component.as2.AS2Configuration",
"configurationField": "configuration", "description": "The value included in
the User-Agent message header identifying the AS2 user a [...]
"exceptionHandler": { "index": 30, "kind": "parameter", "displayName":
"Exception Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.",
"deprecated": false, "autowired": false, "secret": false, "description": "To
let the consumer use a custom ExceptionHandler. Notice if the option
bridgeErrorHandler is enabled then this option is not in use. By de [...]
"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 [...]
+ "expectContinue": { "index": 32, "kind": "parameter", "displayName":
"Expect Continue", "group": "producer", "label": "producer", "required": false,
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.as2.AS2Configuration", "configurationField":
"configuration", "description": "Controls whether the Expect: 100-Continue
header is included in outbound AS2 messages. W [...]
+ "lazyStartProducer": { "index": 33, "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": 34, "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": 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/AS2AsyncMDNServerConnection.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2AsyncMDNServerConnection.java
index 6cad6e5da394..ac5be366f896 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2AsyncMDNServerConnection.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2AsyncMDNServerConnection.java
@@ -40,11 +40,13 @@ import org.apache.hc.core5.http.io.HttpRequestHandler;
import org.apache.hc.core5.http.io.HttpServerConnection;
import org.apache.hc.core5.http.io.HttpServerRequestHandler;
import org.apache.hc.core5.http.io.support.BasicHttpServerRequestHandler;
-import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.protocol.HttpCoreContext;
import org.apache.hc.core5.http.protocol.HttpProcessor;
-import org.apache.hc.core5.http.protocol.RequestValidateHost;
+import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
+import org.apache.hc.core5.http.protocol.ResponseConnControl;
+import org.apache.hc.core5.http.protocol.ResponseContent;
+import org.apache.hc.core5.http.protocol.ResponseDate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -126,7 +128,11 @@ public class AS2AsyncMDNServerConnection {
SSLServerSocketFactory factory =
sslContext.getServerSocketFactory();
serverSocket = factory.createServerSocket(port);
}
- HttpProcessor httpProcessor = new DefaultHttpProcessor(new
RequestValidateHost());
+ HttpProcessor httpProcessor = HttpProcessorBuilder.create()
+ .add(new ResponseContent(true))
+ .add(new ResponseDate())
+ .add(new ResponseConnControl())
+ .build();
// Create initial empty router
currentHandler = createHandler();
// Set up the HTTP service with delegating handler
@@ -194,6 +200,10 @@ public class AS2AsyncMDNServerConnection {
final HttpContext context = HttpCoreContext.create();
try {
while (!Thread.interrupted()) {
+ // Make raw body bytes available in the context for
signature verification
+ if (this.serverConnection instanceof
AS2BHttpServerConnection as2Conn) {
+
context.setAttribute(AS2BHttpServerConnection.class.getName(), as2Conn);
+ }
this.httpService.handleRequest(this.serverConnection,
context);
}
} catch (final IOException ex) {
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientConnection.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientConnection.java
index 75c3bf78f5eb..2d2d4bc8f8f5 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientConnection.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientConnection.java
@@ -57,6 +57,7 @@ import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
import org.apache.hc.core5.http.protocol.RequestConnControl;
import org.apache.hc.core5.http.protocol.RequestContent;
import org.apache.hc.core5.http.protocol.RequestDate;
+import org.apache.hc.core5.http.protocol.RequestExpectContinue;
import org.apache.hc.core5.http.protocol.RequestTargetHost;
import org.apache.hc.core5.http.protocol.RequestUserAgent;
import org.apache.hc.core5.net.URIAuthority;
@@ -80,6 +81,15 @@ public class AS2ClientConnection {
Integer targetPortNumber, Duration
socketTimeout, Duration connectionTimeout,
Integer connectionPoolMaxSize, Duration
connectionPoolTtl,
SSLContext sslContext, HostnameVerifier
hostnameVerifier) throws IOException {
+ this(as2Version, userAgent, clientFqdn, targetHostName,
targetPortNumber, socketTimeout, connectionTimeout,
+ connectionPoolMaxSize, connectionPoolTtl, sslContext,
hostnameVerifier, false);
+ }
+
+ public AS2ClientConnection(String as2Version, String userAgent, String
clientFqdn, String targetHostName,
+ Integer targetPortNumber, Duration
socketTimeout, Duration connectionTimeout,
+ Integer connectionPoolMaxSize, Duration
connectionPoolTtl,
+ SSLContext sslContext, HostnameVerifier
hostnameVerifier,
+ boolean expectContinue) throws IOException {
this.as2Version = ObjectHelper.notNull(as2Version, "as2Version");
this.userAgent = ObjectHelper.notNull(userAgent, "userAgent");
@@ -94,14 +104,18 @@ public class AS2ClientConnection {
ObjectHelper.notNull(connectionPoolTtl, "connectionPoolTtl");
// Build Processor
- httpProcessor = HttpProcessorBuilder.create()
+ HttpProcessorBuilder processorBuilder = HttpProcessorBuilder.create()
.add(new RequestAS2(as2Version, clientFqdn))
.add(new RequestMDN())
.add(new RequestTargetHost())
.add(new RequestUserAgent(this.userAgent))
.add(new RequestDate())
.add(new RequestContent(true))
- .add(new RequestConnControl()).build();
+ .add(new RequestConnControl());
+ if (expectContinue) {
+ processorBuilder.add(new RequestExpectContinue());
+ }
+ httpProcessor = processorBuilder.build();
final Http1Config h1Config = Http1Config.custom().setBufferSize(8 *
1024).build();
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 baf8178ba81a..7a700e01121a 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
@@ -53,6 +53,7 @@ import org.apache.hc.core5.http.impl.routing.RequestRouter;
import org.apache.hc.core5.http.io.HttpRequestHandler;
import org.apache.hc.core5.http.io.HttpServerConnection;
import org.apache.hc.core5.http.io.HttpServerRequestHandler;
+import org.apache.hc.core5.http.io.support.BasicHttpServerExpectationDecorator;
import org.apache.hc.core5.http.io.support.BasicHttpServerRequestHandler;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.protocol.HttpCoreContext;
@@ -401,8 +402,10 @@ public class AS2ServerConnection {
// Create initial empty router
currentHandler = createHandler();
- // Set up the HTTP service with delegating handler
- httpService = new HttpService(inhttpproc, new
DelegatingRequestHandler());
+ // Set up the HTTP service with delegating handler, wrapped to
support Expect: 100-continue
+ httpService = new HttpService(
+ inhttpproc,
+ new BasicHttpServerExpectationDecorator(new
DelegatingRequestHandler()));
}
private HttpServerRequestHandler createHandler() {
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
index d6b4f84efeaa..7d2b25b6de84 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/EntityParser.java
@@ -523,6 +523,9 @@ public final class EntityParser {
contentTransferEncoding);
break;
default:
+ // Accept non-standard content types (e.g., text/plain,
application/octet-stream)
+ // that real-world AS2 partners may use to wrap EDI payloads
+ parseApplicationEDIEntity(message, entity.getContent(),
inBuffer, contentType, contentTransferEncoding);
break;
}
}
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/GenericApplicationEntity.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/GenericApplicationEntity.java
new file mode 100644
index 000000000000..6bc3d2e7a49f
--- /dev/null
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/GenericApplicationEntity.java
@@ -0,0 +1,39 @@
+/*
+ * 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.entity;
+
+import java.io.IOException;
+
+import org.apache.hc.core5.http.ContentType;
+
+/**
+ * A generic application entity that wraps EDI payloads with non-standard
content types (e.g., text/plain,
+ * application/octet-stream). Real-world AS2 partners frequently send EDI
payloads wrapped in content types other than
+ * the standard application/edifact, application/edi-x12, or
application/edi-consent types.
+ */
+public class GenericApplicationEntity extends ApplicationEntity {
+
+ public GenericApplicationEntity(byte[] content, ContentType contentType,
String contentTransferEncoding,
+ boolean isMainBody, String filename) {
+ super(content, contentType, contentTransferEncoding, isMainBody,
filename);
+ }
+
+ @Override
+ public void close() throws IOException {
+ // do nothing
+ }
+}
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/io/AS2BHttpServerConnection.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/io/AS2BHttpServerConnection.java
index 8da0903c6979..ddd61ef68cb5 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/io/AS2BHttpServerConnection.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/io/AS2BHttpServerConnection.java
@@ -16,22 +16,37 @@
*/
package org.apache.camel.component.as2.api.io;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import org.apache.camel.component.as2.api.entity.EntityParser;
+import org.apache.camel.component.as2.api.util.EntityUtils;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.ContentLengthStrategy;
+import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.config.Http1Config;
import org.apache.hc.core5.http.impl.io.DefaultBHttpServerConnection;
import org.apache.hc.core5.http.io.HttpMessageParserFactory;
import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
+import org.apache.hc.core5.http.io.entity.BasicHttpEntity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class AS2BHttpServerConnection extends DefaultBHttpServerConnection {
+ private static final Logger LOG =
LoggerFactory.getLogger(AS2BHttpServerConnection.class);
+
+ /**
+ * The raw (unparsed) request body bytes captured before MIME parsing.
This allows downstream handlers to perform
+ * signature verification against the original bytes, which may differ
from the re-serialized parsed entity due to
+ * MIME header folding, whitespace normalization, and line ending changes.
+ */
+ private byte[] rawRequestBody;
+
public AS2BHttpServerConnection(Http1Config http1Config) {
this(http1Config, null, null);
}
@@ -53,9 +68,32 @@ public class AS2BHttpServerConnection extends
DefaultBHttpServerConnection {
outgoingContentStrategy, requestParserFactory,
responseWriterFactory);
}
+ /**
+ * Returns the raw (unparsed) request body bytes captured before MIME
parsing.
+ *
+ * @return the raw body bytes, or null if no entity was received
+ */
+ public byte[] getRawRequestBody() {
+ return rawRequestBody;
+ }
+
@Override
public void receiveRequestEntity(ClassicHttpRequest request) throws
HttpException, IOException {
super.receiveRequestEntity(request);
+ // Capture raw body bytes before parsing modifies them.
+ // This is essential for signature verification of async MDNs, where
the parsed
+ // MIME entity may have different bytes due to header folding and
whitespace normalization.
+ if (request.getEntity() != null) {
+ try {
+ rawRequestBody = EntityUtils.getContent(request.getEntity());
+ // Reset the entity with the captured bytes so it can be parsed
+ ContentType contentType =
ContentType.parse(request.getEntity().getContentType());
+ request.setEntity(
+ new BasicHttpEntity(new
ByteArrayInputStream(rawRequestBody), rawRequestBody.length, contentType));
+ } catch (Exception e) {
+ LOG.debug("Failed to capture raw request body bytes", e);
+ }
+ }
EntityParser.parseAS2MessageEntity(request);
}
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
index 852ff8e3c0d9..59ad21bf618e 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/protocol/ResponseMDN.java
@@ -73,16 +73,18 @@ public class ResponseMDN implements HttpResponseInterceptor
{
public static final String DISPOSITION_MODIFIER = "Disposition-Modifier";
- private static final String DEFAULT_MDN_MESSAGE_TEMPLATE = """
- MDN for -
- Message ID: $requestHeaders["Message-Id"]
- Subject: $requestHeaders["Subject"]
- Date: $requestHeaders["Date"]
- From: $requestHeaders["AS2-From"]
- To: $requestHeaders["AS2-To"]
- Received on: $responseHeaders["Date"]
- Status: $dispositionType
- """;
+ // Use explicit CRLF line endings to ensure consistent digest computation
for signed MDNs.
+ // Java text blocks use LF, which causes CRLF/LF mismatch when headers are
written through
+ // CanonicalOutputStream (CRLF) but body content is written directly (LF).
+ private static final String DEFAULT_MDN_MESSAGE_TEMPLATE
+ = "MDN for -\r\n"
+ + " Message ID: $requestHeaders[\"Message-Id\"]\r\n"
+ + " Subject: $requestHeaders[\"Subject\"]\r\n"
+ + " Date: $requestHeaders[\"Date\"]\r\n"
+ + " From: $requestHeaders[\"AS2-From\"]\r\n"
+ + " To: $requestHeaders[\"AS2-To\"]\r\n"
+ + " Received on: $responseHeaders[\"Date\"]\r\n"
+ + " Status: $dispositionType\r\n";
private static final Logger LOG =
LoggerFactory.getLogger(ResponseMDN.class);
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/AS2Utils.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/AS2Utils.java
index a4fb208dc73c..7f3c18c98a87 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/AS2Utils.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/AS2Utils.java
@@ -21,8 +21,8 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
-import java.security.SecureRandom;
import java.util.Iterator;
+import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -55,8 +55,6 @@ public final class AS2Utils {
public static final Pattern AS_NAME_PATTERN = Pattern.compile(AS2_NAME);
- private static SecureRandom generator = new SecureRandom();
-
private AS2Utils() {
}
@@ -88,8 +86,7 @@ public final class AS2Utils {
* @return The generated message id.
*/
public static String createMessageId(String fqdn) {
- /* Wall Clock Time in Nanoseconds */ /* 64 Bit Random Number */ /*
Fully Qualified Domain Name */
- return "<" + Long.toString(System.nanoTime(), 36) + "." +
Long.toString(generator.nextLong(), 36) + "@" + fqdn + ">";
+ return "<" + UUID.randomUUID() + "@" + fqdn + ">";
}
/**
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EntityUtils.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EntityUtils.java
index 3de97bda41dc..3bd4404ff917 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EntityUtils.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/EntityUtils.java
@@ -33,6 +33,7 @@ import
org.apache.camel.component.as2.api.entity.ApplicationEDIFACTEntity;
import org.apache.camel.component.as2.api.entity.ApplicationEDIX12Entity;
import org.apache.camel.component.as2.api.entity.ApplicationEntity;
import org.apache.camel.component.as2.api.entity.ApplicationXMLEntity;
+import org.apache.camel.component.as2.api.entity.GenericApplicationEntity;
import org.apache.camel.component.as2.api.entity.MimeEntity;
import org.apache.camel.util.ObjectHelper;
import org.apache.commons.codec.DecoderException;
@@ -203,7 +204,9 @@ public final class EntityUtils {
case AS2MediaType.APPLICATION_XML:
return new ApplicationXMLEntity(ediMessage, charset,
contentTransferEncoding, isMainBody, filename);
default:
- throw new CamelException("Invalid EDI entity mime type: " +
ediMessageContentType.getMimeType());
+ return new GenericApplicationEntity(
+ ediMessage, ediMessageContentType,
contentTransferEncoding,
+ isMainBody, filename);
}
}
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/HttpMessageUtils.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/HttpMessageUtils.java
index d6a03c17dec9..7acc58adee41 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/HttpMessageUtils.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/HttpMessageUtils.java
@@ -75,7 +75,7 @@ public final class HttpMessageUtils {
} else if (message instanceof BasicClassicHttpResponse httpResponse) {
HttpEntity entity = httpResponse.getEntity();
if (entity != null && type.isInstance(entity)) {
- type.cast(entity);
+ return type.cast(entity);
}
}
return null;
@@ -152,10 +152,23 @@ public final class HttpMessageUtils {
}
break;
}
- default:
- throw new HttpException(
- "Failed to extract EDI message: invalid content type
'" + contentType.getMimeType()
- + "' for AS2 request message");
+ default: {
+ // Accept non-standard content types (e.g., text/plain,
application/octet-stream)
+ // that real-world AS2 partners may use to wrap EDI payloads
+ if
(decrpytingAndSigningInfo.getValidateSigningCertificateChain() != null) {
+ throw new AS2InsufficientSecurityException("Failed to
validate the signature");
+ }
+ if (decrpytingAndSigningInfo.getDecryptingPrivateKey() !=
null) {
+ throw new AS2InsufficientSecurityException("Expected to be
encrypted");
+ }
+ ediEntity = getEntity(message, ApplicationEntity.class);
+ if (ediEntity == null) {
+ throw new HttpException(
+ "Failed to extract EDI message: could not parse
entity with content type '"
+ + contentType.getMimeType() + "'");
+ }
+ break;
+ }
}
return ediEntity;
@@ -274,10 +287,20 @@ public final class HttpMessageUtils {
ediEntity =
extractEdiPayloadFromCompressedEntity(compressedDataEntity,
decrpytingAndSigningInfo, false);
break;
}
- default:
- throw new HttpException(
- "Failed to extract EDI payload: invalid content type
'" + contentType.getMimeType()
- + "' for AS2 enveloped entity");
+ default: {
+ // Accept non-standard content types within enveloped entities
+ if
(decrpytingAndSigningInfo.getValidateSigningCertificateChain() != null) {
+ throw new AS2InsufficientSecurityException("Failed to
validate the signature");
+ }
+ if (entity instanceof ApplicationEntity) {
+ ediEntity = (ApplicationEntity) entity;
+ } else {
+ throw new HttpException(
+ "Failed to extract EDI payload: invalid content
type '" + contentType.getMimeType()
+ + "' for AS2 enveloped entity");
+ }
+ break;
+ }
}
return ediEntity;
@@ -325,10 +348,20 @@ public final class HttpMessageUtils {
}
break;
}
- default:
- throw new HttpException(
- "Failed to extract EDI payload: invalid content type
'" + contentType.getMimeType()
- + "' for AS2 compressed entity");
+ default: {
+ // Accept non-standard content types within compressed entities
+ if (!hasValidSignature &&
decrpytingAndSigningInfo.getValidateSigningCertificateChain() != null) {
+ throw new AS2InsufficientSecurityException("Failed to
validate the signature");
+ }
+ if (entity instanceof ApplicationEntity) {
+ ediEntity = (ApplicationEntity) entity;
+ } else {
+ throw new HttpException(
+ "Failed to extract EDI payload: invalid content
type '" + contentType.getMimeType()
+ + "' for AS2 compressed entity");
+ }
+ break;
+ }
}
return ediEntity;
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/MicUtils.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/MicUtils.java
index b1699058d8a9..1852f5d530de 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/MicUtils.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/MicUtils.java
@@ -25,9 +25,16 @@ import java.security.cert.Certificate;
import org.apache.camel.component.as2.api.AS2Header;
import org.apache.camel.component.as2.api.AS2MicAlgorithm;
+import org.apache.camel.component.as2.api.AS2MimeType;
+import
org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeCompressedDataEntity;
+import
org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeEnvelopedDataEntity;
import
org.apache.camel.component.as2.api.entity.DispositionNotificationOptions;
import
org.apache.camel.component.as2.api.entity.DispositionNotificationOptionsParser;
+import org.apache.camel.component.as2.api.entity.EntityParser;
+import org.apache.camel.component.as2.api.entity.MimeEntity;
+import org.apache.camel.component.as2.api.entity.MultipartSignedEntity;
import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.HttpException;
import org.slf4j.Logger;
@@ -98,10 +105,12 @@ public final class MicUtils {
return null;
}
- HttpEntity entity = HttpMessageUtils.extractEdiPayload(request,
- new
HttpMessageUtils.DecrpytingAndSigningInfo(validateSigningCertificateChain,
decryptingPrivateKey));
+ // Compute MIC over the correct content per RFC 5402:
+ // - For compress-before-sign: MIC covers the compressed entity (what
was signed)
+ // - For sign-before-compress or no compression: MIC covers the EDI
payload
+ HttpEntity micEntity = findMicEntity(request,
validateSigningCertificateChain, decryptingPrivateKey);
- byte[] content = EntityUtils.getContent(entity);
+ byte[] content = EntityUtils.getContent(micEntity);
String micAS2AlgorithmName =
AS2MicAlgorithm.getAS2AlgorithmName(micJdkAlgorithmName);
byte[] mic = createMic(content, micJdkAlgorithmName);
@@ -112,6 +121,87 @@ public final class MicUtils {
}
}
+ /**
+ * Finds the correct entity to compute the MIC over, per RFC 5402.
+ * <p>
+ * For compress-before-sign, the MIC must cover the compressed entity
(what was signed). For sign-before-compress or
+ * no compression, the MIC covers the EDI payload.
+ */
+ private static HttpEntity findMicEntity(
+ ClassicHttpRequest request, Certificate[]
validateSigningCertificateChain, PrivateKey decryptingPrivateKey)
+ throws HttpException {
+
+ EntityParser.parseAS2MessageEntity(request);
+
+ String contentTypeString = HttpMessageUtils.getHeaderValue(request,
AS2Header.CONTENT_TYPE);
+ if (contentTypeString == null) {
+ throw new HttpException("Failed to create MIC: content type
missing from request");
+ }
+ ContentType contentType = ContentType.parse(contentTypeString);
+
+ // Navigate the message structure to find the signed data entity
+ HttpEntity entity = findSignedDataEntity(request, contentType,
decryptingPrivateKey);
+ if (entity != null) {
+ return entity;
+ }
+
+ // No multipart/signed found, fall back to extracting the EDI payload
+ return HttpMessageUtils.extractEdiPayload(request,
+ new
HttpMessageUtils.DecrpytingAndSigningInfo(validateSigningCertificateChain,
decryptingPrivateKey));
+ }
+
+ /**
+ * Navigate the entity hierarchy to find the signed data entity (part 0 of
multipart/signed). Returns the signed
+ * data entity which is what the MIC should be computed over, or null if
no multipart/signed is found.
+ */
+ private static HttpEntity findSignedDataEntity(
+ ClassicHttpRequest request, ContentType contentType, PrivateKey
decryptingPrivateKey)
+ throws HttpException {
+
+ String mimeType = contentType.getMimeType().toLowerCase();
+
+ if (AS2MimeType.MULTIPART_SIGNED.equals(mimeType)) {
+ // Top-level signed: MIC is over the signed data entity (part 0)
+ MultipartSignedEntity multipartSignedEntity
+ = HttpMessageUtils.getEntity(request,
MultipartSignedEntity.class);
+ if (multipartSignedEntity != null) {
+ return multipartSignedEntity.getSignedDataEntity();
+ }
+ } else if (AS2MimeType.APPLICATION_PKCS7_MIME.equals(mimeType)) {
+ String smimeType = contentType.getParameter("smime-type");
+ if ("compressed-data".equals(smimeType)) {
+ // Sign-before-compress: decompress first, then find the
signed entity inside
+ ApplicationPkcs7MimeCompressedDataEntity compressedEntity
+ = HttpMessageUtils.getEntity(request,
ApplicationPkcs7MimeCompressedDataEntity.class);
+ if (compressedEntity != null) {
+ MimeEntity inner = compressedEntity
+ .getCompressedEntity(new
org.bouncycastle.cms.jcajce.ZlibExpanderProvider());
+ if (inner instanceof MultipartSignedEntity signedEntity) {
+ return signedEntity.getSignedDataEntity();
+ }
+ }
+ } else if ("enveloped-data".equals(smimeType) &&
decryptingPrivateKey != null) {
+ // Encrypted message: decrypt first, then look for signed
entity
+ ApplicationPkcs7MimeEnvelopedDataEntity envelopedEntity
+ = HttpMessageUtils.getEntity(request,
ApplicationPkcs7MimeEnvelopedDataEntity.class);
+ if (envelopedEntity != null) {
+ MimeEntity decryptedEntity =
envelopedEntity.getEncryptedEntity(decryptingPrivateKey);
+ String decryptedContentType =
decryptedEntity.getContentType();
+ if (decryptedContentType != null) {
+ ContentType decryptedCt =
ContentType.parse(decryptedContentType);
+ String decryptedMime =
decryptedCt.getMimeType().toLowerCase();
+ if (AS2MimeType.MULTIPART_SIGNED.equals(decryptedMime)
+ && decryptedEntity instanceof
MultipartSignedEntity signedEntity) {
+ return signedEntity.getSignedDataEntity();
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
public static String getMicJdkAlgorithmName(String[] micAs2AlgorithmNames)
{
if (micAs2AlgorithmNames == null) {
return AS2MicAlgorithm.SHA_1.getJdkAlgorithmName();
diff --git
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2AsyncMDNServerConnectionTest.java
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2AsyncMDNServerConnectionTest.java
new file mode 100644
index 000000000000..1314f648f3d6
--- /dev/null
+++
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2AsyncMDNServerConnectionTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 java.net.HttpURLConnection;
+import java.net.URL;
+
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.hc.core5.http.ClassicHttpRequest;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpException;
+import org.apache.hc.core5.http.io.HttpRequestHandler;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class AS2AsyncMDNServerConnectionTest {
+
+ private int port;
+ private AS2AsyncMDNServerConnection connection;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ port = AvailablePortFinder.getNextAvailable();
+ connection = new AS2AsyncMDNServerConnection(port, null);
+ }
+
+ @AfterEach
+ void tearDown() {
+ if (connection != null) {
+ connection.close();
+ }
+ }
+
+ @Test
+ void asyncMdnServerAcceptsRequestWithAnyHostHeader() throws Exception {
+ final boolean[] handled = { false };
+
+ connection.receive("/test-mdn", new HttpRequestHandler() {
+ @Override
+ public void handle(ClassicHttpRequest request, ClassicHttpResponse
response, HttpContext context)
+ throws HttpException {
+ handled[0] = true;
+ response.setCode(200);
+ }
+ });
+
+ // Wait for server to be ready
+ Thread.sleep(200);
+
+ // Send a request with a Host header that doesn't match the server's
hostname
+ // This previously caused HTTP 421 due to RequestValidateHost
+ HttpURLConnection conn = (HttpURLConnection) new
URL("http://localhost:" + port + "/test-mdn").openConnection();
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Host", "different-host.example.com");
+ conn.setDoOutput(true);
+ conn.getOutputStream().write("test".getBytes());
+ conn.getOutputStream().flush();
+
+ int responseCode = conn.getResponseCode();
+ conn.disconnect();
+
+ // Should NOT get 421 (Misdirected Request) anymore
+ assertNotEquals(421, responseCode, "Should not reject requests with
non-matching Host header");
+ }
+}
diff --git
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/GenericApplicationEntityTest.java
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/GenericApplicationEntityTest.java
new file mode 100644
index 000000000000..ab00bfbe705b
--- /dev/null
+++
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/GenericApplicationEntityTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.entity;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.Security;
+
+import org.apache.camel.component.as2.api.AS2Header;
+import org.apache.camel.component.as2.api.AS2TransferEncoding;
+import org.apache.camel.component.as2.api.util.EntityUtils;
+import org.apache.camel.component.as2.api.util.HttpMessageUtils;
+import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.io.entity.BasicHttpEntity;
+import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class GenericApplicationEntityTest {
+
+ private static final String EDI_MESSAGE =
"UNB+UNOA:1+005435656:1+006415160:1+060515:1434+00000000000778'";
+
+ @BeforeAll
+ static void setUp() {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ @Test
+ void genericApplicationEntityPreservesContent() throws Exception {
+ byte[] content = EDI_MESSAGE.getBytes(StandardCharsets.US_ASCII);
+ ContentType contentType = ContentType.create("text/plain",
StandardCharsets.US_ASCII);
+ GenericApplicationEntity entity = new
GenericApplicationEntity(content, contentType, null, true, null);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ entity.writeTo(out);
+ assertArrayEquals(content, out.toByteArray());
+ }
+
+ @Test
+ void genericApplicationEntityGetEdiMessage() {
+ byte[] content = EDI_MESSAGE.getBytes(StandardCharsets.US_ASCII);
+ ContentType contentType = ContentType.create("text/plain",
StandardCharsets.US_ASCII);
+ GenericApplicationEntity entity = new
GenericApplicationEntity(content, contentType, null, true, null);
+
+ Object ediMessage = entity.getEdiMessage();
+ assertInstanceOf(String.class, ediMessage);
+ assertEquals(EDI_MESSAGE, ediMessage);
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = { "text/plain", "application/octet-stream" })
+ void extractEdiPayloadAcceptsNonStandardContentTypes(String mimeType)
throws Exception {
+ byte[] content = EDI_MESSAGE.getBytes(StandardCharsets.US_ASCII);
+ ContentType contentType = ContentType.create(mimeType,
StandardCharsets.US_ASCII);
+
+ BasicClassicHttpRequest request = new BasicClassicHttpRequest("POST",
"/");
+ request.addHeader(AS2Header.CONTENT_TYPE, contentType.toString());
+ InputStream is = new ByteArrayInputStream(content);
+ request.setEntity(new BasicHttpEntity(is, content.length,
contentType));
+
+ ApplicationEntity ediEntity =
HttpMessageUtils.extractEdiPayload(request,
+ new HttpMessageUtils.DecrpytingAndSigningInfo(null, null));
+
+ assertNotNull(ediEntity, "EDI entity should not be null for content
type: " + mimeType);
+ assertInstanceOf(GenericApplicationEntity.class, ediEntity);
+ assertEquals(EDI_MESSAGE, ediEntity.getEdiMessage().toString());
+ }
+
+ @Test
+ void createEDIEntityReturnsGenericForUnknownType() throws Exception {
+ byte[] content = EDI_MESSAGE.getBytes(StandardCharsets.US_ASCII);
+ ContentType contentType = ContentType.create("text/plain",
StandardCharsets.US_ASCII);
+
+ ApplicationEntity entity = EntityUtils.createEDIEntity(content,
contentType,
+ AS2TransferEncoding.NONE, false, "test.txt");
+
+ assertInstanceOf(GenericApplicationEntity.class, entity);
+ }
+}
diff --git
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/protocol/ResponseMDNTest.java
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/protocol/ResponseMDNTest.java
new file mode 100644
index 000000000000..2267ab687dd7
--- /dev/null
+++
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/protocol/ResponseMDNTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.protocol;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.component.as2.api.entity.TextPlainEntity;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class ResponseMDNTest {
+
+ @Test
+ void mdnTextPlainEntityWithCrlfProducesConsistentDigest() throws
IOException {
+ // Simulate MDN text with explicit CRLF (as in the fixed
DEFAULT_MDN_MESSAGE_TEMPLATE)
+ String mdnText = "MDN for -\r\n"
+ + " Message ID: test-id\r\n"
+ + " Status: processed\r\n";
+
+ TextPlainEntity entity = new TextPlainEntity(mdnText,
StandardCharsets.US_ASCII.name(), "7bit", false);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ entity.writeTo(out);
+ byte[] output = out.toByteArray();
+
+ // Verify that the body content preserves CRLF
+ String outputStr = new String(output, StandardCharsets.US_ASCII);
+ // The body part (after headers + blank line) should contain CRLF
+ String body = outputStr.substring(outputStr.indexOf("\r\n\r\n") + 4);
+ assertTrue(body.contains("\r\n"), "MDN body should contain CRLF line
endings");
+ assertFalse(body.contains("\n") && !body.contains("\r\n"),
+ "MDN body should not contain bare LF (without CR)");
+ }
+
+ @Test
+ void mdnTextPlainEntityWithLfProducesMismatch() throws IOException {
+ // Simulate MDN text with LF only (the old broken
DEFAULT_MDN_MESSAGE_TEMPLATE behavior)
+ String mdnText = "MDN for -\n"
+ + " Message ID: test-id\n"
+ + " Status: processed\n";
+
+ TextPlainEntity entity = new TextPlainEntity(mdnText,
StandardCharsets.US_ASCII.name(), "7bit", false);
+
+ ByteArrayOutputStream out1 = new ByteArrayOutputStream();
+ entity.writeTo(out1);
+
+ // Now create with CRLF
+ String mdnTextCrlf = "MDN for -\r\n"
+ + " Message ID: test-id\r\n"
+ + " Status: processed\r\n";
+
+ TextPlainEntity entityCrlf = new TextPlainEntity(mdnTextCrlf,
StandardCharsets.US_ASCII.name(), "7bit", false);
+
+ ByteArrayOutputStream out2 = new ByteArrayOutputStream();
+ entityCrlf.writeTo(out2);
+
+ // Headers should be identical (both go through CanonicalOutputStream)
+ // but body content will differ in line endings
+ assertNotEquals(out1.size(), out2.size(),
+ "LF and CRLF bodies should produce different byte lengths");
+ }
+}
diff --git
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/AS2UtilsTest.java
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/AS2UtilsTest.java
new file mode 100644
index 000000000000..9e4970e362b1
--- /dev/null
+++
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/util/AS2UtilsTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.util;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class AS2UtilsTest {
+
+ @Test
+ void createMessageIdShouldBeUnique() {
+ Set<String> ids = new HashSet<>();
+ for (int i = 0; i < 1000; i++) {
+ String id = AS2Utils.createMessageId("example.com");
+ assertTrue(ids.add(id), "Duplicate message ID: " + id);
+ }
+ }
+
+ @Test
+ void createMessageIdShouldContainFqdn() {
+ String id = AS2Utils.createMessageId("test.example.org");
+ assertTrue(id.contains("@test.example.org>"), "Message ID should
contain FQDN");
+ assertTrue(id.startsWith("<"), "Message ID should start with <");
+ assertTrue(id.endsWith(">"), "Message ID should end with >");
+ }
+
+ @Test
+ void createMessageIdShouldBeRfc2822Format() {
+ String id = AS2Utils.createMessageId("server.example.com");
+ // RFC 2822 Message-ID format: <unique-part@fqdn>
+ assertTrue(id.matches("<[^@]+@server\\.example\\.com>"), "Message ID
should match RFC 2822 format: " + id);
+ }
+}
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..9db61f44f424 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
@@ -39,6 +39,7 @@ public class
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
map.put("EdiMessageType", java.lang.String.class);
map.put("EncryptingAlgorithm",
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class);
map.put("EncryptingCertificateChain",
java.security.cert.Certificate[].class);
+ map.put("ExpectContinue", boolean.class);
map.put("From", java.lang.String.class);
map.put("HostnameVerifier", javax.net.ssl.HostnameVerifier.class);
map.put("HttpConnectionPoolSize", java.lang.Integer.class);
@@ -109,6 +110,8 @@ public class
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
case "encryptingAlgorithm":
target.setEncryptingAlgorithm(property(camelContext,
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class, value));
return true;
case "encryptingcertificatechain":
case "encryptingCertificateChain":
target.setEncryptingCertificateChain(property(camelContext,
java.security.cert.Certificate[].class, value)); return true;
+ case "expectcontinue":
+ case "expectContinue": target.setExpectContinue(property(camelContext,
boolean.class, value)); return true;
case "from": target.setFrom(property(camelContext,
java.lang.String.class, value)); return true;
case "hostnameverifier":
case "hostnameVerifier":
target.setHostnameVerifier(property(camelContext,
javax.net.ssl.HostnameVerifier.class, value)); return true;
@@ -209,6 +212,8 @@ public class
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
case "encryptingAlgorithm": return
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class;
case "encryptingcertificatechain":
case "encryptingCertificateChain": return
java.security.cert.Certificate[].class;
+ case "expectcontinue":
+ case "expectContinue": return boolean.class;
case "from": return java.lang.String.class;
case "hostnameverifier":
case "hostnameVerifier": return javax.net.ssl.HostnameVerifier.class;
@@ -305,6 +310,8 @@ public class
AS2AsyncMDNServerManagerEndpointConfigurationConfigurer extends org
case "encryptingAlgorithm": return target.getEncryptingAlgorithm();
case "encryptingcertificatechain":
case "encryptingCertificateChain": return
target.getEncryptingCertificateChain();
+ case "expectcontinue":
+ case "expectContinue": return target.isExpectContinue();
case "from": return target.getFrom();
case "hostnameverifier":
case "hostnameVerifier": return target.getHostnameVerifier();
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..ac5f29f261fd 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
@@ -41,6 +41,7 @@ public class AS2ClientManagerEndpointConfigurationConfigurer
extends org.apache.
map.put("EdiMessageType", java.lang.String.class);
map.put("EncryptingAlgorithm",
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class);
map.put("EncryptingCertificateChain",
java.security.cert.Certificate[].class);
+ map.put("ExpectContinue", boolean.class);
map.put("From", java.lang.String.class);
map.put("HostnameVerifier", javax.net.ssl.HostnameVerifier.class);
map.put("HttpConnectionPoolSize", java.lang.Integer.class);
@@ -114,6 +115,8 @@ public class
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
case "encryptingAlgorithm":
target.setEncryptingAlgorithm(property(camelContext,
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class, value));
return true;
case "encryptingcertificatechain":
case "encryptingCertificateChain":
target.setEncryptingCertificateChain(property(camelContext,
java.security.cert.Certificate[].class, value)); return true;
+ case "expectcontinue":
+ case "expectContinue": target.setExpectContinue(property(camelContext,
boolean.class, value)); return true;
case "from": target.setFrom(property(camelContext,
java.lang.String.class, value)); return true;
case "hostnameverifier":
case "hostnameVerifier":
target.setHostnameVerifier(property(camelContext,
javax.net.ssl.HostnameVerifier.class, value)); return true;
@@ -216,6 +219,8 @@ public class
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
case "encryptingAlgorithm": return
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class;
case "encryptingcertificatechain":
case "encryptingCertificateChain": return
java.security.cert.Certificate[].class;
+ case "expectcontinue":
+ case "expectContinue": return boolean.class;
case "from": return java.lang.String.class;
case "hostnameverifier":
case "hostnameVerifier": return javax.net.ssl.HostnameVerifier.class;
@@ -314,6 +319,8 @@ public class
AS2ClientManagerEndpointConfigurationConfigurer extends org.apache.
case "encryptingAlgorithm": return target.getEncryptingAlgorithm();
case "encryptingcertificatechain":
case "encryptingCertificateChain": return
target.getEncryptingCertificateChain();
+ case "expectcontinue":
+ case "expectContinue": return target.isExpectContinue();
case "from": return target.getFrom();
case "hostnameverifier":
case "hostnameVerifier": return target.getHostnameVerifier();
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..8e4b26428c01 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
@@ -39,6 +39,7 @@ public class AS2ConfigurationConfigurer extends
org.apache.camel.support.compone
map.put("EdiMessageType", java.lang.String.class);
map.put("EncryptingAlgorithm",
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class);
map.put("EncryptingCertificateChain",
java.security.cert.Certificate[].class);
+ map.put("ExpectContinue", boolean.class);
map.put("From", java.lang.String.class);
map.put("HostnameVerifier", javax.net.ssl.HostnameVerifier.class);
map.put("HttpConnectionPoolSize", java.lang.Integer.class);
@@ -108,6 +109,8 @@ public class AS2ConfigurationConfigurer extends
org.apache.camel.support.compone
case "encryptingAlgorithm":
target.setEncryptingAlgorithm(property(camelContext,
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class, value));
return true;
case "encryptingcertificatechain":
case "encryptingCertificateChain":
target.setEncryptingCertificateChain(property(camelContext,
java.security.cert.Certificate[].class, value)); return true;
+ case "expectcontinue":
+ case "expectContinue": target.setExpectContinue(property(camelContext,
boolean.class, value)); return true;
case "from": target.setFrom(property(camelContext,
java.lang.String.class, value)); return true;
case "hostnameverifier":
case "hostnameVerifier":
target.setHostnameVerifier(property(camelContext,
javax.net.ssl.HostnameVerifier.class, value)); return true;
@@ -206,6 +209,8 @@ public class AS2ConfigurationConfigurer extends
org.apache.camel.support.compone
case "encryptingAlgorithm": return
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class;
case "encryptingcertificatechain":
case "encryptingCertificateChain": return
java.security.cert.Certificate[].class;
+ case "expectcontinue":
+ case "expectContinue": return boolean.class;
case "from": return java.lang.String.class;
case "hostnameverifier":
case "hostnameVerifier": return javax.net.ssl.HostnameVerifier.class;
@@ -300,6 +305,8 @@ public class AS2ConfigurationConfigurer extends
org.apache.camel.support.compone
case "encryptingAlgorithm": return target.getEncryptingAlgorithm();
case "encryptingcertificatechain":
case "encryptingCertificateChain": return
target.getEncryptingCertificateChain();
+ case "expectcontinue":
+ case "expectContinue": return target.isExpectContinue();
case "from": return target.getFrom();
case "hostnameverifier":
case "hostnameVerifier": return target.getHostnameVerifier();
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..78c34d6a74fa 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
@@ -54,6 +54,7 @@ public class AS2EndpointConfigurer extends
PropertyConfigurerSupport implements
map.put("UserAgent", java.lang.String.class);
map.put("ExceptionHandler",
org.apache.camel.spi.ExceptionHandler.class);
map.put("ExchangePattern", org.apache.camel.ExchangePattern.class);
+ map.put("ExpectContinue", boolean.class);
map.put("LazyStartProducer", boolean.class);
map.put("AccessToken", java.lang.String.class);
map.put("DecryptingPrivateKey", java.security.PrivateKey.class);
@@ -114,6 +115,8 @@ public class AS2EndpointConfigurer extends
PropertyConfigurerSupport implements
case "exceptionHandler":
target.setExceptionHandler(property(camelContext,
org.apache.camel.spi.ExceptionHandler.class, value)); return true;
case "exchangepattern":
case "exchangePattern":
target.setExchangePattern(property(camelContext,
org.apache.camel.ExchangePattern.class, value)); return true;
+ case "expectcontinue":
+ case "expectContinue":
target.getConfiguration().setExpectContinue(property(camelContext,
boolean.class, value)); return true;
case "from": target.getConfiguration().setFrom(property(camelContext,
java.lang.String.class, value)); return true;
case "hostnameverifier":
case "hostnameVerifier":
target.getConfiguration().setHostnameVerifier(property(camelContext,
javax.net.ssl.HostnameVerifier.class, value)); return true;
@@ -216,6 +219,8 @@ public class AS2EndpointConfigurer extends
PropertyConfigurerSupport implements
case "exceptionHandler": return
org.apache.camel.spi.ExceptionHandler.class;
case "exchangepattern":
case "exchangePattern": return org.apache.camel.ExchangePattern.class;
+ case "expectcontinue":
+ case "expectContinue": return boolean.class;
case "from": return java.lang.String.class;
case "hostnameverifier":
case "hostnameVerifier": return javax.net.ssl.HostnameVerifier.class;
@@ -314,6 +319,8 @@ public class AS2EndpointConfigurer extends
PropertyConfigurerSupport implements
case "exceptionHandler": return target.getExceptionHandler();
case "exchangepattern":
case "exchangePattern": return target.getExchangePattern();
+ case "expectcontinue":
+ case "expectContinue": return
target.getConfiguration().isExpectContinue();
case "from": return target.getConfiguration().getFrom();
case "hostnameverifier":
case "hostnameVerifier": return
target.getConfiguration().getHostnameVerifier();
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..8eb6d43376c4 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,7 +23,7 @@ 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");
@@ -45,6 +45,7 @@ public class AS2EndpointUriFactory extends
org.apache.camel.support.component.En
props.add("encryptingCertificateChain");
props.add("exceptionHandler");
props.add("exchangePattern");
+ props.add("expectContinue");
props.add("from");
props.add("hostnameVerifier");
props.add("httpConnectionPoolSize");
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..dc5f7682a064 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
@@ -39,6 +39,7 @@ public class AS2ServerManagerEndpointConfigurationConfigurer
extends org.apache.
map.put("EdiMessageType", java.lang.String.class);
map.put("EncryptingAlgorithm",
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class);
map.put("EncryptingCertificateChain",
java.security.cert.Certificate[].class);
+ map.put("ExpectContinue", boolean.class);
map.put("From", java.lang.String.class);
map.put("HostnameVerifier", javax.net.ssl.HostnameVerifier.class);
map.put("HttpConnectionPoolSize", java.lang.Integer.class);
@@ -109,6 +110,8 @@ public class
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
case "encryptingAlgorithm":
target.setEncryptingAlgorithm(property(camelContext,
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class, value));
return true;
case "encryptingcertificatechain":
case "encryptingCertificateChain":
target.setEncryptingCertificateChain(property(camelContext,
java.security.cert.Certificate[].class, value)); return true;
+ case "expectcontinue":
+ case "expectContinue": target.setExpectContinue(property(camelContext,
boolean.class, value)); return true;
case "from": target.setFrom(property(camelContext,
java.lang.String.class, value)); return true;
case "hostnameverifier":
case "hostnameVerifier":
target.setHostnameVerifier(property(camelContext,
javax.net.ssl.HostnameVerifier.class, value)); return true;
@@ -209,6 +212,8 @@ public class
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
case "encryptingAlgorithm": return
org.apache.camel.component.as2.api.AS2EncryptionAlgorithm.class;
case "encryptingcertificatechain":
case "encryptingCertificateChain": return
java.security.cert.Certificate[].class;
+ case "expectcontinue":
+ case "expectContinue": return boolean.class;
case "from": return java.lang.String.class;
case "hostnameverifier":
case "hostnameVerifier": return javax.net.ssl.HostnameVerifier.class;
@@ -305,6 +310,8 @@ public class
AS2ServerManagerEndpointConfigurationConfigurer extends org.apache.
case "encryptingAlgorithm": return target.getEncryptingAlgorithm();
case "encryptingcertificatechain":
case "encryptingCertificateChain": return
target.getEncryptingCertificateChain();
+ case "expectcontinue":
+ case "expectContinue": return target.isExpectContinue();
case "from": return target.getFrom();
case "hostnameverifier":
case "hostnameVerifier": return target.getHostnameVerifier();
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 7caadd208337..e101116dd91f 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
@@ -65,23 +65,24 @@
"userAgent": { "index": 29, "kind": "parameter", "displayName": "User
Agent", "group": "common", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "Camel AS2 Client Endpoint",
"configurationClass": "org.apache.camel.component.as2.AS2Configuration",
"configurationField": "configuration", "description": "The value included in
the User-Agent message header identifying the AS2 user a [...]
"exceptionHandler": { "index": 30, "kind": "parameter", "displayName":
"Exception Handler", "group": "consumer (advanced)", "label":
"consumer,advanced", "required": false, "type": "object", "javaType":
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.",
"deprecated": false, "autowired": false, "secret": false, "description": "To
let the consumer use a custom ExceptionHandler. Notice if the option
bridgeErrorHandler is enabled then this option is not in use. By de [...]
"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 [...]
+ "expectContinue": { "index": 32, "kind": "parameter", "displayName":
"Expect Continue", "group": "producer", "label": "producer", "required": false,
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": false, "configurationClass":
"org.apache.camel.component.as2.AS2Configuration", "configurationField":
"configuration", "description": "Controls whether the Expect: 100-Continue
header is included in outbound AS2 messages. W [...]
+ "lazyStartProducer": { "index": 33, "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": 34, "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": 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..4cb70860cca1 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
@@ -129,6 +129,8 @@ public class AS2Configuration {
private String password;
@UriParam(label = "security", secret = true)
private String accessToken;
+ @UriParam(defaultValue = "false", label = "producer")
+ private boolean expectContinue;
@UriParam(label = "security", secret = true)
private String mdnUserName;
@UriParam(label = "security", secret = true)
@@ -620,6 +622,20 @@ public class AS2Configuration {
this.accessToken = accessToken;
}
+ public boolean isExpectContinue() {
+ return expectContinue;
+ }
+
+ /**
+ * Controls whether the Expect: 100-Continue header is included in
outbound AS2 messages. When enabled, the client
+ * sends the headers first and waits for a 100 Continue response from the
server before sending the message body.
+ * This can improve efficiency with compatible partners but may cause
3-second delays with servers that don't
+ * support the protocol. Default is false for backward compatibility.
+ */
+ public void setExpectContinue(boolean expectContinue) {
+ this.expectContinue = expectContinue;
+ }
+
public String getMdnUserName() {
return mdnUserName;
}
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..e22a54588b78 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
@@ -58,7 +58,7 @@ public final class AS2ConnectionHelper {
configuration.getTargetHostname(),
configuration.getTargetPortNumber(), configuration.getHttpSocketTimeout(),
configuration.getHttpConnectionTimeout(),
configuration.getHttpConnectionPoolSize(),
configuration.getHttpConnectionPoolTtl(),
configuration.getSslContext(),
- configuration.getHostnameVerifier());
+ configuration.getHostnameVerifier(),
configuration.isExpectContinue());
}
/**
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..e9d04b7f1e7b 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
@@ -1638,6 +1638,46 @@ public interface AS2EndpointBuilderFactory {
doSetProperty("userAgent", userAgent);
return this;
}
+ /**
+ * Controls whether the Expect: 100-Continue header is included in
+ * outbound AS2 messages. When enabled, the client sends the headers
+ * first and waits for a 100 Continue response from the server before
+ * sending the message body. This can improve efficiency with
compatible
+ * partners but may cause 3-second delays with servers that don't
+ * support the protocol. Default is false for backward compatibility.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: producer
+ *
+ * @param expectContinue the value to set
+ * @return the dsl builder
+ */
+ default AS2EndpointProducerBuilder expectContinue(boolean
expectContinue) {
+ doSetProperty("expectContinue", expectContinue);
+ return this;
+ }
+ /**
+ * Controls whether the Expect: 100-Continue header is included in
+ * outbound AS2 messages. When enabled, the client sends the headers
+ * first and waits for a 100 Continue response from the server before
+ * sending the message body. This can improve efficiency with
compatible
+ * partners but may cause 3-second delays with servers that don't
+ * support the protocol. Default is false for backward compatibility.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: producer
+ *
+ * @param expectContinue the value to set
+ * @return the dsl builder
+ */
+ default AS2EndpointProducerBuilder expectContinue(String
expectContinue) {
+ doSetProperty("expectContinue", expectContinue);
+ return this;
+ }
/**
* The access token that is used by the client for bearer
* authentication.