[ https://issues.apache.org/jira/browse/CAMEL-12605?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16629827#comment-16629827 ]
ASF GitHub Bot commented on CAMEL-12605: ---------------------------------------- oscerd closed pull request #2536: [CAMEL-12605] Added support for encrypted and signed AS2 message URL: https://github.com/apache/camel/pull/2536 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 c99f3413c74..5865efa9434 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 @@ -29,8 +29,10 @@ import org.apache.camel.component.as2.api.util.SigningUtils; import org.apache.http.HttpException; import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; import org.apache.http.entity.ContentType; import org.apache.http.message.BasicHttpEntityEnclosingRequest; +import org.apache.http.message.BasicNameValuePair; import org.apache.http.protocol.HttpCoreContext; import org.apache.http.util.Args; import org.bouncycastle.cms.CMSEnvelopedDataGenerator; @@ -252,31 +254,38 @@ public HttpCoreContext send(String ediMessage, throw new HttpException("Failed to create EDI message entity", e); } switch (as2MessageStructure) { - case PLAIN: + case PLAIN: { applicationEDIEntity.setMainBody(true); EntityUtils.setMessageEntity(request, applicationEDIEntity); break; - case SIGNED: + } + case SIGNED: { AS2SignedDataGenerator gen = createSigningGenerator(httpContext); // Create Multipart Signed Entity - try { - MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity, gen, - AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, true, null); - multipartSignedEntity.setMainBody(true); - EntityUtils.setMessageEntity(request, multipartSignedEntity); - } catch (Exception e) { - throw new HttpException("Failed to sign message", e); - } + MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity, gen, + AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, true, null); + multipartSignedEntity.setMainBody(true); + EntityUtils.setMessageEntity(request, multipartSignedEntity); break; - case ENCRYPTED: + } + case ENCRYPTED: { CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext); OutputEncryptor encryptor = createEncryptor(httpContext); ApplicationPkcs7MimeEntity pkcs7MimeEntity = new ApplicationPkcs7MimeEntity(applicationEDIEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true); EntityUtils.setMessageEntity(request, pkcs7MimeEntity); break; - case ENCRYPTED_SIGNED: - // TODO : Add code here to add application/pkcs7-mime entity when encryption facility available. + } + case ENCRYPTED_SIGNED: { + AS2SignedDataGenerator signingGenrator = createSigningGenerator(httpContext); + MultipartSignedEntity multipartSignedEntity = new MultipartSignedEntity(applicationEDIEntity, + signingGenrator, AS2Charset.US_ASCII, AS2TransferEncoding.BASE64, false, null); + + CMSEnvelopedDataGenerator envelopedDataGenerator = createEncryptingGenerator(httpContext); + OutputEncryptor encryptor = createEncryptor(httpContext); + ApplicationPkcs7MimeEntity pkcs7MimeEntity = new ApplicationPkcs7MimeEntity(multipartSignedEntity, envelopedDataGenerator, encryptor, AS2TransferEncoding.BASE64, true); + EntityUtils.setMessageEntity(request, pkcs7MimeEntity); break; + } default: throw new HttpException("Unknown AS2 Message Structure"); } @@ -292,7 +301,7 @@ public HttpCoreContext send(String ediMessage, httpContext.setAttribute(HTTP_RESPONSE, response); return httpContext; } - + public AS2SignedDataGenerator createSigningGenerator(HttpCoreContext httpContext) throws HttpException { Certificate[] certificateChain = httpContext.getAttribute(SIGNING_CERTIFICATE_CHAIN, Certificate[].class); 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 fcb2431561d..aaf12e86c8a 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 @@ -171,7 +171,7 @@ public static void skipToBoundary(AS2SessionInputBuffer inbuffer, String boundar throw new HttpException("Failed to read start boundary for body part", e); } - if (!foundEndBoundary) { + if (!foundEndBoundary && boundary != null) { throw new HttpException("Failed to find start boundary for body part"); } diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartMimeEntity.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartMimeEntity.java index 2b206f3bff7..03f5835ff4b 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartMimeEntity.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartMimeEntity.java @@ -55,6 +55,10 @@ public MultipartMimeEntity(ContentType contentType, boolean isMainBody, String b protected MultipartMimeEntity() { } + + public String getBoundary() { + return boundary; + } public void addPart(MimeEntity part) { parts.add(part); diff --git a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartSignedEntity.java b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartSignedEntity.java index 6869b5f381c..3b0a6d2bb19 100644 --- a/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartSignedEntity.java +++ b/components/camel-as2/camel-as2-api/src/main/java/org/apache/camel/component/as2/api/entity/MultipartSignedEntity.java @@ -22,10 +22,8 @@ import java.security.cert.X509Certificate; import java.util.Collection; -import org.apache.camel.component.as2.api.AS2Header; import org.apache.camel.component.as2.api.AS2SignedDataGenerator; -import org.apache.http.entity.ContentType; -import org.apache.http.message.BasicHeader; +import org.apache.http.HttpException; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cms.CMSProcessable; @@ -38,10 +36,9 @@ public class MultipartSignedEntity extends MultipartMimeEntity { - public MultipartSignedEntity(MimeEntity data, AS2SignedDataGenerator signer, String signatureCharSet, String signatureTransferEncoding, boolean isMainBody, String boundary) throws Exception { + public MultipartSignedEntity(MimeEntity data, AS2SignedDataGenerator signer, String signatureCharSet, String signatureTransferEncoding, boolean isMainBody, String boundary) throws HttpException { super(null, isMainBody, boundary); - ContentType contentType = signer.createMultipartSignedContentType(this.boundary); - this.contentType = new BasicHeader(AS2Header.CONTENT_TYPE, contentType.toString()); + setContentType(signer.createMultipartSignedContentType(this.boundary)); addPart(data); ApplicationPkcs7SignatureEntity signature = new ApplicationPkcs7SignatureEntity(data, signer, signatureCharSet, signatureTransferEncoding, false); addPart(signature); 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 d9d33384cb2..7d181aafb6a 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 @@ -366,105 +366,105 @@ public void multipartSignedMessageTest() throws Exception { @Test public void aes128CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES128_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.AES128_CBC); } @Test public void aes192CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES192_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.AES192_CBC); } @Test public void aes256CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES256_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.AES256_CBC); } @Test public void aes128CcmEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES128_CCM); + envelopedMessageTest(AS2EncryptionAlgorithm.AES128_CCM); } @Test public void aes192CcmEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES192_CCM); + envelopedMessageTest(AS2EncryptionAlgorithm.AES192_CCM); } @Test public void aes256CcmEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES256_CCM); + envelopedMessageTest(AS2EncryptionAlgorithm.AES256_CCM); } @Test public void aes128GcmEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES128_GCM); + envelopedMessageTest(AS2EncryptionAlgorithm.AES128_GCM); } @Test public void aes192GcmEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES192_GCM); + envelopedMessageTest(AS2EncryptionAlgorithm.AES192_GCM); } @Test public void aes256GcmEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.AES256_GCM); + envelopedMessageTest(AS2EncryptionAlgorithm.AES256_GCM); } @Test public void camellia128CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.CAMELLIA128_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.CAMELLIA128_CBC); } @Test public void camellia192CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.CAMELLIA192_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.CAMELLIA192_CBC); } @Test public void camellia256CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.CAMELLIA256_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.CAMELLIA256_CBC); } @Test public void cast5CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.CAST5_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.CAST5_CBC); } @Test public void desCbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.DES_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.DES_CBC); } @Test public void desEde3CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.DES_EDE3_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.DES_EDE3_CBC); } @Test public void cost28147GcfbEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.GOST28147_GCFB); + envelopedMessageTest(AS2EncryptionAlgorithm.GOST28147_GCFB); } @Test public void ideaCbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.IDEA_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.IDEA_CBC); } @Test public void rc2CbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.RC2_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.RC2_CBC); } @Test public void rc4EnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.RC4); + envelopedMessageTest(AS2EncryptionAlgorithm.RC4); } @Test public void seedCbcEnvelopedMessageTest() throws Exception { - envelopeddMessageTest(AS2EncryptionAlgorithm.SEED_CBC); + envelopedMessageTest(AS2EncryptionAlgorithm.SEED_CBC); } - public void envelopeddMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) throws Exception { + public void envelopedMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) throws Exception { AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN, TARGET_HOST, TARGET_PORT); AS2ClientManager clientManager = new AS2ClientManager(clientConnection); @@ -519,6 +519,80 @@ public void envelopeddMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) th } + @Test + public void aes128CbcEnvelopedAndSignedMessageTest() throws Exception { + envelopedAndSignedMessageTest(AS2EncryptionAlgorithm.AES128_CBC); + } + + public void envelopedAndSignedMessageTest(AS2EncryptionAlgorithm encryptionAlgorithm) throws Exception { + AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN, + TARGET_HOST, TARGET_PORT); + AS2ClientManager clientManager = new AS2ClientManager(clientConnection); + + LOG.info("Key Algoritm: " + signingKP.getPrivate().getAlgorithm()); + + HttpCoreContext httpContext = clientManager.send(EDI_MESSAGE, REQUEST_URI, SUBJECT, FROM, AS2_NAME, AS2_NAME, + AS2MessageStructure.ENCRYPTED_SIGNED, ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), + null, certList.toArray(new Certificate[0]), signingKP.getPrivate(), DISPOSITION_NOTIFICATION_TO, + SIGNED_RECEIPT_MIC_ALGORITHMS, encryptionAlgorithm, certList.toArray(new Certificate[0]), + signingKP.getPrivate()); + + HttpRequest request = httpContext.getRequest(); + assertEquals("Unexpected method value", METHOD, request.getRequestLine().getMethod()); + assertEquals("Unexpected request URI value", REQUEST_URI, request.getRequestLine().getUri()); + assertEquals("Unexpected HTTP version value", HttpVersion.HTTP_1_1, + request.getRequestLine().getProtocolVersion()); + + assertEquals("Unexpected subject value", SUBJECT, request.getFirstHeader(AS2Header.SUBJECT).getValue()); + assertEquals("Unexpected from value", FROM, request.getFirstHeader(AS2Header.FROM).getValue()); + assertEquals("Unexpected AS2 version value", AS2_VERSION, + request.getFirstHeader(AS2Header.AS2_VERSION).getValue()); + assertEquals("Unexpected AS2 from value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_FROM).getValue()); + assertEquals("Unexpected AS2 to value", AS2_NAME, request.getFirstHeader(AS2Header.AS2_TO).getValue()); + assertTrue("Unexpected message id value", + request.getFirstHeader(AS2Header.MESSAGE_ID).getValue().endsWith(CLIENT_FQDN + ">")); + assertEquals("Unexpected target host value", TARGET_HOST + ":" + TARGET_PORT, + request.getFirstHeader(AS2Header.TARGET_HOST).getValue()); + assertEquals("Unexpected user agent value", USER_AGENT, + request.getFirstHeader(AS2Header.USER_AGENT).getValue()); + assertNotNull("Date value missing", request.getFirstHeader(AS2Header.DATE)); + assertNotNull("Content length value missing", request.getFirstHeader(AS2Header.CONTENT_LENGTH)); + assertTrue("Unexpected content type for message", + request.getFirstHeader(AS2Header.CONTENT_TYPE).getValue().startsWith(AS2MimeType.APPLICATION_PKCS7_MIME)); + + assertTrue("Request does not contain entity", request instanceof BasicHttpEntityEnclosingRequest); + HttpEntity entity = ((BasicHttpEntityEnclosingRequest) request).getEntity(); + assertNotNull("Request does not contain entity", entity); + assertTrue("Unexpected request entity type", entity instanceof ApplicationPkcs7MimeEntity); + ApplicationPkcs7MimeEntity envelopedEntity = (ApplicationPkcs7MimeEntity) entity; + assertTrue("Entity not set as main body of request", envelopedEntity.isMainBody()); + + // Validated enveloped part. + MimeEntity encryptedEntity = envelopedEntity.getEncryptedEntity(signingKP.getPrivate()); + assertTrue("Enveloped mime part incorrect type ", encryptedEntity instanceof MultipartSignedEntity); + MultipartSignedEntity multipartSignedEntity = (MultipartSignedEntity) encryptedEntity; + assertTrue("Unexpected content type for enveloped mime part", + multipartSignedEntity.getContentType().getValue().startsWith(AS2MediaType.MULTIPART_SIGNED)); + assertFalse("Enveloped mime type set as main body of request", multipartSignedEntity.isMainBody()); + assertTrue("Request contains invalid number of mime parts", multipartSignedEntity.getPartCount() == 2); + + // Validated first mime part. + assertTrue("First mime part incorrect type ", multipartSignedEntity.getPart(0) instanceof ApplicationEDIFACTEntity); + ApplicationEDIFACTEntity ediEntity = (ApplicationEDIFACTEntity) multipartSignedEntity.getPart(0); + assertTrue("Unexpected content type for first mime part", + ediEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_EDIFACT)); + assertFalse("First mime type set as main body of request", ediEntity.isMainBody()); + + // Validate second mime part. + assertTrue("Second mime part incorrect type ", + multipartSignedEntity.getPart(1) instanceof ApplicationPkcs7SignatureEntity); + ApplicationPkcs7SignatureEntity signatureEntity = (ApplicationPkcs7SignatureEntity) multipartSignedEntity.getPart(1); + assertTrue("Unexpected content type for second mime part", + signatureEntity.getContentType().getValue().startsWith(AS2MediaType.APPLICATION_PKCS7_SIGNATURE)); + assertFalse("First mime type set as main body of request", signatureEntity.isMainBody()); + + } + @Test public void signatureVerificationTest() throws Exception { AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN, ---------------------------------------------------------------- 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 > 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 > > Enhance the AS2 Component to support encrypted AS2 messages per RFC4130 -- This message was sent by Atlassian JIRA (v7.6.3#76005)