This is an automated email from the ASF dual-hosted git repository. ppalaga pushed a commit to branch camel-master in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
commit f786db63e4f97a1b1a8c1f9710a724ee71198e3a Author: JiriOndrusek <ondrusek.j...@gmail.com> AuthorDate: Mon Jul 20 15:30:39 2020 +0200 Add Camel AS2 Modules as Quarkus Extension #1471 --- catalog/pom.xml | 2 + docs/modules/ROOT/nav.adoc | 1 + docs/modules/ROOT/pages/reference/components.adoc | 3 + .../ROOT/pages/reference/extensions/as2.adoc | 37 +++++ docs/modules/ROOT/pages/reference/index.adoc | 3 + extensions-support/bouncycastle/deployment/pom.xml | 69 +++++++++ .../deployment/BouncycastleSupportProcessor.java | 54 +++++++ extensions-support/{ => bouncycastle}/pom.xml | 34 +---- extensions-support/bouncycastle/runtime/pom.xml | 80 ++++++++++ .../main/resources/META-INF/quarkus-extension.yaml | 27 ++++ extensions-support/pom.xml | 1 + extensions/as2/deployment/pom.xml | 67 ++++++++ .../component/as2/deployment/As2Processor.java | 87 +++++++++++ extensions/as2/pom.xml | 39 +++++ extensions/as2/runtime/pom.xml | 108 +++++++++++++ extensions/as2/runtime/src/main/doc/usage.adoc | 4 + .../camel/quarkus/component/as2/As2Recorder.java | 34 +++++ .../main/resources/META-INF/quarkus-extension.yaml | 31 ++++ extensions/pom.xml | 1 + integration-tests/as2/pom.xml | 145 ++++++++++++++++++ .../component/as2/it/As2CertificateHelper.java | 140 +++++++++++++++++ .../quarkus/component/as2/it/As2Resource.java | 131 ++++++++++++++++ .../component/as2/it/transport/ClientResult.java | 68 +++++++++ .../component/as2/it/transport/Request.java | 152 ++++++++++++++++++ .../component/as2/it/transport/ServerResult.java | 39 +++++ .../as2/src/main/resources/application.properties | 18 +++ .../camel/quarkus/component/as2/it/As2Helper.java | 123 +++++++++++++++ .../camel/quarkus/component/as2/it/As2IT.java | 24 +++ .../quarkus/component/as2/it/As2Receiver.java | 169 +++++++++++++++++++++ .../camel/quarkus/component/as2/it/As2Sender.java | 54 +++++++ .../camel/quarkus/component/as2/it/As2Test.java | 127 ++++++++++++++++ .../quarkus/component/as2/it/As2TestResource.java | 35 +++++ integration-tests/pom.xml | 1 + pom.xml | 1 + poms/bom/pom.xml | 35 +++++ tooling/scripts/test-categories.yaml | 1 + 36 files changed, 1918 insertions(+), 27 deletions(-) diff --git a/catalog/pom.xml b/catalog/pom.xml index c64a753..5aa78ea 100644 --- a/catalog/pom.xml +++ b/catalog/pom.xml @@ -44,6 +44,7 @@ camel-quarkus-amqp camel-quarkus-apns camel-quarkus-arangodb + camel-quarkus-as2 camel-quarkus-asterisk camel-quarkus-atmos camel-quarkus-atom @@ -246,6 +247,7 @@ camel-quarkus-support-ahc camel-quarkus-support-aws camel-quarkus-support-aws2 + camel-quarkus-support-bouncycastle camel-quarkus-support-common camel-quarkus-support-commons-logging camel-quarkus-support-consul-client diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index e5e414b..7dffb40 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -19,6 +19,7 @@ *** xref:reference/extensions/amqp.adoc[AMQP] *** xref:reference/extensions/apns.adoc[APNS] *** xref:reference/extensions/arangodb.adoc[ArangoDb] +*** xref:reference/extensions/as2.adoc[AS2] *** xref:reference/extensions/asterisk.adoc[Asterisk] *** xref:reference/extensions/ahc.adoc[Async HTTP Client (AHC)] *** xref:reference/extensions/ahc-ws.adoc[Async HTTP Client (AHC) Websocket] diff --git a/docs/modules/ROOT/pages/reference/components.adoc b/docs/modules/ROOT/pages/reference/components.adoc index 5ea5ced..09da315 100644 --- a/docs/modules/ROOT/pages/reference/components.adoc +++ b/docs/modules/ROOT/pages/reference/components.adoc @@ -22,6 +22,9 @@ Preview | 1.1.0 | Send notifications to Apple iOS devices. | xref:reference/extensions/arangodb.adoc[ArangoDb] | [.camel-element-artifact]##camel-quarkus-arangodb## | [.camel-element-Native]##Native## + Stable | 1.1.0 | Perform operations on ArangoDb when used as a Document Database, or as a Graph Database +| xref:reference/extensions/as2.adoc[AS2] | [.camel-element-artifact]##camel-quarkus-as2## | [.camel-element-Native]##Native## + +Stable | 1.0.0-CR4 | Transfer data securely and reliably using the AS2 protocol (RFC4130). + | xref:reference/extensions/asterisk.adoc[Asterisk] | [.camel-element-artifact]##camel-quarkus-asterisk## | [.camel-element-JVM]##JVM## + Preview | 1.1.0 | Interact with Asterisk PBX Server. diff --git a/docs/modules/ROOT/pages/reference/extensions/as2.adoc b/docs/modules/ROOT/pages/reference/extensions/as2.adoc new file mode 100644 index 0000000..23db52b --- /dev/null +++ b/docs/modules/ROOT/pages/reference/extensions/as2.adoc @@ -0,0 +1,37 @@ +// Do not edit directly! +// This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page + +[[as2]] += AS2 +:page-aliases: extensions/as2.adoc + +[.badges] +[.badge-key]##Since Camel Quarkus##[.badge-version]##1.0.0-CR4## [.badge-key]##JVM##[.badge-supported]##supported## [.badge-key]##Native##[.badge-supported]##supported## + +Transfer data securely and reliably using the AS2 protocol (RFC4130). + +== What's inside + +* https://camel.apache.org/components/latest/as2-component.html[AS2 component], URI syntax: `as2:apiName/methodName` + +Please refer to the above link for usage and configuration details. + +== Maven coordinates + +[source,xml] +---- +<dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-as2</artifactId> +</dependency> +---- + +Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications. + +== Usage + +Depending on its configuration, this component may require SSL encryption on its connections. In such a case, you will need +to add `quarkus.ssl.native=true` to your `application.properties`. +See also https://quarkus.io/guides/native-and-ssl[Quarkus native SSL guide] and xref:user-guide/native-mode.adoc[Native mode] +section of Camel Quarkus user guide. + diff --git a/docs/modules/ROOT/pages/reference/index.adoc b/docs/modules/ROOT/pages/reference/index.adoc index 76e9a03..0a400c3 100644 --- a/docs/modules/ROOT/pages/reference/index.adoc +++ b/docs/modules/ROOT/pages/reference/index.adoc @@ -35,6 +35,9 @@ Preview | 1.1.0 | Send notifications to Apple iOS devices. | xref:reference/extensions/arangodb.adoc[ArangoDb] | camel-quarkus-arangodb | [.camel-element-Native]##Native## + Stable | 1.1.0 | Perform operations on ArangoDb when used as a Document Database, or as a Graph Database +| xref:reference/extensions/as2.adoc[AS2] | camel-quarkus-as2 | [.camel-element-Native]##Native## + +Stable | 1.0.0-CR4 | Transfer data securely and reliably using the AS2 protocol (RFC4130). + | xref:reference/extensions/asterisk.adoc[Asterisk] | camel-quarkus-asterisk | [.camel-element-JVM]##JVM## + Preview | 1.1.0 | Interact with Asterisk PBX Server. diff --git a/extensions-support/bouncycastle/deployment/pom.xml b/extensions-support/bouncycastle/deployment/pom.xml new file mode 100644 index 0000000..477c47b --- /dev/null +++ b/extensions-support/bouncycastle/deployment/pom.xml @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-support-bouncycastle-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-support-bouncycastle-deployment</artifactId> + <name>Camel Quarkus :: Support :: Bouncy Castle :: Deployment</name> + + <dependencies> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-core-deployment</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-support-bouncycastle</artifactId> + </dependency> + <dependency> + <artifactId>bcprov-jdk15on</artifactId> + <groupId>org.bouncycastle</groupId> + </dependency> + <dependency> + <artifactId>bcpkix-jdk15on</artifactId> + <groupId>org.bouncycastle</groupId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-extension-processor</artifactId> + <version>${quarkus.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/extensions-support/bouncycastle/deployment/src/main/java/org/apache/camel/quarkus/support/bouncycastle/deployment/BouncycastleSupportProcessor.java b/extensions-support/bouncycastle/deployment/src/main/java/org/apache/camel/quarkus/support/bouncycastle/deployment/BouncycastleSupportProcessor.java new file mode 100644 index 0000000..47dfbac --- /dev/null +++ b/extensions-support/bouncycastle/deployment/src/main/java/org/apache/camel/quarkus/support/bouncycastle/deployment/BouncycastleSupportProcessor.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.support.bouncycastle.deployment; + +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.CombinedIndexBuildItem; +import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.IndexDependencyBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; +import org.jboss.jandex.IndexView; + +public class BouncycastleSupportProcessor { + static final String FEATURE = "camel-support-bouncycastle"; + + @BuildStep + FeatureBuildItem feature() { + return new FeatureBuildItem(FEATURE); + } + + @BuildStep + ReflectiveClassBuildItem registerForReflection(CombinedIndexBuildItem combinedIndex) { + IndexView index = combinedIndex.getIndex(); + + String[] dtos = index.getKnownClasses().stream() + .map(ci -> ci.name().toString()) + .filter(n -> n.startsWith("org.bouncycastle.jcajce.provider.digest.") || + n.startsWith("org.bouncycastle.jcajce.provider.symmetric.") || + n.startsWith("org.bouncycastle.jcajce.provider.asymmetric.") || + n.startsWith("org.bouncycastle.jcajce.provider.keystore.")) + .sorted() + .toArray(String[]::new); + + return new ReflectiveClassBuildItem(false, false, dtos); + } + + @BuildStep + IndexDependencyBuildItem registerBCDependencyForIndex() { + return new IndexDependencyBuildItem("org.bouncycastle", "bcprov-jdk15on"); + } +} diff --git a/extensions-support/pom.xml b/extensions-support/bouncycastle/pom.xml similarity index 57% copy from extensions-support/pom.xml copy to extensions-support/bouncycastle/pom.xml index 12dee0c..f1bc64d 100644 --- a/extensions-support/pom.xml +++ b/extensions-support/bouncycastle/pom.xml @@ -18,40 +18,20 @@ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - + <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache.camel.quarkus</groupId> - <artifactId>camel-quarkus</artifactId> + <artifactId>camel-quarkus-build-parent</artifactId> <version>1.1.0-SNAPSHOT</version> + <relativePath>../../poms/build-parent/pom.xml</relativePath> </parent> - <modelVersion>4.0.0</modelVersion> - - <artifactId>camel-quarkus-extensions-support</artifactId> - <name>Camel Quarkus :: Extensions :: Support</name> + <artifactId>camel-quarkus-support-bouncycastle-parent</artifactId> + <name>Camel Quarkus :: Support :: Bouncy Castle</name> <packaging>pom</packaging> <modules> - <!-- extensions a..z; do not remove this comment, it is important when sorting via mvn process-resources -Pformat --> - <module>ahc</module> - <module>aws</module> - <module>aws2</module> - <module>common</module> - <module>commons-logging</module> - <module>consul-client</module> - <module>debezium</module> - <module>google-http-client</module> - <module>httpclient</module> - <module>jackson-dataformat-xml</module> - <module>jetty</module> - <module>mail</module> - <module>mongodb</module> - <module>policy</module> - <module>retrofit</module> - <module>spring</module> - <module>webhook</module> - <module>xstream</module> - <module>xml</module> - <module>xalan</module> + <module>deployment</module> + <module>runtime</module> </modules> </project> diff --git a/extensions-support/bouncycastle/runtime/pom.xml b/extensions-support/bouncycastle/runtime/pom.xml new file mode 100644 index 0000000..07a6eac --- /dev/null +++ b/extensions-support/bouncycastle/runtime/pom.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-support-bouncycastle-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-support-bouncycastle</artifactId> + <name>Camel Quarkus :: Support :: Bouncy Castle :: Runtime</name> + + <properties> + <firstVersion>1.1.0</firstVersion> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-bom</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-core</artifactId> + </dependency> + <dependency> + <groupId>org.javassist</groupId> + <artifactId>javassist</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-bootstrap-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-extension-processor</artifactId> + <version>${quarkus.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/extensions-support/bouncycastle/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions-support/bouncycastle/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000..50c9c1a --- /dev/null +++ b/extensions-support/bouncycastle/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,27 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +--- +name: "Camel Quarkus Support Bouncy Castle" +description: "Camel Quarkus Support Bouncy Castle" +metadata: + unlisted: true + keywords: + - "camel" + guide: "https://quarkus.io/guides/camel" + categories: + - "integration" diff --git a/extensions-support/pom.xml b/extensions-support/pom.xml index 12dee0c..8fd3916 100644 --- a/extensions-support/pom.xml +++ b/extensions-support/pom.xml @@ -36,6 +36,7 @@ <module>ahc</module> <module>aws</module> <module>aws2</module> + <module>bouncycastle</module> <module>common</module> <module>commons-logging</module> <module>consul-client</module> diff --git a/extensions/as2/deployment/pom.xml b/extensions/as2/deployment/pom.xml new file mode 100644 index 0000000..83d9cf6 --- /dev/null +++ b/extensions/as2/deployment/pom.xml @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-as2-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-as2-deployment</artifactId> + <name>Camel Quarkus :: AS2 :: Deployment</name> + + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-core-deployment</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-as2</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-support-bouncycastle-deployment</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-extension-processor</artifactId> + <version>${quarkus.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> + +</project> diff --git a/extensions/as2/deployment/src/main/java/org/apache/camel/quarkus/component/as2/deployment/As2Processor.java b/extensions/as2/deployment/src/main/java/org/apache/camel/quarkus/component/as2/deployment/As2Processor.java new file mode 100644 index 0000000..8aebdaf --- /dev/null +++ b/extensions/as2/deployment/src/main/java/org/apache/camel/quarkus/component/as2/deployment/As2Processor.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.deployment; + +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.ExecutionTime; +import io.quarkus.deployment.annotations.Record; +import io.quarkus.deployment.builditem.CombinedIndexBuildItem; +import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.IndexDependencyBuildItem; +import io.quarkus.deployment.builditem.LogConsoleFormatBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; +import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; +import org.apache.camel.component.as2.AS2ClientManagerEndpointConfiguration; +import org.apache.camel.component.as2.AS2ServerManagerEndpointConfiguration; +import org.apache.camel.component.as2.api.util.AS2Utils; +import org.apache.camel.quarkus.component.as2.As2Recorder; +import org.jboss.jandex.IndexView; + +class As2Processor { + + private static final String FEATURE = "camel-as2"; + + @BuildStep + FeatureBuildItem feature() { + return new FeatureBuildItem(FEATURE); + } + + @BuildStep + RuntimeInitializedClassBuildItem runtimeInitializedClasses() { + return new RuntimeInitializedClassBuildItem(AS2Utils.class.getCanonicalName()); + } + + @BuildStep + ReflectiveClassBuildItem registerAs2ConfigurationForReflection() { + return new ReflectiveClassBuildItem(true, true, + AS2ServerManagerEndpointConfiguration.class.getCanonicalName(), + AS2ClientManagerEndpointConfiguration.class.getCanonicalName(), + java.security.AlgorithmParameterGeneratorSpi.class.getCanonicalName()); + } + + @BuildStep + ReflectiveClassBuildItem registerForReflection(CombinedIndexBuildItem combinedIndex) { + IndexView index = combinedIndex.getIndex(); + + String[] dtos = index.getKnownClasses().stream() + .map(ci -> ci.name().toString()) + .filter(n -> n.startsWith("org.apache.velocity.runtime") || n.startsWith("org.apache.velocity.util")) + .sorted() + .toArray(String[]::new); + + return new ReflectiveClassBuildItem(false, false, dtos); + } + + @BuildStep + IndexDependencyBuildItem registerDependencyForIndex() { + return new IndexDependencyBuildItem("org.apache.velocity", "velocity-engine-core"); + } + + @BuildStep + NativeImageResourceBuildItem initResources() { + return new NativeImageResourceBuildItem("org/apache/velocity/runtime/defaults/velocity.properties", + "org/apache/velocity/runtime/defaults/directive.properties"); + } + + @BuildStep + @Record(ExecutionTime.RUNTIME_INIT) + public LogConsoleFormatBuildItem setUpFormatter(As2Recorder as2Recorder) { + return new LogConsoleFormatBuildItem(as2Recorder.createFormatter()); + } + +} diff --git a/extensions/as2/pom.xml b/extensions/as2/pom.xml new file mode 100644 index 0000000..6440496 --- /dev/null +++ b/extensions/as2/pom.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-build-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../../poms/build-parent/pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-as2-parent</artifactId> + <name>Camel Quarkus :: AS2</name> + <packaging>pom</packaging> + + <modules> + <module>deployment</module> + <module>runtime</module> + </modules> +</project> diff --git a/extensions/as2/runtime/pom.xml b/extensions/as2/runtime/pom.xml new file mode 100644 index 0000000..6ee151f --- /dev/null +++ b/extensions/as2/runtime/pom.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-as2-parent</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-as2</artifactId> + <name>Camel Quarkus :: AS2 :: Runtime</name> + <description>Transfer data securely and reliably using the AS2 protocol (RFC4130).</description> + + <properties> + <firstVersion>1.0.0-CR4</firstVersion> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-bom</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-core</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-as2</artifactId> + <exclusions> + <exclusion> + <artifactId>log4j-slf4j-impl</artifactId> + <groupId>org.apache.logging.log4j</groupId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-support-bouncycastle</artifactId> + </dependency> + <dependency> + <groupId>org.jboss.slf4j</groupId> + <artifactId>slf4j-jboss-logging</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-maven-plugin</artifactId> + <executions> + <execution> + <id>update-extension-doc-page</id> + <goals><goal>update-extension-doc-page</goal></goals> + <phase>process-classes</phase> + </execution> + </executions> + </plugin> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-bootstrap-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <annotationProcessorPaths> + <path> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-extension-processor</artifactId> + <version>${quarkus.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> +</project> diff --git a/extensions/as2/runtime/src/main/doc/usage.adoc b/extensions/as2/runtime/src/main/doc/usage.adoc new file mode 100644 index 0000000..f0af355 --- /dev/null +++ b/extensions/as2/runtime/src/main/doc/usage.adoc @@ -0,0 +1,4 @@ +Depending on its configuration, this component may require SSL encryption on its connections. In such a case, you will need +to add `quarkus.ssl.native=true` to your `application.properties`. +See also https://quarkus.io/guides/native-and-ssl[Quarkus native SSL guide] and xref:user-guide/native-mode.adoc[Native mode] +section of Camel Quarkus user guide. diff --git a/extensions/as2/runtime/src/main/java/org/apache/camel/quarkus/component/as2/As2Recorder.java b/extensions/as2/runtime/src/main/java/org/apache/camel/quarkus/component/as2/As2Recorder.java new file mode 100644 index 0000000..cbfe6bb --- /dev/null +++ b/extensions/as2/runtime/src/main/java/org/apache/camel/quarkus/component/as2/As2Recorder.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.quarkus.component.as2; + +import java.util.Optional; +import java.util.logging.Formatter; + +import io.quarkus.runtime.RuntimeValue; +import io.quarkus.runtime.annotations.Recorder; +import org.jboss.logmanager.formatters.PatternFormatter; + +@Recorder +public class As2Recorder { + + public RuntimeValue<Optional<Formatter>> createFormatter() { + final Formatter formatter = new PatternFormatter("[%30.30t] %-30.30c{1} %-5p %m%n"); + return new RuntimeValue<>(Optional.of(formatter)); + } +} diff --git a/extensions/as2/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/as2/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000..7ecc69c --- /dev/null +++ b/extensions/as2/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This is a generated file. Do not edit directly! +# To re-generate, run the following command from the top level directory: +# +# mvn -N cq:update-quarkus-metadata +# +--- +name: "Camel AS2" +description: "Transfer data securely and reliably using the AS2 protocol (RFC4130)" +metadata: + guide: "https://camel.apache.org/camel-quarkus/latest/reference/extensions/as2.html" + categories: + - "integration" + status: + - "stable" diff --git a/extensions/pom.xml b/extensions/pom.xml index dc708c9..15a1df3 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -38,6 +38,7 @@ <module>ahc-ws</module> <module>amqp</module> <module>arangodb</module> + <module>as2</module> <module>attachments</module> <module>avro</module> <module>aws-ec2</module> diff --git a/integration-tests/as2/pom.xml b/integration-tests/as2/pom.xml new file mode 100644 index 0000000..e1d0dad --- /dev/null +++ b/integration-tests/as2/pom.xml @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-tests</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>../pom.xml</relativePath> + </parent> + + <artifactId>camel-quarkus-integration-test-as2</artifactId> + <name>Camel Quarkus :: Integration Tests :: AS2</name> + <description>Integration tests for Camel Quarkus AS2 extension</description> + + <properties> + <!-- mvnd, a.k.a. Maven Daemon: https://github.com/gnodet/mvnd --> + <!-- The following rule tells mvnd to build the listed deployment modules before this module. --> + <!-- This is important because mvnd builds modules in parallel by default. The deployment modules are not --> + <!-- explicit dependencies of this module in the Maven sense, although they are required by the Quarkus Maven plugin. --> + <!-- Please update rule whenever you change the dependencies of this module by running --> + <!-- mvn process-resources -Pformat from the root directory --> + <mvnd.builder.rule>camel-quarkus-as2-deployment,camel-quarkus-mock-deployment,camel-quarkus-support-policy-deployment</mvnd.builder.rule> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-bom-test</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-as2</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-resteasy</artifactId> + </dependency> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-resteasy-jackson</artifactId> + </dependency> + + <!-- test dependencies --> + <dependency> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-junit5</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.rest-assured</groupId> + <artifactId>rest-assured</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-integration-test-support</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-mock</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>io.quarkus</groupId> + <artifactId>quarkus-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>build</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>native</id> + <activation> + <property> + <name>native</name> + </property> + </activation> + <properties> + <quarkus.package.type>native</quarkus.package.type> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-failsafe-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> + +</project> diff --git a/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/As2CertificateHelper.java b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/As2CertificateHelper.java new file mode 100644 index 0000000..d6089e6 --- /dev/null +++ b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/As2CertificateHelper.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.camel.component.as2.api.AS2ClientConnection; +import org.apache.camel.component.as2.api.AS2ClientManager; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.bc.BcX509ExtensionUtils; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +public class As2CertificateHelper { + + private static final String TARGET_HOST = "localhost"; + private static final String AS2_VERSION = "1.1"; + private static final String USER_AGENT = "Camel AS2 Endpoint"; + private static final String CLIENT_FQDN = "example.org"; + + private static KeyPair signingKP; + private static X509Certificate signingCert; + private static List<X509Certificate> certList; + // certificate serial number seed. + static int serialNo = 1; + + private As2CertificateHelper() { + } + + public static void setup() throws Exception { + Security.addProvider(new BouncyCastleProvider()); + + // + // set up our certificates + // + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC"); + + kpg.initialize(1024, new SecureRandom()); + + String issueDN = "O=Earth 2 Software, C=E2"; + KeyPair issueKP = kpg.generateKeyPair(); + X509Certificate issueCert = makeCertificate( + issueKP, issueDN, issueKP, issueDN); + + // + // certificate we sign against + // + String signingDN = "CN=Shekdon, E=t...@gmail.com, O=Earth 2 Software, C=E2"; + signingKP = kpg.generateKeyPair(); + signingCert = makeCertificate( + signingKP, signingDN, issueKP, issueDN); + + certList = new ArrayList<>(); + + certList.add(signingCert); + certList.add(issueCert); + + } + + /** + * create a basic X509 certificate from the given keys + */ + public static X509Certificate makeCertificate(KeyPair subKP, String subDN, KeyPair issKP, String issDN) + throws GeneralSecurityException, IOException, OperatorCreationException { + PublicKey subPub = subKP.getPublic(); + PrivateKey issPriv = issKP.getPrivate(); + PublicKey issPub = issKP.getPublic(); + + X509v3CertificateBuilder v3CertGen = new JcaX509v3CertificateBuilder(new X500Name(issDN), + BigInteger.valueOf(serialNo++), new Date(System.currentTimeMillis()), + new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)), new X500Name(subDN), subPub); + + v3CertGen.addExtension(Extension.subjectKeyIdentifier, false, createSubjectKeyId(subPub)); + + v3CertGen.addExtension(Extension.authorityKeyIdentifier, false, createAuthorityKeyId(issPub)); + + return new JcaX509CertificateConverter().setProvider("BC").getCertificate( + v3CertGen.build(new JcaContentSignerBuilder("MD5withRSA").setProvider("BC").build(issPriv))); + } + + public static AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pub) throws IOException { + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pub.getEncoded()); + + BcX509ExtensionUtils utils = new BcX509ExtensionUtils(); + return utils.createAuthorityKeyIdentifier(info); + } + + public static SubjectKeyIdentifier createSubjectKeyId(PublicKey pub) throws IOException { + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pub.getEncoded()); + + return new BcX509ExtensionUtils().createSubjectKeyIdentifier(info); + } + + public static AS2ClientManager createClient(int port) throws IOException { + AS2ClientConnection clientConnection = new AS2ClientConnection(AS2_VERSION, USER_AGENT, CLIENT_FQDN, TARGET_HOST, port); + return new AS2ClientManager(clientConnection); + } + + public static List<X509Certificate> getCertList() { + return certList; + } + + public static KeyPair getSigningKP() { + return signingKP; + } +} diff --git a/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/As2Resource.java b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/As2Resource.java new file mode 100644 index 0000000..3f4c04d --- /dev/null +++ b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/As2Resource.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import org.apache.camel.ConsumerTemplate; +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.as2.api.entity.DispositionNotificationMultipartReportEntity; +import org.apache.camel.component.as2.api.entity.MimeEntity; +import org.apache.camel.component.as2.api.entity.MultipartSignedEntity; +import org.apache.camel.component.as2.internal.AS2Constants; +import org.apache.camel.quarkus.component.as2.it.transport.ClientResult; +import org.apache.camel.quarkus.component.as2.it.transport.Request; +import org.apache.camel.quarkus.component.as2.it.transport.ServerResult; +import org.apache.http.protocol.HttpCoreContext; +import org.jboss.logging.Logger; + +@Path("/as2") +@ApplicationScoped +public class As2Resource { + + public static String CLIENT_PORT_PARAMETER = As2Resource.class.getSimpleName() + "-client-port"; + public static String SERVER_PORT_PARAMETER = As2Resource.class.getSimpleName() + "-server-port"; + + private static final Logger LOG = Logger.getLogger(As2Resource.class); + + @Inject + ProducerTemplate producerTemplate; + + @Inject + ConsumerTemplate consumerTemplate; + + @Path("/client") + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public ClientResult client(Request request) throws Exception { + LOG.infof("Sending to as2: %s", request.getHeaders()); + As2CertificateHelper.setup(); + final Object response = producerTemplate.requestBodyAndHeaders(getClientEndpoint(), + request.getEdiMessage(), request.collectHeaders()); + ClientResult clientResult = new ClientResult(); + if (response instanceof DispositionNotificationMultipartReportEntity) { + clientResult.setDispositionNotificationMultipartReportEntity(true); + clientResult.setPartsCount(((DispositionNotificationMultipartReportEntity) response).getPartCount()); + if (clientResult.getPartsCount() > 1) { + clientResult.setSecondPartClassName( + ((DispositionNotificationMultipartReportEntity) response).getPart(1).getClass().getSimpleName()); + } + } else if (response instanceof MultipartSignedEntity) { + clientResult.setMultipartSignedEntity(true); + MimeEntity responseSignedDataEntity = ((MultipartSignedEntity) response).getSignedDataEntity(); + clientResult + .setPartsCount(((DispositionNotificationMultipartReportEntity) responseSignedDataEntity).getPartCount()); + if (clientResult.getPartsCount() > 1) { + clientResult.setSecondPartClassName( + ((DispositionNotificationMultipartReportEntity) responseSignedDataEntity).getPart(1).getClass() + .getSimpleName()); + } + clientResult.setSignedEntityReceived(((MultipartSignedEntity) response).getSignatureEntity() != null); + } + + LOG.infof("Got response from as2: %s", response); + return clientResult; + } + + @Path("/serverInit") + @GET + @Produces(MediaType.APPLICATION_JSON) + public boolean serverInit() throws Exception { + LOG.info("Initializing server from as2 component."); + //execute request, which won't return anything, because client doesn't send anything, but it starts component + consumerTemplate.receiveNoWait(getServerEndpoint()); + return true; + } + + @Path("/server") + @GET + @Produces(MediaType.APPLICATION_JSON) + public ServerResult server() throws Exception { + LOG.info("Receiving from as2."); + Exchange exchange = consumerTemplate.receive(getServerEndpoint()); + if (exchange == null) { + return null; + } + ServerResult serverResult = new ServerResult(); + serverResult.setResult(exchange.getIn().getBody(String.class)); + HttpCoreContext coreContext = exchange.getProperty(AS2Constants.AS2_INTERCHANGE, HttpCoreContext.class); + if (coreContext != null) { + serverResult.setRequestClass(coreContext.getRequest().getClass().getSimpleName()); + } + return serverResult; + } + + private String getServerEndpoint() { + String url = String.format("as2://server/listen?serverPortNumber=%s&clientFqdn=%s&requestUriPattern=/", + System.getProperty(SERVER_PORT_PARAMETER), "example.com"); + + return url; + } + + private String getClientEndpoint() { + String url = String.format("as2://client/send?inBody=ediMessage&targetPortNumber=%s&targetHostname=%s", + System.getProperty(CLIENT_PORT_PARAMETER), "localhost"); + + return url; + } +} diff --git a/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/ClientResult.java b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/ClientResult.java new file mode 100644 index 0000000..2c8518e --- /dev/null +++ b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/ClientResult.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it.transport; + +public class ClientResult { + + boolean dispositionNotificationMultipartReportEntity; + boolean multipartSignedEntity; + boolean signedEntityReceived; + + int partsCount; + + String secondPartClassName; + + public boolean isDispositionNotificationMultipartReportEntity() { + return dispositionNotificationMultipartReportEntity; + } + + public void setDispositionNotificationMultipartReportEntity(boolean dispositionNotificationMultipartReportEntity) { + this.dispositionNotificationMultipartReportEntity = dispositionNotificationMultipartReportEntity; + } + + public int getPartsCount() { + return partsCount; + } + + public void setPartsCount(int partsCount) { + this.partsCount = partsCount; + } + + public String getSecondPartClassName() { + return secondPartClassName; + } + + public void setSecondPartClassName(String secondPartClassName) { + this.secondPartClassName = secondPartClassName; + } + + public boolean isMultipartSignedEntity() { + return multipartSignedEntity; + } + + public void setMultipartSignedEntity(boolean multipartSignedEntity) { + this.multipartSignedEntity = multipartSignedEntity; + } + + public boolean isSignedEntityReceived() { + return signedEntityReceived; + } + + public void setSignedEntityReceived(boolean signedEntityReceived) { + this.signedEntityReceived = signedEntityReceived; + } +} diff --git a/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/Request.java b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/Request.java new file mode 100644 index 0000000..8b89a3b --- /dev/null +++ b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/Request.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it.transport; + +import java.security.cert.Certificate; +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.component.as2.api.AS2Charset; +import org.apache.camel.component.as2.api.AS2EncryptionAlgorithm; +import org.apache.camel.component.as2.api.AS2MediaType; +import org.apache.camel.component.as2.api.AS2MessageStructure; +import org.apache.camel.component.as2.api.AS2SignatureAlgorithm; +import org.apache.camel.quarkus.component.as2.it.As2CertificateHelper; +import org.apache.http.entity.ContentType; + +public class Request { + + private AS2MessageStructure messageStructure; + private String messageStructureKey; + private ContentType contentType; + private String contentTypeKey; + private Map<String, Object> headers = new HashMap<>(); + private String ediMessage; + private AS2EncryptionAlgorithm encryptionAlgorithm; + private AS2SignatureAlgorithm signingAlgorithm; + + public Request() { + } + + public Request(String ediMessage) { + this.ediMessage = ediMessage; + } + + public AS2MessageStructure getMessageStructure() { + return messageStructure; + } + + public void setMessageStructure(AS2MessageStructure messageStructure) { + this.messageStructure = messageStructure; + } + + public Map<String, Object> getHeaders() { + return headers; + } + + public void addField(String key, Object value) { + this.headers.put(key, value); + } + + public void setHeaders(Map<String, Object> headers) { + this.headers = headers; + } + + public String getMessageStructureKey() { + return messageStructureKey; + } + + public void setMessageStructureKey(String messageStructureKey) { + this.messageStructureKey = messageStructureKey; + } + + public ContentType getContentType() { + return contentType; + } + + public void setContentType(ContentType contentType) { + this.contentType = contentType; + } + + public String getContentTypeKey() { + return contentTypeKey; + } + + public void setContentTypeKey(String contentTypeKey) { + this.contentTypeKey = contentTypeKey; + } + + public String getEdiMessage() { + return ediMessage; + } + + public Request withEdiMessage(String ediMessage) { + this.ediMessage = ediMessage; + return this; + } + + public Request withHeaders(Map<String, Object> headers) { + this.headers = headers; + for (Map.Entry<String, Object> entry : headers.entrySet()) { + if (entry.getValue() instanceof AS2MessageStructure) { + setMessageStructure((AS2MessageStructure) entry.getValue()); + setMessageStructureKey(entry.getKey()); + } + } + return this; + } + + public Map<String, Object> collectHeaders() { + Map<String, Object> retVal = new HashMap<>(headers); + if (getMessageStructure() != null) { + retVal.put(getMessageStructureKey(), getMessageStructure()); + } + retVal.put("CamelAS2.ediMessageContentType", + org.apache.http.entity.ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII)); + if (getEncryptionAlgorithm() != null) { + retVal.put("CamelAS2.encryptingCertificateChain", As2CertificateHelper.getCertList()); + retVal.put("CamelAS2.encryptingAlgorithm", getEncryptionAlgorithm()); + } + if (getSigningAlgorithm() != null) { + // parameter type is java.security.cert.Certificate[] + retVal.put("CamelAS2.signingCertificateChain", As2CertificateHelper.getCertList().toArray(new Certificate[0])); + // parameter type is java.security.PrivateKey + retVal.put("CamelAS2.signingPrivateKey", As2CertificateHelper.getSigningKP().getPrivate()); + // parameter type is org.apache.camel.component.as2.api.AS2SignatureAlgorithm + retVal.put("CamelAS2.signingAlgorithm", getSigningAlgorithm()); + } + return retVal; + } + + public AS2EncryptionAlgorithm getEncryptionAlgorithm() { + return encryptionAlgorithm; + } + + public Request withEncryptionAlgorithm(AS2EncryptionAlgorithm encryptionAlgorithm) { + this.encryptionAlgorithm = encryptionAlgorithm; + return this; + } + + public AS2SignatureAlgorithm getSigningAlgorithm() { + return signingAlgorithm; + } + + public Request withSigningAlgorithm(AS2SignatureAlgorithm signingAlgorithm) { + this.signingAlgorithm = signingAlgorithm; + return this; + } +} diff --git a/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/ServerResult.java b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/ServerResult.java new file mode 100644 index 0000000..bfc79cf --- /dev/null +++ b/integration-tests/as2/src/main/java/org/apache/camel/quarkus/component/as2/it/transport/ServerResult.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it.transport; + +public class ServerResult { + + String result; + String requestClass; + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getRequestClass() { + return requestClass; + } + + public void setRequestClass(String requestClass) { + this.requestClass = requestClass; + } +} diff --git a/integration-tests/as2/src/main/resources/application.properties b/integration-tests/as2/src/main/resources/application.properties new file mode 100644 index 0000000..8136208 --- /dev/null +++ b/integration-tests/as2/src/main/resources/application.properties @@ -0,0 +1,18 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +quarkus.ssl.native=true diff --git a/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Helper.java b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Helper.java new file mode 100644 index 0000000..d4b0123 --- /dev/null +++ b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Helper.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.camel.component.as2.api.AS2Charset; +import org.apache.camel.component.as2.api.AS2EncryptionAlgorithm; +import org.apache.camel.component.as2.api.AS2MediaType; +import org.apache.camel.component.as2.api.AS2MessageStructure; +import org.apache.camel.component.as2.api.AS2SignatureAlgorithm; +import org.apache.camel.quarkus.component.as2.it.transport.Request; +import org.apache.http.entity.ContentType; + +public class As2Helper { + + public static final String AS2_VERSION = "1.1"; + public static final String REQUEST_URI = "/"; + public static final String SUBJECT = "Test Case"; + public static final String AS2_NAME = "878051556"; + public static final String FROM = "m...@example.org"; + public static final String[] SIGNED_RECEIPT_MIC_ALGORITHMS = new String[] { "sha1", "md5" }; + public static final String DISPOSITION_NOTIFICATION_TO = FROM; + public static final String EDI_MESSAGE = "UNB+UNOA:1+005435656:1+006415160:1+060515:1434+00000000000778'\n" + + "UNH+00000000000117+INVOIC:D:97B:UN'\n" + + "BGM+380+342459+9'\n" + + "DTM+3:20060515:102'\n" + + "RFF+ON:521052'\n" + + "NAD+BY+792820524::16++CUMMINS MID-RANGE ENGINE PLANT'\n" + + "NAD+SE+005435656::16++GENERAL WIDGET COMPANY'\n" + + "CUX+1:USD'\n" + + "LIN+1++157870:IN'\n" + + "IMD+F++:::WIDGET'\n" + + "QTY+47:1020:EA'\n" + + "ALI+US'\n" + + "MOA+203:1202.58'\n" + + "PRI+INV:1.179'\n" + + "LIN+2++157871:IN'\n" + + "IMD+F++:::DIFFERENT WIDGET'\n" + + "QTY+47:20:EA'\n" + + "ALI+JP'\n" + + "MOA+203:410'\n" + + "PRI+INV:20.5'\n" + + "UNS+S'\n" + + "MOA+39:2137.58'\n" + + "ALC+C+ABG'\n" + + "MOA+8:525'\n" + + "UNT+23+00000000000117'\n" + + "UNZ+1+00000000000778'"; + + private static final String EDI_MESSAGE_CONTENT_TRANSFER_ENCODING = "7bit"; + + private As2Helper() { + } + + public static Request createPlainRequest() { + final Map<String, Object> headers = createBaseHeaders(AS2MessageStructure.PLAIN); + + return new Request() + .withHeaders(headers) + .withEdiMessage(EDI_MESSAGE); + } + + public static Request createEncryptedRequest() { + final Map<String, Object> headers = createBaseHeaders(AS2MessageStructure.ENCRYPTED); + + return new Request() + .withHeaders(headers) + .withEdiMessage(EDI_MESSAGE) + .withEncryptionAlgorithm(AS2EncryptionAlgorithm.AES128_CBC); + } + + public static Request createMultipartSignedRequest() { + final Map<String, Object> headers = createBaseHeaders(AS2MessageStructure.SIGNED); + // parameter type is String[] + headers.put("CamelAS2.signedReceiptMicAlgorithms", SIGNED_RECEIPT_MIC_ALGORITHMS); + + return new Request() + .withHeaders(headers) + .withEdiMessage(EDI_MESSAGE) + .withSigningAlgorithm(AS2SignatureAlgorithm.SHA512WITHRSA); + } + + private static Map<String, Object> createBaseHeaders(AS2MessageStructure plain) { + 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", plain); + // 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 String + headers.put("CamelAS2.dispositionNotificationTo", DISPOSITION_NOTIFICATION_TO); + return headers; + } + +} diff --git a/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2IT.java b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2IT.java new file mode 100644 index 0000000..1896dda --- /dev/null +++ b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2IT.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it; + +import io.quarkus.test.junit.NativeImageTest; + +@NativeImageTest +class As2IT extends As2Test { + +} diff --git a/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Receiver.java b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Receiver.java new file mode 100644 index 0000000..6b288bb --- /dev/null +++ b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Receiver.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.camel.component.as2.api.AS2ServerConnection; +import org.apache.camel.component.as2.api.AS2SignatureAlgorithm; +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.bc.BcX509ExtensionUtils; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; + +public class As2Receiver { + private static final String SERVER_FQDN = "server.example.com"; + private static final String ORIGIN_SERVER_NAME = "AS2ClientManagerIntegrationTest Server"; + private static AS2ServerConnection serverConnection; + private static KeyPair serverSigningKP; + private static List<X509Certificate> serverCertList; + private static RequestHandler receiverHandler; + // certificate serial number seed. + private static int serialNo = 1; + + private As2Receiver() { + } + + public static RequestHandler startReceiver(int port) throws Exception { + if (receiverHandler == null) { + setupServerKeysAndCertificates(); + receiverHandler = receiveTestMessages(port); + } + return receiverHandler; + } + + private static void setupServerKeysAndCertificates() throws Exception { + Security.addProvider(new BouncyCastleProvider()); + + // + // set up our certificates + // + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC"); + + kpg.initialize(1024, new SecureRandom()); + + String issueDN = "O=Earth2 Software, C=E2"; + KeyPair issueKP = kpg.generateKeyPair(); + X509Certificate issueCert = makeCertificate( + issueKP, issueDN, issueKP, issueDN); + + // + // certificate we sign against + // + String signingDN = "CN=Sheldon, E=t...@gmail.com, O=Earth2 Software, C=E2"; + serverSigningKP = kpg.generateKeyPair(); + X509Certificate signingCert = makeCertificate( + serverSigningKP, signingDN, issueKP, issueDN); + + serverCertList = new ArrayList<>(); + + serverCertList.add(signingCert); + serverCertList.add(issueCert); + } + + private static RequestHandler receiveTestMessages(int port) throws IOException { + serverConnection = new AS2ServerConnection(As2Helper.AS2_VERSION, ORIGIN_SERVER_NAME, + SERVER_FQDN, port, AS2SignatureAlgorithm.SHA256WITHRSA, + serverCertList.toArray(new Certificate[0]), serverSigningKP.getPrivate(), serverSigningKP.getPrivate()); + + RequestHandler handler = new RequestHandler(); + serverConnection.listen("/", handler); + + return handler; + } + + /** + * create a basic X509 certificate from the given keys + */ + public static X509Certificate makeCertificate(KeyPair subKP, String subDN, KeyPair issKP, String issDN) + throws GeneralSecurityException, IOException, OperatorCreationException { + PublicKey subPub = subKP.getPublic(); + PrivateKey issPriv = issKP.getPrivate(); + PublicKey issPub = issKP.getPublic(); + + X509v3CertificateBuilder v3CertGen = new JcaX509v3CertificateBuilder(new X500Name(issDN), + BigInteger.valueOf(serialNo++), new Date(System.currentTimeMillis()), + new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)), new X500Name(subDN), subPub); + + v3CertGen.addExtension(Extension.subjectKeyIdentifier, false, createSubjectKeyId(subPub)); + + v3CertGen.addExtension(Extension.authorityKeyIdentifier, false, createAuthorityKeyId(issPub)); + + return new JcaX509CertificateConverter().setProvider("BC").getCertificate( + v3CertGen.build(new JcaContentSignerBuilder("MD5withRSA").setProvider("BC").build(issPriv))); + } + + public static AuthorityKeyIdentifier createAuthorityKeyId(PublicKey pub) throws IOException { + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pub.getEncoded()); + + BcX509ExtensionUtils utils = new BcX509ExtensionUtils(); + return utils.createAuthorityKeyIdentifier(info); + } + + public static SubjectKeyIdentifier createSubjectKeyId(PublicKey pub) throws IOException { + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pub.getEncoded()); + + return new BcX509ExtensionUtils().createSubjectKeyIdentifier(info); + } + + public static class RequestHandler implements HttpRequestHandler { + + private HttpRequest request; + private HttpResponse response; + + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + this.request = request; + this.response = response; + } + + public HttpRequest getRequest() { + return request; + } + + public HttpResponse getResponse() { + return response; + } + } +} diff --git a/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Sender.java b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Sender.java new file mode 100644 index 0000000..e8d2d9e --- /dev/null +++ b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Sender.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it; + +import java.io.IOException; + +import org.apache.camel.component.as2.api.AS2Charset; +import org.apache.camel.component.as2.api.AS2ClientConnection; +import org.apache.camel.component.as2.api.AS2ClientManager; +import org.apache.camel.component.as2.api.AS2MediaType; +import org.apache.camel.component.as2.api.AS2MessageStructure; +import org.apache.http.HttpException; +import org.apache.http.entity.ContentType; + +public class As2Sender { + + private static final String TARGET_HOST = "localhost"; + private static final String USER_AGENT = "Camel AS2 Endpoint"; + private static final String CLIENT_FQDN = "example.org"; + + private As2Sender() { + } + + public static As2SenderClient createClient(int port) throws IOException { + AS2ClientConnection clientConnection = new AS2ClientConnection(As2Helper.AS2_VERSION, USER_AGENT, CLIENT_FQDN, + TARGET_HOST, port); + AS2ClientManager clientManager = new AS2ClientManager(clientConnection); + + return ediMessage -> clientManager.send(ediMessage, As2Helper.REQUEST_URI, As2Helper.SUBJECT, As2Helper.FROM, + As2Helper.AS2_NAME, + As2Helper.AS2_NAME, AS2MessageStructure.PLAIN, + ContentType.create(AS2MediaType.APPLICATION_EDIFACT, AS2Charset.US_ASCII), null, null, null, null, + null, As2Helper.DISPOSITION_NOTIFICATION_TO, As2Helper.SIGNED_RECEIPT_MIC_ALGORITHMS, null, null); + } + + public interface As2SenderClient { + + void sendMessage(String ediMessage) throws HttpException; + } +} diff --git a/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Test.java b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Test.java new file mode 100644 index 0000000..d58986c --- /dev/null +++ b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2Test.java @@ -0,0 +1,127 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.RestAssured; +import org.apache.camel.component.as2.api.entity.AS2MessageDispositionNotificationEntity; +import org.apache.camel.quarkus.component.as2.it.transport.ClientResult; +import org.apache.camel.quarkus.component.as2.it.transport.Request; +import org.apache.camel.quarkus.component.as2.it.transport.ServerResult; +import org.apache.http.message.BasicHttpEntityEnclosingRequest; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@QuarkusTestResource(As2TestResource.class) +@QuarkusTest +public class As2Test { + private static final Logger LOG = LoggerFactory.getLogger(As2Test.class); + + @Test + public void serverPlainTest() throws Exception { + + //prepare component by sending empty request with no wait + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future<Boolean> initResult = executor.submit( + () -> RestAssured.given().get("/as2/serverInit").then().statusCode(200).extract().as(Boolean.class)); + + //give some time for server component to be created + await().atMost(5L, TimeUnit.SECONDS).untilAsserted(() -> { + assertTrue(initResult.get()); + }); + + //execute component server to wait for the result + Future<ServerResult> futureResult = executor.submit( + () -> RestAssured.given().get("/as2/server").then().statusCode(200).extract().as(ServerResult.class)); + + //create client for sending message to server + As2Sender.As2SenderClient client = As2Sender + .createClient(Integer.parseInt(System.getProperty(As2Resource.SERVER_PORT_PARAMETER))); + + //send message to server + client.sendMessage(As2Helper.EDI_MESSAGE); + + //wait for the result from the server + await().atMost(10L, TimeUnit.SECONDS).untilAsserted(() -> { + ServerResult result = futureResult.get(); + + assertEquals(As2Helper.EDI_MESSAGE.replaceAll("[\n\r]", ""), result.getResult().replaceAll("[\n\r]", ""), + "Unexpected content for enveloped mime part"); + + assertEquals(BasicHttpEntityEnclosingRequest.class.getSimpleName(), result.getRequestClass(), + "Request does not contain entity"); + }); + } + + @Test + public void clientPlainTest() throws Exception { + clientTest(As2Helper.createPlainRequest()); + } + + @Test + public void clientEncryptionTest() throws Exception { + clientTest(As2Helper.createEncryptedRequest()); + } + + @Test + public void clientMultipartSignedTest() throws Exception { + ClientResult clientResult = clientTest(As2Helper.createMultipartSignedRequest()); + + Assertions.assertTrue(clientResult.isSignedEntityReceived(), "Signature Entity"); + } + + private ClientResult clientTest(Request request) throws Exception { + + //start server (not component) + As2Receiver.RequestHandler requestHandler = As2Receiver + .startReceiver(Integer.parseInt(System.getProperty(As2Resource.CLIENT_PORT_PARAMETER))); + + //send message by component (as client) + ClientResult clientResult = RestAssured.given() // + .contentType(io.restassured.http.ContentType.JSON) + .body(request) + .post("/as2/client") // + .then() + .statusCode(200) + .extract().body().as(ClientResult.class); + + //assert result + assertNotNull(clientResult, "Response entity"); + assertEquals(2, clientResult.getPartsCount(), "Unexpected number of body parts in report"); + assertEquals(AS2MessageDispositionNotificationEntity.class.getSimpleName(), clientResult.getSecondPartClassName(), + "Unexpected type of As2Entity"); + + //assert that receiver was really used + assertNotNull(requestHandler.getRequest(), "Request"); + assertNotNull(requestHandler.getResponse(), "Response"); + + return clientResult; + } +} diff --git a/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2TestResource.java b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2TestResource.java new file mode 100644 index 0000000..59a2f01 --- /dev/null +++ b/integration-tests/as2/src/test/java/org/apache/camel/quarkus/component/as2/it/As2TestResource.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.quarkus.component.as2.it; + +import java.util.Map; +import java.util.Objects; + +import io.quarkus.test.common.QuarkusTestResourceLifecycleManager; +import org.apache.camel.quarkus.test.AvailablePortFinder; + +public class As2TestResource implements QuarkusTestResourceLifecycleManager { + @Override + public Map<String, String> start() { + return AvailablePortFinder.reserveNetworkPorts(Objects::toString, As2Resource.CLIENT_PORT_PARAMETER, + As2Resource.SERVER_PORT_PARAMETER); + } + + @Override + public void stop() { + } +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index 588d462..b235131 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -67,6 +67,7 @@ <module>activemq</module> <module>amqp</module> <module>arangodb</module> + <module>as2</module> <module>avro</module> <module>aws</module> <module>aws2</module> diff --git a/pom.xml b/pom.xml index 1c23dde..3260bc6 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,7 @@ <awssdk1.version>1.11.714</awssdk1.version> <awssdk1-swf-libs.version>1.11.22</awssdk1-swf-libs.version> <awssdk2.version>2.14.3</awssdk2.version> + <bouncycastle.version>1.66</bouncycastle.version> <camel.version>3.5.0-SNAPSHOT</camel.version> <commons-beanutils.version>1.9.4</commons-beanutils.version><!-- keep in sync with Camel --> <commons-cli.version>1.4</commons-cli.version><!-- keep in sync with Quarkus, via quarkus-bootstrap-core --> diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml index 2e8333b..dc7ec44 100644 --- a/poms/bom/pom.xml +++ b/poms/bom/pom.xml @@ -141,6 +141,11 @@ </dependency> <dependency> <groupId>org.apache.camel</groupId> + <artifactId>camel-as2</artifactId> + <version>${camel.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> <artifactId>camel-asterisk</artifactId> <version>${camel.version}</version> </dependency> @@ -1695,6 +1700,16 @@ </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-as2</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-as2-deployment</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-asterisk</artifactId> <version>${camel-quarkus.version}</version> </dependency> @@ -3675,6 +3690,16 @@ </dependency> <dependency> <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-support-bouncycastle</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> + <artifactId>camel-quarkus-support-bouncycastle-deployment</artifactId> + <version>${camel-quarkus.version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel.quarkus</groupId> <artifactId>camel-quarkus-support-common</artifactId> <version>${camel-quarkus.version}</version> </dependency> @@ -4431,6 +4456,16 @@ <version>${ahc.version}</version> </dependency> <dependency> + <artifactId>bcpkix-jdk15on</artifactId> + <groupId>org.bouncycastle</groupId> + <version>${bouncycastle.version}</version> + </dependency> + <dependency> + <artifactId>bcprov-jdk15on</artifactId> + <groupId>org.bouncycastle</groupId> + <version>${bouncycastle.version}</version> + </dependency> + <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy</artifactId> <version>${groovy.version}</version> diff --git a/tooling/scripts/test-categories.yaml b/tooling/scripts/test-categories.yaml index 5c800ad..b148895 100644 --- a/tooling/scripts/test-categories.yaml +++ b/tooling/scripts/test-categories.yaml @@ -95,6 +95,7 @@ misc: - qute - stream - tika + - as2 networking2-dataformats: - git - mail