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 71a21b78345 CAMEL-18017: return body part fields copied from parsed
MDN entity to avoid corruption (#13708)
71a21b78345 is described below
commit 71a21b7834571be1afde5cd5a32fcbf8ac59f250
Author: Jono Morris <[email protected]>
AuthorDate: Mon Apr 8 04:37:57 2024 +1200
CAMEL-18017: return body part fields copied from parsed MDN entity to avoid
corruption (#13708)
* CAMEL-18017: return copy of MDN body part fields
* CAMEL-18017 update comment text in test
---
.../AS2MessageDispositionNotificationEntity.java | 15 +++-
.../util/DispositionNotificationContentUtils.java | 10 ++-
.../component/as2/api/entity/EntityParserTest.java | 80 +++++++++++++++++++---
3 files changed, 94 insertions(+), 11 deletions(-)
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/AS2MessageDispositionNotificationEntity.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/AS2MessageDispositionNotificationEntity.java
index 4f2c6467919..ccf5c121f78 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/AS2MessageDispositionNotificationEntity.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/AS2MessageDispositionNotificationEntity.java
@@ -66,6 +66,7 @@ public class AS2MessageDispositionNotificationEntity extends
MimeEntity {
private String[] warningFields;
private Map<String, String> extensionFields = new HashMap<>();
private ReceivedContentMic receivedContentMic;
+ private String parsedBodyPartFields;
public AS2MessageDispositionNotificationEntity(ClassicHttpRequest request,
HttpResponse response,
@@ -119,7 +120,8 @@ public class AS2MessageDispositionNotificationEntity
extends MimeEntity {
String[] errorFields,
String[] warningFields,
Map<String, String>
extensionFields,
- ReceivedContentMic
receivedContentMic) {
+ ReceivedContentMic
receivedContentMic,
+ String
parsedBodyPartFields) {
super(ContentType.create(AS2MimeType.MESSAGE_DISPOSITION_NOTIFICATION), null);
this.reportingUA = reportingUA;
this.mtnName = mtnName;
@@ -133,6 +135,7 @@ public class AS2MessageDispositionNotificationEntity
extends MimeEntity {
this.warningFields = warningFields;
this.extensionFields = extensionFields;
this.receivedContentMic = receivedContentMic;
+ this.parsedBodyPartFields = parsedBodyPartFields;
}
public String getReportingUA() {
@@ -199,6 +202,16 @@ public class AS2MessageDispositionNotificationEntity
extends MimeEntity {
// 5.1.1
}
+ if (parsedBodyPartFields != null) {
+ // The 'writeTo' method is used when verifying the signature
of the received MDN, and any alteration
+ // to the body part fields would mean that the signature would
fail verification. Therefor return
+ // the fields parsed from the MDN entity if available so that
the specific field
+ // ordering/formatting is maintained otherwise fall back to
recreating each header, e.g. 'Reporting-UA',
+ // in the order prescribed in this method.
+ canonicalOutstream.writeln(parsedBodyPartFields);
+ return;
+ }
+
if (reportingUA != null) {
Header reportingUAField = new BasicHeader(REPORTING_UA,
reportingUA);
canonicalOutstream.writeln(reportingUAField.toString());
diff --git
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/DispositionNotificationContentUtils.java
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/DispositionNotificationContentUtils.java
index 36cddc5c437..75eeb253285 100644
---
a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/DispositionNotificationContentUtils.java
+++
b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/DispositionNotificationContentUtils.java
@@ -131,6 +131,7 @@ public final class DispositionNotificationContentUtils {
private static final char PARAM_DELIMITER = ',';
private static final char ELEM_DELIMITER = ';';
+ private static final int DEFAULT_BUFFER_SIZE = 8 * 1024;
private static final BitSet TOKEN_DELIMS =
TokenParser.INIT_BITSET(PARAM_DELIMITER, ELEM_DELIMITER);
@@ -152,9 +153,15 @@ public final class DispositionNotificationContentUtils {
List<String> warnings = new ArrayList<>();
Map<String, String> extensionFields = new HashMap<>();
ReceivedContentMic receivedContentMic = null;
+ CharArrayBuffer bodyPartFields = new
CharArrayBuffer(DEFAULT_BUFFER_SIZE);
for (int i = 0; i < dispositionNotificationFields.size(); i++) {
final CharArrayBuffer fieldLine =
dispositionNotificationFields.get(i);
+ bodyPartFields.append(fieldLine);
+ if (i < dispositionNotificationFields.size() - 1) {
+ bodyPartFields.append('\r');
+ bodyPartFields.append('\n');
+ }
final Field field = parseDispositionField(fieldLine);
switch (field.getName().toLowerCase()) {
case REPORTING_UA: {
@@ -250,7 +257,8 @@ public final class DispositionNotificationContentUtils {
errors.toArray(new String[0]),
warnings.toArray(new String[0]),
extensionFields,
- receivedContentMic);
+ receivedContentMic,
+ bodyPartFields.toString());
}
public static Field parseDispositionField(CharArrayBuffer fieldLine)
throws ParseException {
diff --git
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
index aa7997790dd..27f2fe44eb7 100644
---
a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
+++
b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/entity/EntityParserTest.java
@@ -17,6 +17,7 @@
package org.apache.camel.component.as2.api.entity;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
@@ -45,6 +46,7 @@ import
org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
import org.apache.hc.core5.http.impl.EnglishReasonPhraseCatalog;
import org.apache.hc.core5.http.io.entity.BasicHttpEntity;
import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
+import org.apache.hc.core5.http.message.BasicHeader;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.Extension;
@@ -109,6 +111,39 @@ public class EntityParserTest {
+
"\r\n"
+
"------=_Part_56_1672293592.1028122454656--\r\n";
+ // version of the MDN report without any folded body parts that would be
unfolded when the entity is parsed
+ // modifying the report
+ public static final String
DISPOSITION_NOTIFICATION_REPORT_CONTENT_UNFOLDED = "\r\n"
+
+ "------=_Part_56_1672293592.1028122454656\r\n"
+
+ "Content-Type: text/plain\r\n"
+
+ "Content-Transfer-Encoding: 7bit\r\n"
+
+ "\r\n"
+
+ "MDN for -\r\n"
+
+ " Message ID: <200207310834482A70BF63@\\\"~~foo~~\\\">\r\n"
+
+ " From: \"\\\" as2Name \\\"\"\r\n"
+
+ " To: \"0123456780000\""
+
+ " Received on: 2002-07-31 at 09:34:14 (EDT)\r\n"
+
+ " Status: processed\r\n"
+
+ " Comment: This is not a guarantee that the message has\r\n"
+
+ " been completely processed or &understood by the receiving\r\n"
+
+ " translator\r\n" + "\r\n"
+
+ "------=_Part_56_1672293592.1028122454656\r\n"
+
+ "Content-Type: message/disposition-notification\r\n"
+
+ "Content-Transfer-Encoding: 7bit\r\n"
+
+ "\r\n"
+
+ "Reporting-UA: AS2 Server\r\n"
+
+ "MDN-Gateway: dns; example.com\r\n"
+
+ "Original-Recipient: rfc822; 0123456780000\r\n"
+
+ "Final-Recipient: rfc822; 0123456780000\r\n"
+
+ "Original-Message-ID: <200207310834482A70BF63@\\\"~~foo~~\\\">\r\n"
+
+ "Disposition: automatic-action/MDN-sent-automatically; rocessed/warning:
you're awesome\r\n"
+
+ "Failure: oops-a-failure\r\n"
+
+ "Error: oops-an-error\r\n"
+
+ "Warning: oops-a-warning\r\n"
+
+ "Received-content-MIC: 7v7F++fQaNB1sVLFtMRp+dF+eG4=, sha1\r\n"
+
+ "\r\n"
+
+ "------=_Part_56_1672293592.1028122454656--\r\n";
+
public static final String
DISPOSITION_NOTIFICATION_REPORT_CONTENT_BOUNDARY =
"----=_Part_56_1672293592.1028122454656";
public static final String
DISPOSITION_NOTIFICATION_REPORT_CONTENT_CHARSET_NAME = "US-ASCII";
@@ -214,15 +249,8 @@ public class EntityParserTest {
@Test
public void parseMessageDispositionNotificationReportBodyTest() throws
Exception {
- InputStream is = new ByteArrayInputStream(
-
DISPOSITION_NOTIFICATION_REPORT_CONTENT.getBytes(DISPOSITION_NOTIFICATION_REPORT_CONTENT_CHARSET_NAME));
- AS2SessionInputBuffer inbuffer
- = new AS2SessionInputBuffer(new BasicHttpTransportMetrics(),
DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
-
- DispositionNotificationMultipartReportEntity
dispositionNotificationMultipartReportEntity = EntityParser
- .parseMultipartReportEntityBody(inbuffer, is,
DISPOSITION_NOTIFICATION_REPORT_CONTENT_BOUNDARY,
- DISPOSITION_NOTIFICATION_REPORT_CONTENT_CHARSET_NAME,
-
DISPOSITION_NOTIFICATION_REPORT_CONTENT_TRANSFER_ENCODING);
+ DispositionNotificationMultipartReportEntity
dispositionNotificationMultipartReportEntity
+ = createMdnEntity(DISPOSITION_NOTIFICATION_REPORT_CONTENT,
DISPOSITION_NOTIFICATION_REPORT_CONTENT_BOUNDARY);
assertNotNull(dispositionNotificationMultipartReportEntity,
"Unexpected Null disposition notification multipart entity");
@@ -234,6 +262,22 @@ public class EntityParserTest {
"Unexpected type for second body part");
}
+ // verify that parsing the MDN has made no alteration to the entity's body
part fields
+ @Test
+ public void messageDispositionNotificationReportBodyContentTest() throws
Exception {
+
+ DispositionNotificationMultipartReportEntity
dispositionNotificationMultipartReportEntity
+ =
createMdnEntity(DISPOSITION_NOTIFICATION_REPORT_CONTENT_UNFOLDED,
+ DISPOSITION_NOTIFICATION_REPORT_CONTENT_BOUNDARY);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ dispositionNotificationMultipartReportEntity.writeTo(out);
+
assertEquals(out.toString(DISPOSITION_NOTIFICATION_CONTENT_CHARSET_NAME),
+ new BasicHeader(AS2Header.CONTENT_TYPE,
ContentType.parse(REPORT_CONTENT_TYPE_VALUE))
+
+ "\r\n"
+
+ DISPOSITION_NOTIFICATION_REPORT_CONTENT_UNFOLDED);
+ }
+
@Test
public void parseTextPlainBodyTest() throws Exception {
@@ -377,6 +421,24 @@ public class EntityParserTest {
return utils.createAuthorityKeyIdentifier(info);
}
+ private DispositionNotificationMultipartReportEntity
createMdnEntity(String reportContent, String boundary)
+ throws Exception {
+ InputStream is = new ByteArrayInputStream(
+
reportContent.getBytes(DISPOSITION_NOTIFICATION_REPORT_CONTENT_CHARSET_NAME));
+ AS2SessionInputBuffer inbuffer
+ = new AS2SessionInputBuffer(new BasicHttpTransportMetrics(),
DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
+
+ DispositionNotificationMultipartReportEntity
dispositionNotificationMultipartReportEntity = EntityParser
+ .parseMultipartReportEntityBody(inbuffer, is, boundary,
+ DISPOSITION_NOTIFICATION_REPORT_CONTENT_CHARSET_NAME,
+
DISPOSITION_NOTIFICATION_REPORT_CONTENT_TRANSFER_ENCODING);
+
+ assertNotNull(dispositionNotificationMultipartReportEntity,
+ "Unexpected Null disposition notification multipart entity");
+
+ return dispositionNotificationMultipartReportEntity;
+ }
+
static SubjectKeyIdentifier createSubjectKeyId(PublicKey pub) throws
IOException {
SubjectPublicKeyInfo info =
SubjectPublicKeyInfo.getInstance(pub.getEncoded());