[ https://issues.apache.org/jira/browse/CAMEL-12605?focusedWorklogId=174523&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-174523 ]
ASF GitHub Bot logged work on CAMEL-12605: ------------------------------------------ Author: ASF GitHub Bot Created on: 12/Dec/18 14:05 Start Date: 12/Dec/18 14:05 Worklog Time Spent: 10m Work Description: oscerd closed pull request #2666: [CAMEL-12605] Refactoring and fixed issue of receipt for compressed m… URL: https://github.com/apache/camel/pull/2666 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): 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 5f7ce3bfc90..e6d8a4b33ce 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 @@ -154,12 +154,6 @@ */ 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 AS2ClientManager(AS2ClientConnection as2ClientConnection) { * @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 HttpCoreContext send(String ediMessage, 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 HttpCoreContext send(String ediMessage, 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 f97b0ae8656..eb4563919dc 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.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.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 static MimeEntity parseCompressedEntity(byte[] compressedData, InputExpan byte[] uncompressedContent = uncompressData(compressedData, expanderProvider); - String uncompressedContentString = new String(uncompressedContent); - return parseEntity(uncompressedContent); } @@ -200,7 +193,6 @@ public static MimeEntity parseEnvelopedEntity(byte[] envelopedContent, PrivateKe 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 static MimeEntity parseEntity(byte[] content) throws HttpException { 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 static void parseMultipartSignedEntity(HttpMessage message) } } - 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 static String parseBodyPartText(final AS2SessionInputBuffer inbuffer, } 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 926d345d190..560eb1c93ad 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.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 static void setMessageEntity(HttpMessage message, HttpEntity entity) { 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 4aec7f665d9..8eb66b13d86 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.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 static ReceivedContentMic createReceivedContentMic(HttpEntityEnclosingReq 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 static ReceivedContentMic createReceivedContentMic(HttpEntityEnclosingReq 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 f4b530a019e..ffe26df4024 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 static AS2SignedDataGenerator createSigningGenerator(AS2SignatureAlgorith } 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 b764d620bc4..b9d336ac030 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 void plainEDIMessageTest() throws Exception { 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 void multipartSignedMessageTest() throws Exception { 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 void envelopedMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) thr 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 void envelopedAndSignedMessageTest(AS2EncryptionAlgorithm encryptionAlgor 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 void signatureVerificationTest() throws Exception { 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 void mdnMessageTest() throws Exception { 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 void compressedMessageTest() throws Exception { 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 void compressedAndSignedMessageTest() throws Exception { 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 void envelopedAndCompressedMessageTest() throws Exception { 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 void envelopedCompressedAndSignedMessageTest() throws Exception { 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 d5b3a0dd646..ead203705a9 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 void parseMessageDispositionNotificationReportMessageTest() throws Except 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 8903e25dca7..d6ca3a7d6a6 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 36c03866316..9f83ea2747d 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.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.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.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 void plainMessageSendTest() throws Exception { 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 void envelopedMessageSendTest() throws Exception { 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 void multipartSignedMessageTest() throws Exception { 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 void multipartSignedMessageTest() throws Exception { 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); @@ -460,6 +441,93 @@ public void multipartSignedMessageTest() throws Exception { assertEquals("Received content MIC does not match computed", computedContentMic.getEncodedMessageDigest(), receivedContentMic.getEncodedMessageDigest()); } + @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, 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 0f6b93125ca..cb58af7716e 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 void receivePlainEDIMessageTest() throws Exception { 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 void receiveMultipartSignedMessageTest() throws Exception { 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); ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org Issue Time Tracking ------------------- Worklog Id: (was: 174523) Time Spent: 10m Remaining Estimate: 0h > Enhance the AS2 Component to send and receive encrypted AS2 messages > -------------------------------------------------------------------- > > Key: CAMEL-12605 > URL: https://issues.apache.org/jira/browse/CAMEL-12605 > Project: Camel > Issue Type: Improvement > Affects Versions: 2.23.0 > Reporter: William Collins > Assignee: William Collins > Priority: Major > Time Spent: 10m > Remaining Estimate: 0h > > Enhance the AS2 Component to support encrypted AS2 messages per RFC4130 -- This message was sent by Atlassian JIRA (v7.6.3#76005)