This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 21410db [CAMEL-12605] Refactoring and fixed issue of receipt for compressed message 21410db is described below commit 21410db6e446757e84c0564fe798a8f05d609f0f Author: William Collins <punkhor...@gmail.com> AuthorDate: Tue Dec 11 13:16:18 2018 -0500 [CAMEL-12605] Refactoring and fixed issue of receipt for compressed message --- .../camel/component/as2/api/AS2ClientManager.java | 18 +- .../component/as2/api/entity/EntityParser.java | 351 ++++++++++++++------- .../camel/component/as2/api/util/EntityUtils.java | 7 + .../camel/component/as2/api/util/MicUtils.java | 31 +- .../camel/component/as2/api/util/SigningUtils.java | 14 - .../camel/component/as2/api/AS2MessageTest.java | 25 +- .../component/as2/api/entity/EntityParserTest.java | 2 +- components/camel-as2/camel-as2-component/pom.xml | 16 + .../as2/AS2ClientManagerIntegrationTest.java | 116 +++++-- .../as2/AS2ServerManagerIntegrationTest.java | 4 +- 10 files changed, 384 insertions(+), 200 deletions(-) diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java index 5f7ce3b..e6d8a4b 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/AS2ClientManager.java @@ -155,12 +155,6 @@ public class AS2ClientManager { public static final String ENCRYPTING_CERTIFICATE_CHAIN = CAMEL_AS2_CLIENT_PREFIX + "encrypting-certificate-chain"; /** - * The HTTP Context Attribute containing the private key used to encrypt EDI - * message - */ - public static final String ENCRYPTING_PRIVATE_KEY = CAMEL_AS2_CLIENT_PREFIX + "encrypting-private-key"; - - /** * The HTTP Context Attribute containing the algorithm used to compress EDI * message */ @@ -203,11 +197,11 @@ public class AS2ClientManager { * @param signingAlgorithm - the algorithm used to sign the message or <code>null</code> if sending EDI message unsigned * @param signingCertificateChain - the chain of certificates used to sign the message or <code>null</code> if sending EDI message unsigned * @param signingPrivateKey - the private key used to sign EDI message + * @param compressionAlgorithm - the algorithm used to compress the message or <code>null</code> if sending EDI message uncompressed * @param dispositionNotificationTo - an RFC2822 address to request a receipt or <code>null</code> if no receipt requested * @param signedReceiptMicAlgorithms - the senders list of signing algorithms for signing receipt, in preferred order, or <code>null</code> if requesting an unsigned receipt. * @param encryptingAlgorithm - the algorithm used to encrypt the message or <code>null</code> if sending EDI message unencrypted * @param encryptingCertificateChain - the chain of certificates used to encrypt the message or <code>null</code> if sending EDI message unencrypted - * @param encryptingPrivateKey - the private key used to encrypt EDI message * @return {@link HttpCoreContext} containing request and response used to send EDI message * @throws HttpException when things go wrong. */ @@ -227,13 +221,16 @@ public class AS2ClientManager { String dispositionNotificationTo, String[] signedReceiptMicAlgorithms, AS2EncryptionAlgorithm encryptingAlgorithm, - Certificate[] encryptingCertificateChain, - PrivateKey encryptingPrivateKey) + Certificate[] encryptingCertificateChain) throws HttpException { Args.notNull(ediMessage, "EDI Message"); - Args.notNull(as2MessageStructure, "AS2 Message Structure"); Args.notNull(requestUri, "Request URI"); + Args.notNull(subject, "Subject"); + Args.notNull(from, "Subject"); + Args.notNull(as2From, "Subject"); + Args.notNull(as2To, "Subject"); + Args.notNull(as2MessageStructure, "AS2 Message Structure"); Args.notNull(ediMessageContentType, "EDI Message Content Type"); // Add Context attributes @@ -254,7 +251,6 @@ public class AS2ClientManager { httpContext.setAttribute(AS2ClientManager.SIGNED_RECEIPT_MIC_ALGORITHMS, signedReceiptMicAlgorithms); httpContext.setAttribute(AS2ClientManager.ENCRYPTING_ALGORITHM, encryptingAlgorithm); httpContext.setAttribute(AS2ClientManager.ENCRYPTING_CERTIFICATE_CHAIN, encryptingCertificateChain); - httpContext.setAttribute(AS2ClientManager.ENCRYPTING_PRIVATE_KEY, encryptingPrivateKey); BasicHttpEntityEnclosingRequest request = new BasicHttpEntityEnclosingRequest("POST", requestUri); httpContext.setAttribute(HTTP_REQUEST, request); 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 f97b0ae..eb45639 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 @@ -38,6 +38,7 @@ import org.apache.camel.component.as2.api.util.EntityUtils; import org.apache.camel.component.as2.api.util.HttpMessageUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpException; import org.apache.http.HttpMessage; import org.apache.http.NameValuePair; @@ -58,19 +59,13 @@ import org.bouncycastle.cms.Recipient; import org.bouncycastle.cms.RecipientInformation; import org.bouncycastle.cms.RecipientInformationStore; import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient; +import org.bouncycastle.cms.jcajce.ZlibExpanderProvider; import org.bouncycastle.operator.InputExpanderProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public final class EntityParser { - private static final Logger LOG = LoggerFactory.getLogger(EntityParser.class); - private static final int DEFAULT_BUFFER_SIZE = 8 * 1024; - private static final String APPLICATION_EDI_CONTENT_TYPE_PREFIX = "application/edi"; - - private EntityParser() { } @@ -185,8 +180,6 @@ public final class EntityParser { byte[] uncompressedContent = uncompressData(compressedData, expanderProvider); - String uncompressedContentString = new String(uncompressedContent); - return parseEntity(uncompressedContent); } @@ -200,7 +193,6 @@ public final class EntityParser { public static MimeEntity parseEntity(byte[] content) throws HttpException { try { - String contentString = new String(content); InputStream is = new ByteArrayInputStream(content); AS2SessionInputBuffer inbuffer = new AS2SessionInputBuffer(new HttpTransportMetricsImpl(), DEFAULT_BUFFER_SIZE); inbuffer.bind(is); @@ -274,55 +266,87 @@ public final class EntityParser { throw new HttpException("Failed to decrypt data: bno recipeint information"); } - public static void parseMultipartSignedEntity(HttpMessage message) - throws HttpException { - MultipartSignedEntity multipartSignedEntity = null; + private static void parseApplicationPkcs7MimeCompressedEntity(HttpMessage message, AS2SessionInputBuffer inBuffer, ContentType contentType, String contentTransferEncoding) throws HttpException { + ApplicationPkcs7MimeCompressedDataEntity applicationPkcs7MimeCompressedDataEntity = null; + + Args.notNull(message, "message"); + Args.notNull(inBuffer, "inBuffer"); + HttpEntity entity = Args.notNull(EntityUtils.getMessageEntity(message), "message entity"); - if (entity instanceof MultipartSignedEntity) { + if (entity instanceof ApplicationPkcs7MimeCompressedDataEntity) { + // already parsed return; } + + Args.check(entity.isStreaming(), "Message entity can not be parsed: entity is not streaming"); + + try { + + applicationPkcs7MimeCompressedDataEntity = parseApplicationPkcs7MimeCompressedDataEntityBody(inBuffer, null, contentType, contentTransferEncoding); + applicationPkcs7MimeCompressedDataEntity.setMainBody(true); + + EntityUtils.setMessageEntity(message, applicationPkcs7MimeCompressedDataEntity); + + } catch (Exception e) { + throw new HttpException("Failed to parse entity content", e); + } + } + + private static void parseApplicationPkcs7MimeEnvelopedEntity(HttpMessage message, AS2SessionInputBuffer inBuffer, ContentType contentType, String contentTransferEncoding) throws HttpException { + ApplicationPkcs7MimeEnvelopedDataEntity applicationPkcs7MimeEnvelopedDataEntity = null; + + Args.notNull(message, "message"); + Args.notNull(inBuffer, "inBuffer"); + + HttpEntity entity = Args.notNull(EntityUtils.getMessageEntity(message), "message entity"); - Args.check(entity.isStreaming(), "Entity is not streaming"); + if (entity instanceof ApplicationPkcs7MimeCompressedDataEntity) { + // already parsed + return; + } + + Args.check(entity.isStreaming(), "Message entity can not be parsed: entity is not streaming"); try { + + applicationPkcs7MimeEnvelopedDataEntity = parseApplicationPkcs7MimeEnvelopedDataEntityBody(inBuffer, null, contentType, contentTransferEncoding); + applicationPkcs7MimeEnvelopedDataEntity.setMainBody(true); + + EntityUtils.setMessageEntity(message, applicationPkcs7MimeEnvelopedDataEntity); - // Determine and validate the Content Type - Header contentTypeHeader = entity.getContentType(); - if (contentTypeHeader == null) { - throw new HttpException("Content-Type header is missing"); - } - ContentType contentType = ContentType.parse(entity.getContentType().getValue()); - if (!contentType.getMimeType().equals(AS2MimeType.MULTIPART_SIGNED)) { - throw new HttpException("Entity has invalid MIME type '" + contentType.getMimeType() + "'"); - } + } catch (Exception e) { + throw new HttpException("Failed to parse entity content", e); + } + } + + private static void parseMultipartSignedEntity(HttpMessage message, AS2SessionInputBuffer inBuffer, String boundary, String charsetName, String contentTransferEncoding) + throws HttpException { + MultipartSignedEntity multipartSignedEntity = null; + + Args.notNull(message, "message"); + Args.notNull(inBuffer, "inBuffer"); + Args.notNull(boundary, "boundary"); + Args.notNull(charsetName, "charsetName"); + + HttpEntity entity = Args.notNull(EntityUtils.getMessageEntity(message), "message entity"); - // Determine Charset - String charsetName = AS2Charset.US_ASCII; - Charset charset = contentType.getCharset(); - if (charset != null) { - charsetName = charset.name(); - } + if (entity instanceof MultipartSignedEntity) { + // already parsed + return; + } - // Determine content transfer encoding - String contentTransferEncoding = HttpMessageUtils.getHeaderValue(message, AS2Header.CONTENT_TRANSFER_ENCODING); + Args.check(entity.isStreaming(), "Message entity can not be parsed: entity is not streaming"); - AS2SessionInputBuffer inbuffer = new AS2SessionInputBuffer(new HttpTransportMetricsImpl(), DEFAULT_BUFFER_SIZE); - inbuffer.bind(entity.getContent()); + try { - // Get Boundary Value - String boundary = HttpMessageUtils.getParameterValue(message, AS2Header.CONTENT_TYPE, "boundary"); - if (boundary == null) { - throw new HttpException("Failed to retrieve 'boundary' parameter from content type header"); - } - // Get Micalg Value String micalg = HttpMessageUtils.getParameterValue(message, AS2Header.CONTENT_TYPE, "micalg"); if (micalg == null) { throw new HttpException("Failed to retrieve 'micalg' parameter from content type header"); } - multipartSignedEntity = parseMultipartSignedEntityBody(inbuffer, boundary, micalg, charsetName, contentTransferEncoding); + multipartSignedEntity = parseMultipartSignedEntityBody(inBuffer, boundary, micalg, charsetName, contentTransferEncoding); multipartSignedEntity.setMainBody(true); EntityUtils.setMessageEntity(message, multipartSignedEntity); @@ -334,127 +358,123 @@ public final class EntityParser { } } - public static void parseApplicationEDIEntity(HttpMessage message) throws HttpException { + private static void parseApplicationEDIEntity(HttpMessage message, AS2SessionInputBuffer inBuffer, ContentType contentType, String contentTransferEncoding) throws HttpException { ApplicationEDIEntity applicationEDIEntity = null; + + Args.notNull(message, "message"); + Args.notNull(inBuffer, "inBuffer"); + HttpEntity entity = Args.notNull(EntityUtils.getMessageEntity(message), "message entity"); if (entity instanceof ApplicationEDIEntity) { + // already parsed return; } - Args.check(entity.isStreaming(), "Entity is not streaming"); + Args.check(entity.isStreaming(), "Message entity can not be parsed: entity is not streaming"); try { - // Determine and validate the Content Type - Header contentTypeHeader = entity.getContentType(); - if (contentTypeHeader == null) { - throw new HttpException("Content-Type header is missing"); - } - ContentType contentType = ContentType.parse(entity.getContentType().getValue()); - if (!contentType.getMimeType().startsWith(EntityParser.APPLICATION_EDI_CONTENT_TYPE_PREFIX)) { - throw new HttpException("Entity has invalid MIME type '" + contentType.getMimeType() + "'"); - } - - // Determine Transfer Encoding - Header transferEncoding = entity.getContentEncoding(); - String contentTransferEncoding = transferEncoding == null ? null : transferEncoding.getValue(); - - AS2SessionInputBuffer inBuffer = new AS2SessionInputBuffer(new HttpTransportMetricsImpl(), 8 * 1024); - inBuffer.bind(entity.getContent()); - applicationEDIEntity = parseEDIEntityBody(inBuffer, null, contentType, contentTransferEncoding); applicationEDIEntity.setMainBody(true); EntityUtils.setMessageEntity(message, applicationEDIEntity); - } catch (HttpException e) { - throw e; + } catch (Exception e) { throw new HttpException("Failed to parse entity content", e); } } - public static void parseMessageDispositionNotificationReportEntity(HttpMessage message) + private static void parseMessageDispositionNotificationReportEntity(HttpMessage message, AS2SessionInputBuffer inBuffer, String boundary, String charsetName, String contentTransferEncoding) throws HttpException { DispositionNotificationMultipartReportEntity dispositionNotificationMultipartReportEntity = null; + + Args.notNull(message, "message"); + Args.notNull(inBuffer, "inBuffer"); + Args.notNull(boundary, "boundary"); + Args.notNull(charsetName, "charsetName"); HttpEntity entity = Args.notNull(EntityUtils.getMessageEntity(message), "message entity"); if (entity instanceof DispositionNotificationMultipartReportEntity) { + // already parsed return; } - Args.check(entity.isStreaming(), "Entity is not streaming"); + Args.check(entity.isStreaming(), "Message entity can not be parsed: entity is not streaming"); try { - // Determine and validate the Content Type - Header contentTypeHeader = entity.getContentType(); - if (contentTypeHeader == null) { - throw new HttpException("Content-Type header is missing"); - } - ContentType contentType = ContentType.parse(entity.getContentType().getValue()); - if (!contentType.getMimeType().equals(AS2MimeType.MULTIPART_REPORT)) { - throw new HttpException("Entity has invalid MIME type '" + contentType.getMimeType() + "'"); - } - - // Determine Charset - String charsetName = AS2Charset.US_ASCII; - Charset charset = contentType.getCharset(); - if (charset != null) { - charsetName = charset.name(); - } - - // Determine content transfer encoding - String contentTransferEncoding = HttpMessageUtils.getHeaderValue(message, AS2Header.CONTENT_TRANSFER_ENCODING); - - AS2SessionInputBuffer inbuffer = new AS2SessionInputBuffer(new HttpTransportMetricsImpl(), 8 * 1024); - inbuffer.bind(entity.getContent()); - - // Get Boundary Value - String boundary = HttpMessageUtils.getParameterValue(message, AS2Header.CONTENT_TYPE, "boundary"); - if (boundary == null) { - throw new HttpException("Failed to retrive boundary value"); - } - - dispositionNotificationMultipartReportEntity = parseMultipartReportEntityBody(inbuffer, boundary, charsetName, contentTransferEncoding); + dispositionNotificationMultipartReportEntity = parseMultipartReportEntityBody(inBuffer, boundary, charsetName, contentTransferEncoding); EntityUtils.setMessageEntity(message, dispositionNotificationMultipartReportEntity); - } catch (HttpException e) { - throw e; } catch (Exception e) { throw new HttpException("Failed to parse entity content", e); } } + /** + * Parses message's entity and replaces it with mime entity. + * + * @param message - message whose entity is parsed. + * @throws HttpException when things go wrong. + */ public static void parseAS2MessageEntity(HttpMessage message) throws HttpException { if (EntityUtils.hasEntity(message)) { - String contentTypeStr = HttpMessageUtils.getHeaderValue(message, AS2Header.CONTENT_TYPE); - if (contentTypeStr != null) { - ContentType contentType; - try { - contentType = ContentType.parse(contentTypeStr); - } catch (Exception e) { - LOG.debug("Failed to get content type of message", e); - return; + HttpEntity entity = Args.notNull(EntityUtils.getMessageEntity(message), "message entity"); + + try { + // Determine Content Type of Message + String contentTypeStr = HttpMessageUtils.getHeaderValue(message, AS2Header.CONTENT_TYPE); + ContentType contentType = ContentType.parse(contentTypeStr); + + + // Determine Charset + String charsetName = AS2Charset.US_ASCII; + Charset charset = contentType.getCharset(); + if (charset != null) { + charsetName = charset.name(); } + + // Get any Boundary Value + String boundary = HttpMessageUtils.getParameterValue(message, AS2Header.CONTENT_TYPE, "boundary"); + + // Determine content transfer encoding + String contentTransferEncoding = HttpMessageUtils.getHeaderValue(message, AS2Header.CONTENT_TRANSFER_ENCODING); + + AS2SessionInputBuffer inBuffer = new AS2SessionInputBuffer(new HttpTransportMetricsImpl(), 8 * 1024); + inBuffer.bind(entity.getContent()); + switch (contentType.getMimeType().toLowerCase()) { case AS2MimeType.APPLICATION_EDIFACT: case AS2MimeType.APPLICATION_EDI_X12: case AS2MimeType.APPLICATION_EDI_CONSENT: - parseApplicationEDIEntity(message); + parseApplicationEDIEntity(message, inBuffer, contentType, contentTransferEncoding); break; case AS2MimeType.MULTIPART_SIGNED: - parseMultipartSignedEntity(message); + parseMultipartSignedEntity(message, inBuffer, boundary, charsetName, contentTransferEncoding); break; case AS2MimeType.APPLICATION_PKCS7_MIME: + switch (contentType.getParameter("smime-type")) { + case "compressed-data": + parseApplicationPkcs7MimeCompressedEntity(message, inBuffer, contentType, contentTransferEncoding); + break; + case "enveloped-data": + parseApplicationPkcs7MimeEnvelopedEntity(message, inBuffer, contentType, contentTransferEncoding); + break; + default: + } break; case AS2MimeType.MULTIPART_REPORT: - parseMessageDispositionNotificationReportEntity(message); + parseMessageDispositionNotificationReportEntity(message, inBuffer, boundary, charsetName, contentTransferEncoding); break; default: break; } + } catch (HttpException e) { + throw e; + } catch (Exception e) { + throw new HttpException("Failed to parse entity content", e); } } } @@ -1043,4 +1063,121 @@ public final class EntityParser { } return fields; } + + public static HttpEntity extractEdiPayload(HttpEntityEnclosingRequest request, PrivateKey privateKey) throws HttpException { + + 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); + + parseAS2MessageEntity(request); + MimeEntity ediEntity = null; + switch (contentType.getMimeType().toLowerCase()) { + case AS2MimeType.APPLICATION_EDIFACT: + case AS2MimeType.APPLICATION_EDI_X12: + case AS2MimeType.APPLICATION_EDI_CONSENT: { + ediEntity = HttpMessageUtils.getEntity(request, ApplicationEDIEntity.class); + break; + } + case AS2MimeType.MULTIPART_SIGNED: { + MultipartSignedEntity multipartSignedEntity = HttpMessageUtils.getEntity(request, + MultipartSignedEntity.class); + ediEntity = multipartSignedEntity.getSignedDataEntity(); + break; + } + case AS2MimeType.APPLICATION_PKCS7_MIME: { + switch(contentType.getParameter("smime-type")) { + case "compressed-data": { + ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity = HttpMessageUtils.getEntity(request, ApplicationPkcs7MimeCompressedDataEntity.class); + ediEntity = extractEdiPayloadFromCompressedEntity(compressedDataEntity); + break; + } + case "enveloped-data": { + if (privateKey == null) { + throw new HttpException("Failed to get EDI message from encrypted request: private key is null"); + } + ApplicationPkcs7MimeEnvelopedDataEntity envelopedDataEntity = HttpMessageUtils.getEntity(request, ApplicationPkcs7MimeEnvelopedDataEntity.class); + ediEntity = extractEdiPayloadFromEnvelopedEntity(envelopedDataEntity, privateKey); + break; + } + default: + throw new HttpException("Failed to create MIC: unknown " + AS2MimeType.APPLICATION_PKCS7_MIME + " smime-type: " + contentType.getParameter("smime-type")); + } + break; + } + default: + throw new HttpException("Failed to create MIC: invalid content type '" + contentType.getMimeType() + "' for message integrity check"); + } + + return ediEntity; + + } + + private static MimeEntity extractEdiPayloadFromEnvelopedEntity(ApplicationPkcs7MimeEnvelopedDataEntity envelopedDataEntity, PrivateKey privateKey) throws HttpException { + MimeEntity ediEntity = null; + + MimeEntity entity = envelopedDataEntity.getEncryptedEntity(privateKey); + String contentTypeString = entity.getContentTypeValue(); + if (contentTypeString == null) { + throw new HttpException("Failed to create MIC: content type missing from encrypted entity"); + } + ContentType contentType = ContentType.parse(contentTypeString); + + switch(contentType.getMimeType().toLowerCase()) { + case AS2MimeType.APPLICATION_EDIFACT: + case AS2MimeType.APPLICATION_EDI_X12: + case AS2MimeType.APPLICATION_EDI_CONSENT: { + ediEntity = entity; + break; + } + case AS2MimeType.MULTIPART_SIGNED: { + MultipartSignedEntity multipartSignedEntity = (MultipartSignedEntity) entity; + ediEntity = multipartSignedEntity.getSignedDataEntity(); + break; + } + case AS2MimeType.APPLICATION_PKCS7_MIME: { + if (contentType.getParameter("mime-type").equals("compressed-data")) { + throw new HttpException("Failed to extract EDI payload: invalid mime type '" + contentType.getParameter("mime-type") + "' for AS2 enveloped entity"); + } + ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity = (ApplicationPkcs7MimeCompressedDataEntity) entity; + ediEntity = extractEdiPayloadFromCompressedEntity(compressedDataEntity); + break; + } + default: + throw new HttpException("Failed to extract EDI payload: invalid content type '" + contentType.getMimeType() + "' for AS2 enveloped entity"); + } + + return ediEntity; + } + + private static MimeEntity extractEdiPayloadFromCompressedEntity(ApplicationPkcs7MimeCompressedDataEntity compressedDataEntity) throws HttpException { + MimeEntity ediEntity = null; + + MimeEntity entity = compressedDataEntity.getCompressedEntity(new ZlibExpanderProvider()); + String contentTypeString = entity.getContentTypeValue(); + if (contentTypeString == null) { + throw new HttpException("Failed to extract EDI payload: content type missing from compressed entity"); + } + ContentType contentType = ContentType.parse(contentTypeString); + + switch(contentType.getMimeType().toLowerCase()) { + case AS2MimeType.APPLICATION_EDIFACT: + case AS2MimeType.APPLICATION_EDI_X12: + case AS2MimeType.APPLICATION_EDI_CONSENT: { + ediEntity = entity; + break; + } + case AS2MimeType.MULTIPART_SIGNED: { + MultipartSignedEntity multipartSignedEntity = (MultipartSignedEntity) entity; + ediEntity = multipartSignedEntity.getSignedDataEntity(); + break; + } + default: + throw new HttpException("Failed to extract EDI payload: invalid content type '" + contentType.getMimeType() + "' for AS2 compressed entity"); + } + + return ediEntity; + } } 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 926d345..560eb1c 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 @@ -32,6 +32,7 @@ import org.apache.camel.component.as2.api.entity.ApplicationEDIConsentEntity; import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity; 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.MimeEntity; import org.apache.commons.codec.binary.Base64InputStream; import org.apache.commons.codec.binary.Base64OutputStream; import org.apache.commons.codec.net.QuotedPrintableCodec; @@ -242,6 +243,12 @@ public final class EntityUtils { if (contentTypeHeader != null) { message.setHeader(contentTypeHeader); } + if (entity instanceof MimeEntity) { + Header contentTransferEncodingHeader = ((MimeEntity)entity).getContentTransferEncoding(); + if (contentTransferEncodingHeader != null) { + message.setHeader(contentTransferEncodingHeader); + } + } long contentLength = entity.getContentLength(); message.setHeader(AS2Header.CONTENT_LENGTH, Long.toString(contentLength)); } 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 4aec7f6..8eb66b1 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,6 +25,7 @@ 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.ApplicationEDIEntity; +import org.apache.camel.component.as2.api.entity.ApplicationPkcs7MimeCompressedDataEntity; 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; @@ -96,33 +97,7 @@ public final class MicUtils { return null; } - String contentTypeString = HttpMessageUtils.getHeaderValue(request, AS2Header.CONTENT_TYPE); - if (contentTypeString == null) { - LOG.debug("can not create MIC: content type missing from request"); - return null; - } - ContentType contentType = ContentType.parse(contentTypeString); - - HttpEntity entity = null; - switch (contentType.getMimeType().toLowerCase()) { - case AS2MimeType.APPLICATION_EDIFACT: - case AS2MimeType.APPLICATION_EDI_X12: - case AS2MimeType.APPLICATION_EDI_CONSENT: { - EntityParser.parseAS2MessageEntity(request); - entity = HttpMessageUtils.getEntity(request, ApplicationEDIEntity.class); - break; - } - case AS2MimeType.MULTIPART_SIGNED: { - EntityParser.parseAS2MessageEntity(request); - MultipartSignedEntity multipartSignedEntity = HttpMessageUtils.getEntity(request, - MultipartSignedEntity.class); - entity = multipartSignedEntity.getSignedDataEntity(); - break; - } - default: - LOG.debug("can not create MIC: invalid content type '{}' for message integrity check", contentType.getMimeType()); - return null; - } + HttpEntity entity = EntityParser.extractEdiPayload(request, null); byte[] content = EntityUtils.getContent(entity); @@ -131,7 +106,7 @@ public final class MicUtils { try { return new ReceivedContentMic(micAS2AlgorithmName, mic); } catch (Exception e) { - throw new HttpException("failed to encode MIC", e); + throw new HttpException("Failed to encode MIC", e); } } diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/SigningUtils.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/SigningUtils.java index f4b530a0..ffe26df 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/SigningUtils.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/util/SigningUtils.java @@ -77,20 +77,6 @@ public final class SigningUtils { } catch (Exception e) { throw new HttpException("Failed to create signer info", e); } -// for (String signingAlgorithmName : AS2SignedDataGenerator.getSupportedSignatureAlgorithmNamesForKey(privateKey)) { -// try { -// signerInfoGenerator = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC") -// .setSignedAttributeGenerator(new AttributeTable(attributes)) -// .build(signingAlgorithmName, privateKey, signingCert); -// break; -// } catch (Exception e) { -// signerInfoGenerator = null; -// continue; -// } -// } -// if (signerInfoGenerator == null) { -// throw new HttpException("Failed to create signer info"); -// } gen.addSignerInfoGenerator(signerInfoGenerator); // Create and populate certificate store. diff --git a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java index b764d62..b9d336a 100644 --- a/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java +++ b/components/camel-as2/camel-as2-api/src/test/java/org/apache/camel/component/as2/api/AS2MessageTest.java @@ -272,7 +272,7 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), - null, null, null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); + null, null, null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -316,7 +316,7 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), - null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); + null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -478,7 +478,7 @@ public class AS2MessageTest { ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm, - certList.toArray(new Certificate[0]), signingKP.getPrivate()); + certList.toArray(new Certificate[0])); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -539,7 +539,7 @@ public class AS2MessageTest { ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm, - certList.toArray(new Certificate[0]), signingKP.getPrivate()); + certList.toArray(new Certificate[0])); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -606,7 +606,7 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), - null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); + null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null); HttpRequest request = httpContext.getRequest(); assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest); @@ -634,8 +634,7 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), - null, null, null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, - null); + null, null, null, null, null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null); HttpResponse response = httpContext.getResponse(); assertEquals("Unexpected method value", HttpVersion.HTTP_1_1, response.getStatusLine().getProtocolVersion()); @@ -751,7 +750,7 @@ public class AS2MessageTest { ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, null, null, null, AS2CompressionAlgorithm.ZLIB, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, - null, null); + null); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -804,10 +803,10 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.SIGNED_COMPRESSED, - ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, + ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), "base64", AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), AS2CompressionAlgorithm.ZLIB, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, - null, null); + null); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -875,10 +874,10 @@ public class AS2MessageTest { HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.ENCRYPTED_COMPRESSED, - ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, + ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), "base64", null, null, null, AS2CompressionAlgorithm.ZLIB, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, AS2EncryptionAlgorithm.AES128_CBC, - certList.toArray(new Certificate[0]), signingKP.getPrivate()); + certList.toArray(new Certificate[0])); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); @@ -942,7 +941,7 @@ public class AS2MessageTest { ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), AS2CompressionAlgorithm.ZLIB, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, - AS2EncryptionAlgorithm.AES128_CBC, certList.toArray(new Certificate[0]), signingKP.getPrivate()); + AS2EncryptionAlgorithm.AES128_CBC, certList.toArray(new Certificate[0])); HttpRequest request = httpContext.getRequest(); assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); 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 d5b3a0d..ead2037 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 @@ -204,7 +204,7 @@ public class EntityParserTest { entity.setContent(is); EntityUtils.setMessageEntity(response, entity); - EntityParser.parseMessageDispositionNotificationReportEntity(response); + EntityParser.parseAS2MessageEntity(response); HttpEntity parsedEntity = EntityUtils.getMessageEntity(response); assertNotNull("Unexpected Null message disposition notification report entity", parsedEntity); assertTrue("Unexpected type for message disposition notification report entity", parsedEntity instanceof DispositionNotificationMultipartReportEntity); diff --git a/components/camel-as2/camel-as2-component/pom.xml b/components/camel-as2/camel-as2-component/pom.xml index 8903e25..d6ca3a7 100644 --- a/components/camel-as2/camel-as2-component/pom.xml +++ b/components/camel-as2/camel-as2-component/pom.xml @@ -156,7 +156,23 @@ <proxyClass>org.apache.camel.component.as2.api.AS2ClientManager</proxyClass> <fromJavadoc> <excludeMethods>createSigningGenerator</excludeMethods> + <excludeMethods>createEncryptingGenerator</excludeMethods> + <excludeMethods>createCompressorGenerator</excludeMethods> + <excludeMethods>createEncryptor</excludeMethods> + <excludeMethods>createCompressor</excludeMethods> </fromJavadoc> + <nullableOptions> + <nullableOption>ediMessageTransferEncoding</nullableOption> + <nullableOption>signingAlgorithm</nullableOption> + <nullableOption>signingCertificateChain</nullableOption> + <nullableOption>signingPrivateKey</nullableOption> + <nullableOption>compressionAlgorithm</nullableOption> + <nullableOption>dispositionNotificationTo</nullableOption> + <nullableOption>signedReceiptMicAlgorithms</nullableOption> + <nullableOption>encryptingAlgorithm</nullableOption> + <nullableOption>encryptingCertificateChain</nullableOption> + <nullableOption>encryptingPrivateKey</nullableOption> + </nullableOptions> </api> <api> <apiName>server</apiName> diff --git a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java index 36c0386..9f83ea2 100644 --- a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java +++ b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ClientManagerIntegrationTest.java @@ -31,6 +31,7 @@ import org.apache.camel.Processor; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.as2.api.AS2AsynchronousMDNManager; import org.apache.camel.component.as2.api.AS2Charset; +import org.apache.camel.component.as2.api.AS2CompressionAlgorithm; import org.apache.camel.component.as2.api.AS2Constants; import org.apache.camel.component.as2.api.AS2EncryptionAlgorithm; import org.apache.camel.component.as2.api.AS2Header; @@ -45,6 +46,7 @@ import org.apache.camel.component.as2.api.entity.AS2DispositionModifier; import org.apache.camel.component.as2.api.entity.AS2DispositionType; import org.apache.camel.component.as2.api.entity.AS2MessageDispositionNotificationEntity; import org.apache.camel.component.as2.api.entity.ApplicationEDIEntity; +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.ApplicationPkcs7SignatureEntity; import org.apache.camel.component.as2.api.entity.DispositionMode; @@ -83,6 +85,7 @@ import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder; +import org.bouncycastle.cms.jcajce.ZlibExpanderProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.AfterClass; import org.junit.Before; @@ -222,20 +225,8 @@ public class AS2ClientManagerIntegrationTest extends AbstractAS2TestSupport { headers.put("CamelAS2.ediMessageContentType", ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII)); // parameter type is String headers.put("CamelAS2.ediMessageTransferEncoding", EDI_MESSAGE_CONTENT_TRANSFER_ENCODING); - // parameter type is java.security.cert.Certificate[] - headers.put("CamelAS2.signingCertificateChain", null); - // parameter type is java.security.PrivateKey - headers.put("CamelAS2.signingPrivateKey", null); // parameter type is String headers.put("CamelAS2.dispositionNotificationTo", "mr...@example.com"); - // parameter type is String[] - headers.put("CamelAS2.signedReceiptMicAlgorithms", null); - // parameter type is org.apache.camel.component.as2.api.AS2EncryptionAlgorithm - headers.put("CamelAS2.encryptingAlgorithm", null); - // parameter type is java.security.cert.Certificate[] - headers.put("CamelAS2.encryptingCertificateChain", null); - // parameter type is java.security.PrivateKey - headers.put("CamelAS2.encryptingPrivateKey", null); final org.apache.http.protocol.HttpCoreContext result = requestBodyAndHeaders("direct://SEND", EDI_MESSAGE, headers); @@ -302,14 +293,8 @@ public class AS2ClientManagerIntegrationTest extends AbstractAS2TestSupport { headers.put("CamelAS2.ediMessageContentType", ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII)); // parameter type is String headers.put("CamelAS2.ediMessageTransferEncoding", EDI_MESSAGE_CONTENT_TRANSFER_ENCODING); - // parameter type is java.security.cert.Certificate[] - headers.put("CamelAS2.signingCertificateChain", null); - // parameter type is java.security.PrivateKey - headers.put("CamelAS2.signingPrivateKey", null); // parameter type is String headers.put("CamelAS2.dispositionNotificationTo", "mr...@example.com"); - // parameter type is String[] - headers.put("CamelAS2.signedReceiptMicAlgorithms", null); // parameter type is org.apache.camel.component.as2.api.AS2EncryptionAlgorithm headers.put("CamelAS2.encryptingAlgorithm", AS2EncryptionAlgorithm.AES128_CBC); // parameter type is java.security.cert.Certificate[] @@ -384,6 +369,8 @@ public class AS2ClientManagerIntegrationTest extends AbstractAS2TestSupport { headers.put("CamelAS2.ediMessageContentType", ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII)); // parameter type is String headers.put("CamelAS2.ediMessageTransferEncoding", EDI_MESSAGE_CONTENT_TRANSFER_ENCODING); + // parameter type is org.apache.camel.component.as2.api.AS2SignatureAlgorithm + headers.put("CamelAS2.signingAlgorithm", AS2SignatureAlgorithm.SHA512WITHRSA); // parameter type is java.security.cert.Certificate[] headers.put("CamelAS2.signingCertificateChain", certList.toArray(new Certificate[0])); // parameter type is java.security.PrivateKey @@ -392,12 +379,6 @@ public class AS2ClientManagerIntegrationTest extends AbstractAS2TestSupport { headers.put("CamelAS2.dispositionNotificationTo", "mr...@example.com"); // parameter type is String[] headers.put("CamelAS2.signedReceiptMicAlgorithms", SIGNED_RECEIPT_MIC_ALGORITHMS); - // parameter type is org.apache.camel.component.as2.api.AS2EncryptionAlgorithm - headers.put("CamelAS2.encryptingAlgorithm", null); - // parameter type is java.security.cert.Certificate[] - headers.put("CamelAS2.encryptingCertificateChain", null); - // parameter type is java.security.PrivateKey - headers.put("CamelAS2.encryptingPrivateKey", null); final org.apache.http.protocol.HttpCoreContext result = requestBodyAndHeaders("direct://SEND", EDI_MESSAGE, headers); @@ -461,6 +442,93 @@ public class AS2ClientManagerIntegrationTest extends AbstractAS2TestSupport { } @Test + public void compressedMessageTest() throws Exception { + final Map<String, Object> headers = new HashMap<>(); + // parameter type is String + headers.put("CamelAS2.requestUri", REQUEST_URI); + // parameter type is String + headers.put("CamelAS2.subject", SUBJECT); + // parameter type is String + headers.put("CamelAS2.from", FROM); + // parameter type is String + headers.put("CamelAS2.as2From", AS2_NAME); + // parameter type is String + headers.put("CamelAS2.as2To", AS2_NAME); + // parameter type is org.apache.camel.component.as2.api.AS2MessageStructure + headers.put("CamelAS2.as2MessageStructure", AS2MessageStructure.PLAIN_COMPRESSED); + // parameter type is org.apache.http.entity.ContentType + headers.put("CamelAS2.ediMessageContentType", ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII)); + // parameter type is String + headers.put("CamelAS2.ediMessageTransferEncoding", EDI_MESSAGE_CONTENT_TRANSFER_ENCODING); + // parameter type is org.apache.camel.component.as2.api.AS2CompressionAlgorithm + headers.put("CamelAS2.compressionAlgorithm", AS2CompressionAlgorithm.ZLIB); + // parameter type is String + headers.put("CamelAS2.dispositionNotificationTo", "mr...@example.com"); + // parameter type is String[] + headers.put("CamelAS2.signedReceiptMicAlgorithms", SIGNED_RECEIPT_MIC_ALGORITHMS); + + final org.apache.http.protocol.HttpCoreContext result = requestBodyAndHeaders("direct://SEND", EDI_MESSAGE, headers); + + assertNotNull("send result", result); + LOG.debug("send: " + result); + HttpRequest request = result.getRequest(); + assertNotNull("Request", request); + assertTrue("Request does not contain body", request instanceof HttpEntityEnclosingRequest); + HttpEntity entity = ((HttpEntityEnclosingRequest)request).getEntity(); + assertNotNull("Request body", entity); + assertTrue("Request body does not contain EDI entity", entity instanceof ApplicationPkcs7MimeCompressedDataEntity); + + MimeEntity compressedEntity = ((ApplicationPkcs7MimeCompressedDataEntity)entity).getCompressedEntity(new ZlibExpanderProvider()); + assertTrue("Signed entity wrong type", compressedEntity instanceof ApplicationEDIEntity); + ApplicationEDIEntity ediMessageEntity = (ApplicationEDIEntity) compressedEntity; + String ediMessage = ediMessageEntity.getEdiMessage(); + assertEquals("EDI message is different", EDI_MESSAGE.replaceAll("[\n\r]", ""), ediMessage.replaceAll("[\n\r]", "")); + + HttpResponse response = result.getResponse(); + assertNotNull("Response", response); + String contentTypeHeaderValue = HttpMessageUtils.getHeaderValue(response, AS2Header.CONTENT_TYPE); + ContentType responseContentType = ContentType.parse(contentTypeHeaderValue); + assertEquals("Unexpected response type", AS2MimeType.MULTIPART_SIGNED, responseContentType.getMimeType()); + assertEquals("Unexpected mime version", AS2Constants.MIME_VERSION, HttpMessageUtils.getHeaderValue(response, AS2Header.MIME_VERSION)); + assertEquals("Unexpected AS2 version", EXPECTED_AS2_VERSION, HttpMessageUtils.getHeaderValue(response, AS2Header.AS2_VERSION)); + assertEquals("Unexpected MDN subject", EXPECTED_MDN_SUBJECT, HttpMessageUtils.getHeaderValue(response, AS2Header.SUBJECT)); + assertEquals("Unexpected MDN from", MDN_FROM, HttpMessageUtils.getHeaderValue(response, AS2Header.FROM)); + assertEquals("Unexpected AS2 from", AS2_NAME, HttpMessageUtils.getHeaderValue(response, AS2Header.AS2_FROM)); + assertEquals("Unexpected AS2 to", AS2_NAME, HttpMessageUtils.getHeaderValue(response, AS2Header.AS2_TO)); + assertNotNull("Missing message id", HttpMessageUtils.getHeaderValue(response, AS2Header.MESSAGE_ID)); + + HttpEntity responseEntity = response.getEntity(); + assertNotNull("Response entity", responseEntity); + assertTrue("Unexpected response entity type", responseEntity instanceof MultipartSignedEntity); + MultipartSignedEntity responseSignedEntity = (MultipartSignedEntity) responseEntity; + assertTrue("Signature for response entity is invalid", responseSignedEntity.isValid()); + MimeEntity responseSignedDataEntity = responseSignedEntity.getSignedDataEntity(); + assertTrue("Signed entity wrong type", responseSignedDataEntity instanceof DispositionNotificationMultipartReportEntity); + DispositionNotificationMultipartReportEntity reportEntity = (DispositionNotificationMultipartReportEntity)responseSignedDataEntity; + assertEquals("Unexpected number of body parts in report", 2, reportEntity.getPartCount()); + MimeEntity firstPart = reportEntity.getPart(0); + assertEquals("Unexpected content type in first body part of report", ContentType.create(AS2MimeType.TEXT_PLAIN, AS2Charset.US_ASCII).toString(), firstPart.getContentTypeValue()); + MimeEntity secondPart = reportEntity.getPart(1); + assertEquals("Unexpected content type in second body part of report", + ContentType.create(AS2MimeType.MESSAGE_DISPOSITION_NOTIFICATION, AS2Charset.US_ASCII).toString(), + secondPart.getContentTypeValue()); + ApplicationPkcs7SignatureEntity signatureEntity = responseSignedEntity.getSignatureEntity(); + assertNotNull("Signature Entity", signatureEntity); + + assertTrue("", secondPart instanceof AS2MessageDispositionNotificationEntity); + AS2MessageDispositionNotificationEntity messageDispositionNotificationEntity = (AS2MessageDispositionNotificationEntity) secondPart; + assertEquals("Unexpected value for reporting UA", ORIGIN_SERVER_NAME, messageDispositionNotificationEntity.getReportingUA()); + assertEquals("Unexpected value for final recipient", AS2_NAME, messageDispositionNotificationEntity.getFinalRecipient()); + assertEquals("Unexpected value for original message ID", HttpMessageUtils.getHeaderValue(request, AS2Header.MESSAGE_ID), messageDispositionNotificationEntity.getOriginalMessageId()); + assertEquals("Unexpected value for disposition mode", DispositionMode.AUTOMATIC_ACTION_MDN_SENT_AUTOMATICALLY, messageDispositionNotificationEntity.getDispositionMode()); + assertEquals("Unexpected value for disposition type", AS2DispositionType.PROCESSED, messageDispositionNotificationEntity.getDispositionType()); + + ReceivedContentMic receivedContentMic = messageDispositionNotificationEntity.getReceivedContentMic(); + ReceivedContentMic computedContentMic = MicUtils.createReceivedContentMic((HttpEntityEnclosingRequest)request); + assertEquals("Received content MIC does not match computed", computedContentMic.getEncodedMessageDigest(), receivedContentMic.getEncodedMessageDigest()); + } + + @Test public void asyncMDNTest() throws Exception { AS2AsynchronousMDNManager mdnManager = new AS2AsynchronousMDNManager(AS2_VERSION, ORIGIN_SERVER_NAME, SERVER_FQDN, certList.toArray(new X509Certificate[0]), signingKP.getPrivate()); diff --git a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java index 0f6b931..cb58af7 100644 --- a/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java +++ b/components/camel-as2/camel-as2-component/src/test/java/org/apache/camel/component/as2/AS2ServerManagerIntegrationTest.java @@ -128,7 +128,7 @@ public class AS2ServerManagerIntegrationTest extends AbstractAS2TestSupport { clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.PLAIN, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, null, null, null, - null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); + null, DISPOSITION_NOTIFICATION_TO, SIGNED_RECEIPT_MIC_ALGORITHMS, null, null); MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs"); mockEndpoint.expectedMinimumMessageCount(1); @@ -186,7 +186,7 @@ public class AS2ServerManagerIntegrationTest extends AbstractAS2TestSupport { clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, AS2MessageStructure.SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, AS2SignatureAlgorithm.SHA256WITHRSA, certList.toArray(new Certificate[0]), signingKP.getPrivate(), null, DISPOSITION_NOTIFICATION_TO, - SIGNED_RECEIPT_MIC_ALGORITHMS, null, null, null); + SIGNED_RECEIPT_MIC_ALGORITHMS, null, null); MockEndpoint mockEndpoint = getMockEndpoint("mock:as2RcvMsgs"); mockEndpoint.expectedMinimumMessageCount(1);