This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/main by this push:
new 64d0ee1a8c feat: Add mina-sftp integration tests & native support
64d0ee1a8c is described below
commit 64d0ee1a8c48d54ddbe8b05e5ccb5954f6ee9bf5
Author: Gaƫlle Fournier <[email protected]>
AuthorDate: Wed Mar 18 08:07:42 2026 +0100
feat: Add mina-sftp integration tests & native support
Closes #8333
* chore: create integration tests support sftp module
* feat: Add basic operations jvm tests for mina-sftp
* feat: First native mina-sft with iso test from ftp component
* test: Add more test use case on mina-sftp
* Add cipher, compression and secure authentications tests for mina-sftp
* Add more complex use cases tests for mina-sftp
* Add certificate authentifaction options for mina-sftp
* chore: Add script to regenerate certificates in mina-sftp integration
tests
---
.../modules/ROOT/examples/components/mina-sftp.yml | 6 +-
.../ROOT/pages/reference/extensions/ftp.adoc | 10 +
.../ROOT/pages/reference/extensions/mina-sftp.adoc | 24 +-
.../mina/sftp/deployment/MinaSftpProcessor.java | 46 ---
extensions-jvm/pom.xml | 1 -
.../ftp/runtime/src/main/doc/limitations.adoc | 4 +
.../mina-sftp/deployment/pom.xml | 18 +-
.../mina/sftp/deployment/MinaSftpProcessor.java | 58 +++
{extensions-jvm => extensions}/mina-sftp/pom.xml | 2 +-
.../mina-sftp/runtime/pom.xml | 33 +-
.../runtime/src/main/doc/limitations.adoc | 4 +
.../graal/SftpFileSystemProviderSubstitution.java | 21 +-
.../main/resources/META-INF/quarkus-extension.yaml | 1 -
extensions/pom.xml | 1 +
.../component/mina/sftp/it/MinaSftpResource.java | 50 ---
integration-tests-jvm/pom.xml | 1 -
integration-tests-support/pom.xml | 1 +
.../sftp}/pom.xml | 49 ++-
.../test/support/sftp}/SftpTestResource.java | 5 +-
integration-tests/ftp/pom.xml | 5 +
.../camel/quarkus/component/sftp/it/SftpTest.java | 1 +
.../mina-sftp/pom.xml | 62 +++
.../component/mina/sftp/it/MinaSftpResource.java | 412 ++++++++++++++++++++
.../quarkus/component/mina/sftp/it/MinaSftpIT.java | 17 +-
.../component/mina/sftp/it/MinaSftpTest.java | 417 +++++++++++++++++++++
.../src/test/resources/generate-certificates.sh | 66 ++++
.../src/test/resources/test-key-rsa-cert.pub | 1 +
.../mina-sftp/src/test/resources/test-key-rsa.key | 27 ++
integration-tests/pom.xml | 1 +
pom.xml | 1 +
poms/bom-test/pom.xml | 5 +
poms/bom/pom.xml | 5 +
poms/bom/src/main/generated/flattened-full-pom.xml | 5 +
poms/build-parent/pom.xml | 5 +
tooling/scripts/test-categories.yaml | 1 +
35 files changed, 1193 insertions(+), 173 deletions(-)
diff --git a/docs/modules/ROOT/examples/components/mina-sftp.yml
b/docs/modules/ROOT/examples/components/mina-sftp.yml
index aaac7da03d..f09de7b9e0 100644
--- a/docs/modules/ROOT/examples/components/mina-sftp.yml
+++ b/docs/modules/ROOT/examples/components/mina-sftp.yml
@@ -2,11 +2,11 @@
# This file was generated by
camel-quarkus-maven-plugin:update-extension-doc-page
cqArtifactId: camel-quarkus-mina-sftp
cqArtifactIdBase: mina-sftp
-cqNativeSupported: false
-cqStatus: Preview
+cqNativeSupported: true
+cqStatus: Stable
cqDeprecated: false
cqJvmSince: 3.33.0
-cqNativeSince: n/a
+cqNativeSince: 3.33.0
cqCamelPartName: mina-sftp
cqCamelPartTitle: MINA SFTP
cqCamelPartDescription: Upload and download files to/from SFTP servers using
Apache MINA SSHD.
diff --git a/docs/modules/ROOT/pages/reference/extensions/ftp.adoc
b/docs/modules/ROOT/pages/reference/extensions/ftp.adoc
index 4d556b4855..d6b336c9ac 100644
--- a/docs/modules/ROOT/pages/reference/extensions/ftp.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/ftp.adoc
@@ -46,3 +46,13 @@ Or add the coordinates to your existing project:
ifeval::[{doc-show-user-guide-link} == true]
Check the xref:user-guide/index.adoc[User guide] for more information about
writing Camel Quarkus applications.
endif::[]
+
+[id="extensions-ftp-camel-quarkus-limitations"]
+== Camel Quarkus limitations
+
+
+[id="extensions-ftp-limitations-incompatibility-with-camel-quarkus-mina-sftp-extension"]
+=== Incompatibility with camel-quarkus-mina-sftp extension
+
+The `camel-quarkus-mina-sftp` and `camel-quarkus-ftp` extensions cannot be
used together in the same application. If you have both extension dependencies
on the classpath, you are likely to encounter problems at build time when
compiling your application.
+
diff --git a/docs/modules/ROOT/pages/reference/extensions/mina-sftp.adoc
b/docs/modules/ROOT/pages/reference/extensions/mina-sftp.adoc
index 294fae03e5..2ec9707a72 100644
--- a/docs/modules/ROOT/pages/reference/extensions/mina-sftp.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/mina-sftp.adoc
@@ -4,17 +4,17 @@
= MINA SFTP
:linkattrs:
:cq-artifact-id: camel-quarkus-mina-sftp
-:cq-native-supported: false
-:cq-status: Preview
-:cq-status-deprecation: Preview
+:cq-native-supported: true
+:cq-status: Stable
+:cq-status-deprecation: Stable
:cq-description: Upload and download files to/from SFTP servers using Apache
MINA SSHD.
:cq-deprecated: false
:cq-jvm-since: 3.33.0
-:cq-native-since: n/a
+:cq-native-since: 3.33.0
ifeval::[{doc-show-badges} == true]
[.badges]
-[.badge-key]##JVM since##[.badge-supported]##3.33.0##
[.badge-key]##Native##[.badge-unsupported]##unsupported##
+[.badge-key]##JVM since##[.badge-supported]##3.33.0## [.badge-key]##Native
since##[.badge-supported]##3.33.0##
endif::[]
Upload and download files to/from SFTP servers using Apache MINA SSHD.
@@ -29,6 +29,10 @@ Please refer to the above link for usage and configuration
details.
[id="extensions-mina-sftp-maven-coordinates"]
== Maven coordinates
+https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-mina-sftp[Create
a new project with this extension on {link-quarkus-code-generator},
window="_blank"]
+
+Or add the coordinates to your existing project:
+
[source,xml]
----
<dependency>
@@ -39,3 +43,13 @@ Please refer to the above link for usage and configuration
details.
ifeval::[{doc-show-user-guide-link} == true]
Check the xref:user-guide/index.adoc[User guide] for more information about
writing Camel Quarkus applications.
endif::[]
+
+[id="extensions-mina-sftp-camel-quarkus-limitations"]
+== Camel Quarkus limitations
+
+
+[id="extensions-mina-sftp-limitations-incompatibility-with-camel-quarkus-ftp-extension"]
+=== Incompatibility with camel-quarkus-ftp extension
+
+The `camel-quarkus-mina-sftp` and `camel-quarkus-ftp` extensions cannot be
used together in the same application. If you have both extension dependencies
on the classpath, you are likely to encounter problems at build time when
compiling your application.
+
diff --git
a/extensions-jvm/mina-sftp/deployment/src/main/java/org/apache/camel/quarkus/component/mina/sftp/deployment/MinaSftpProcessor.java
b/extensions-jvm/mina-sftp/deployment/src/main/java/org/apache/camel/quarkus/component/mina/sftp/deployment/MinaSftpProcessor.java
deleted file mode 100644
index 08b0079e2f..0000000000
---
a/extensions-jvm/mina-sftp/deployment/src/main/java/org/apache/camel/quarkus/component/mina/sftp/deployment/MinaSftpProcessor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.mina.sftp.deployment;
-
-import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.annotations.ExecutionTime;
-import io.quarkus.deployment.annotations.Record;
-import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
-import org.apache.camel.quarkus.core.JvmOnlyRecorder;
-import org.jboss.logging.Logger;
-
-class MinaSftpProcessor {
-
- private static final Logger LOG =
Logger.getLogger(MinaSftpProcessor.class);
- private static final String FEATURE = "camel-mina-sftp";
-
- @BuildStep
- FeatureBuildItem feature() {
- return new FeatureBuildItem(FEATURE);
- }
-
- /**
- * Remove this once this extension starts supporting the native mode.
- */
- @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
- @Record(value = ExecutionTime.RUNTIME_INIT)
- void warnJvmInNative(JvmOnlyRecorder recorder) {
- JvmOnlyRecorder.warnJvmInNative(LOG, FEATURE); // warn at build time
- recorder.warnJvmInNative(FEATURE); // warn at runtime
- }
-}
diff --git a/extensions-jvm/pom.xml b/extensions-jvm/pom.xml
index c57002cfa9..0523e32134 100644
--- a/extensions-jvm/pom.xml
+++ b/extensions-jvm/pom.xml
@@ -78,7 +78,6 @@
<module>jsonapi</module>
<module>ldif</module>
<module>lucene</module>
- <module>mina-sftp</module>
<module>mvel</module>
<module>opensearch</module>
<module>pqc</module>
diff --git a/extensions/ftp/runtime/src/main/doc/limitations.adoc
b/extensions/ftp/runtime/src/main/doc/limitations.adoc
new file mode 100644
index 0000000000..ca2a8b63b5
--- /dev/null
+++ b/extensions/ftp/runtime/src/main/doc/limitations.adoc
@@ -0,0 +1,4 @@
+
+=== Incompatibility with camel-quarkus-mina-sftp extension
+
+The `camel-quarkus-mina-sftp` and `camel-quarkus-ftp` extensions cannot be
used together in the same application. If you have both extension dependencies
on the classpath, you are likely to encounter problems at build time when
compiling your application.
\ No newline at end of file
diff --git a/extensions-jvm/mina-sftp/deployment/pom.xml
b/extensions/mina-sftp/deployment/pom.xml
similarity index 77%
copy from extensions-jvm/mina-sftp/deployment/pom.xml
copy to extensions/mina-sftp/deployment/pom.xml
index 275918b14f..1cb5f60fcd 100644
--- a/extensions-jvm/mina-sftp/deployment/pom.xml
+++ b/extensions/mina-sftp/deployment/pom.xml
@@ -18,8 +18,8 @@
-->
<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">
+ 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>
@@ -40,6 +40,18 @@
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mina-sftp</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ssh-deployment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-support-bouncycastle-deployment</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkiverse.jsch</groupId>
+ <artifactId>quarkus-jsch-deployment</artifactId>
+ </dependency>
</dependencies>
<build>
@@ -60,4 +72,4 @@
</plugins>
</build>
-</project>
+</project>
\ No newline at end of file
diff --git
a/extensions/mina-sftp/deployment/src/main/java/org/apache/camel/quarkus/component/mina/sftp/deployment/MinaSftpProcessor.java
b/extensions/mina-sftp/deployment/src/main/java/org/apache/camel/quarkus/component/mina/sftp/deployment/MinaSftpProcessor.java
new file mode 100644
index 0000000000..4100ceba33
--- /dev/null
+++
b/extensions/mina-sftp/deployment/src/main/java/org/apache/camel/quarkus/component/mina/sftp/deployment/MinaSftpProcessor.java
@@ -0,0 +1,58 @@
+/*
+ * 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.mina.sftp.deployment;
+
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import
io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
+import org.apache.camel.quarkus.core.deployment.spi.CamelServiceFilter;
+import
org.apache.camel.quarkus.core.deployment.spi.CamelServiceFilterBuildItem;
+
+class MinaSftpProcessor {
+
+ private static final String FEATURE = "camel-mina-sftp";
+
+ @BuildStep
+ FeatureBuildItem feature() {
+ return new FeatureBuildItem(FEATURE);
+ }
+
+ @BuildStep
+ void filterFtpComponents(BuildProducer<CamelServiceFilterBuildItem>
serviceFilter) {
+ // camel-mina-sftp depends on camel-ftp only for shared base classes
(RemoteFileEndpoint, etc.)
+ serviceFilter.produce(new
CamelServiceFilterBuildItem(CamelServiceFilter.forComponent("ftp")));
+ serviceFilter.produce(new
CamelServiceFilterBuildItem(CamelServiceFilter.forComponent("ftps")));
+ serviceFilter.produce(new
CamelServiceFilterBuildItem(CamelServiceFilter.forComponent("sftp")));
+ }
+
+ @BuildStep
+ void
runtimeInitializedClasses(BuildProducer<RuntimeInitializedClassBuildItem>
runtimeInitializedClass) {
+ // FTP/FTPS/SFTP endpoint classes are still on the classpath (from
camel-ftp)
+ runtimeInitializedClass
+ .produce(new
RuntimeInitializedClassBuildItem("org.apache.camel.component.file.remote.FtpEndpoint"));
+ runtimeInitializedClass
+ .produce(new
RuntimeInitializedClassBuildItem("org.apache.camel.component.file.remote.FtpsEndpoint"));
+ runtimeInitializedClass
+ .produce(new
RuntimeInitializedClassBuildItem("org.apache.camel.component.file.remote.SftpEndpoint"));
+
+ runtimeInitializedClass
+ .produce(
+ new
RuntimeInitializedClassBuildItem("org.apache.camel.component.file.remote.mina.MinaSftpOperations"));
+ }
+
+}
diff --git a/extensions-jvm/mina-sftp/pom.xml b/extensions/mina-sftp/pom.xml
similarity index 96%
rename from extensions-jvm/mina-sftp/pom.xml
rename to extensions/mina-sftp/pom.xml
index 6ce08d438b..db94cf85e7 100644
--- a/extensions-jvm/mina-sftp/pom.xml
+++ b/extensions/mina-sftp/pom.xml
@@ -23,7 +23,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-extensions-jvm</artifactId>
+ <artifactId>camel-quarkus-extensions</artifactId>
<version>3.33.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
diff --git a/extensions-jvm/mina-sftp/runtime/pom.xml
b/extensions/mina-sftp/runtime/pom.xml
similarity index 73%
rename from extensions-jvm/mina-sftp/runtime/pom.xml
rename to extensions/mina-sftp/runtime/pom.xml
index 85e049d904..93e3be8b2c 100644
--- a/extensions-jvm/mina-sftp/runtime/pom.xml
+++ b/extensions/mina-sftp/runtime/pom.xml
@@ -18,8 +18,8 @@
-->
<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">
+ 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>
@@ -34,6 +34,7 @@
<properties>
<camel.quarkus.jvmSince>3.33.0</camel.quarkus.jvmSince>
+ <camel.quarkus.nativeSince>3.33.0</camel.quarkus.nativeSince>
</properties>
<dependencies>
@@ -45,6 +46,32 @@
<groupId>org.apache.camel</groupId>
<artifactId>camel-mina-sftp</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-ssh</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-support-bouncycastle</artifactId>
+ </dependency>
+ <!-- Use quarkus-jsch for proper GraalVM configuration -->
+ <dependency>
+ <groupId>io.quarkiverse.jsch</groupId>
+ <artifactId>quarkus-jsch</artifactId>
+ </dependency>
+
+ <!-- commons-net is excluded by camel-mina-sftp from camel-ftp, but
needed for native image build
+ to allow GraalVM to analyze FTP/FTPS endpoint classes. Clean
after https://issues.apache.org/jira/browse/CAMEL-23164 -->
+ <dependency>
+ <groupId>commons-net</groupId>
+ <artifactId>commons-net</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.graalvm.sdk</groupId>
+ <artifactId>nativeimage</artifactId>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
<build>
@@ -97,4 +124,4 @@
</build>
</profile>
</profiles>
-</project>
+</project>
\ No newline at end of file
diff --git a/extensions/mina-sftp/runtime/src/main/doc/limitations.adoc
b/extensions/mina-sftp/runtime/src/main/doc/limitations.adoc
new file mode 100644
index 0000000000..07fc43baa3
--- /dev/null
+++ b/extensions/mina-sftp/runtime/src/main/doc/limitations.adoc
@@ -0,0 +1,4 @@
+
+=== Incompatibility with camel-quarkus-ftp extension
+
+The `camel-quarkus-mina-sftp` and `camel-quarkus-ftp` extensions cannot be
used together in the same application. If you have both extension dependencies
on the classpath, you are likely to encounter problems at build time when
compiling your application.
\ No newline at end of file
diff --git
a/integration-tests-jvm/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
b/extensions/mina-sftp/runtime/src/main/java/org/apache/camel/quarkus/component/mina/sftp/graal/SftpFileSystemProviderSubstitution.java
similarity index 65%
copy from
integration-tests-jvm/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
copy to
extensions/mina-sftp/runtime/src/main/java/org/apache/camel/quarkus/component/mina/sftp/graal/SftpFileSystemProviderSubstitution.java
index 5817d488f3..e6a7eb1317 100644
---
a/integration-tests-jvm/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
+++
b/extensions/mina-sftp/runtime/src/main/java/org/apache/camel/quarkus/component/mina/sftp/graal/SftpFileSystemProviderSubstitution.java
@@ -14,21 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.quarkus.component.mina.sftp.it;
+package org.apache.camel.quarkus.component.mina.sftp.graal;
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
-import org.junit.jupiter.api.Test;
-
-@QuarkusTest
-class MinaSftpTest {
-
- @Test
- void loadComponentMinaSftp() {
- /* A simple autogenerated test */
- RestAssured.get("/mina-sftp/load/component/mina-sftp")
- .then()
- .statusCode(200);
- }
+import com.oracle.svm.core.annotate.Delete;
+import com.oracle.svm.core.annotate.TargetClass;
+@TargetClass(className =
"org.apache.sshd.sftp.client.fs.SftpFileSystemProvider")
+@Delete
+final class SftpFileSystemProviderSubstitution {
}
diff --git
a/extensions-jvm/mina-sftp/runtime/src/main/resources/META-INF/quarkus-extension.yaml
b/extensions/mina-sftp/runtime/src/main/resources/META-INF/quarkus-extension.yaml
similarity index 98%
rename from
extensions-jvm/mina-sftp/runtime/src/main/resources/META-INF/quarkus-extension.yaml
rename to
extensions/mina-sftp/runtime/src/main/resources/META-INF/quarkus-extension.yaml
index 67be1b66eb..b76ff5c17a 100644
---
a/extensions-jvm/mina-sftp/runtime/src/main/resources/META-INF/quarkus-extension.yaml
+++
b/extensions/mina-sftp/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -26,7 +26,6 @@ description: "Upload and download files to/from SFTP servers
using Apache MINA S
metadata:
icon-url:
"https://raw.githubusercontent.com/apache/camel-website/main/antora-ui-camel/src/img/logo-d.svg"
sponsor: "Apache Software Foundation"
- unlisted: true
guide:
"https://camel.apache.org/camel-quarkus/latest/reference/extensions/mina-sftp.html"
categories:
- "integration"
diff --git a/extensions/pom.xml b/extensions/pom.xml
index f3cbaa1c50..3ec25806a7 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -204,6 +204,7 @@
<module>microprofile-health</module>
<module>milo</module>
<module>milvus</module>
+ <module>mina-sftp</module>
<module>minio</module>
<module>mllp</module>
<module>mock</module>
diff --git
a/integration-tests-jvm/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpResource.java
b/integration-tests-jvm/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpResource.java
deleted file mode 100644
index 5a0bac2a6b..0000000000
---
a/integration-tests-jvm/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpResource.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.mina.sftp.it;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.inject.Inject;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-import org.apache.camel.CamelContext;
-import org.jboss.logging.Logger;
-
-@Path("/mina-sftp")
-@ApplicationScoped
-public class MinaSftpResource {
-
- private static final Logger LOG = Logger.getLogger(MinaSftpResource.class);
-
- private static final String COMPONENT_MINA_SFTP = "mina-sftp";
- @Inject
- CamelContext context;
-
- @Path("/load/component/mina-sftp")
- @GET
- @Produces(MediaType.TEXT_PLAIN)
- public Response loadComponentMinaSftp() throws Exception {
- /* This is an autogenerated test */
- if (context.getComponent(COMPONENT_MINA_SFTP) != null) {
- return Response.ok().build();
- }
- LOG.warnf("Could not load [%s] from the Camel context",
COMPONENT_MINA_SFTP);
- return Response.status(500, COMPONENT_MINA_SFTP + " could not be
loaded from the Camel context").build();
- }
-}
diff --git a/integration-tests-jvm/pom.xml b/integration-tests-jvm/pom.xml
index 29bc8fba07..f2e71fefdf 100644
--- a/integration-tests-jvm/pom.xml
+++ b/integration-tests-jvm/pom.xml
@@ -79,7 +79,6 @@
<module>ldif</module>
<module>lucene</module>
<module>main-devmode</module>
- <module>mina-sftp</module>
<module>mvel</module>
<module>opensearch</module>
<module>pqc</module>
diff --git a/integration-tests-support/pom.xml
b/integration-tests-support/pom.xml
index 0491554d94..73e17f02bd 100644
--- a/integration-tests-support/pom.xml
+++ b/integration-tests-support/pom.xml
@@ -63,6 +63,7 @@
<module>messaging</module>
<module>mongodb</module>
<module>process-executor-support</module>
+ <module>sftp</module>
<module>splunk</module>
<module>test-support</module>
<module>wiremock</module>
diff --git a/extensions-jvm/mina-sftp/deployment/pom.xml
b/integration-tests-support/sftp/pom.xml
similarity index 50%
rename from extensions-jvm/mina-sftp/deployment/pom.xml
rename to integration-tests-support/sftp/pom.xml
index 275918b14f..6bec636d22 100644
--- a/extensions-jvm/mina-sftp/deployment/pom.xml
+++ b/integration-tests-support/sftp/pom.xml
@@ -17,47 +17,42 @@
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">
+<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-mina-sftp-parent</artifactId>
+ <artifactId>camel-quarkus-integration-tests-support</artifactId>
<version>3.33.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
- <artifactId>camel-quarkus-mina-sftp-deployment</artifactId>
- <name>Camel Quarkus :: MINA SFTP :: Deployment</name>
+ <artifactId>camel-quarkus-integration-tests-support-sftp</artifactId>
+
+ <name>Camel Quarkus :: Integration Tests :: Support :: SFTP</name>
+ <description>Common SFTP test infrastructure</description>
<dependencies>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-core-deployment</artifactId>
+ <artifactId>camel-quarkus-integration-test-support</artifactId>
</dependency>
<dependency>
- <groupId>org.apache.camel.quarkus</groupId>
- <artifactId>camel-quarkus-mina-sftp</artifactId>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-sftp</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-scp</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-test-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</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/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTestResource.java
b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpTestResource.java
similarity index 95%
rename from
integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTestResource.java
rename to
integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpTestResource.java
index e10a13888b..1a1994d1c6 100644
---
a/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTestResource.java
+++
b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpTestResource.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.quarkus.component.sftp.it;
+package org.apache.camel.quarkus.test.support.sftp;
import java.io.File;
import java.nio.charset.StandardCharsets;
@@ -28,7 +28,6 @@ import java.util.stream.Stream;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.apache.camel.quarkus.test.AvailablePortFinder;
-import org.apache.camel.util.CollectionHelper;
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.scp.server.ScpCommandFactory;
@@ -73,7 +72,7 @@ public class SftpTestResource implements
QuarkusTestResourceLifecycleManager {
sshServer.setFileSystemFactory(factory);
sshServer.start();
- return CollectionHelper.mapOf("camel.sftp.test-port",
Integer.toString(port));
+ return Collections.singletonMap("camel.sftp.test-port",
Integer.toString(port));
} catch (Exception e) {
throw new RuntimeException(e);
}
diff --git a/integration-tests/ftp/pom.xml b/integration-tests/ftp/pom.xml
index cc19e49cdd..ff0988e0d4 100644
--- a/integration-tests/ftp/pom.xml
+++ b/integration-tests/ftp/pom.xml
@@ -62,6 +62,11 @@
<artifactId>camel-quarkus-integration-test-support</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-integration-tests-support-sftp</artifactId>
+ <scope>test</scope>
+ </dependency>
<!-- test dependencies - (s)ftp -->
<dependency>
diff --git
a/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java
b/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java
index 65f0294095..58e2e8aede 100644
---
a/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java
+++
b/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java
@@ -23,6 +23,7 @@ import io.restassured.http.ContentType;
import io.smallrye.certs.Format;
import io.smallrye.certs.junit5.Certificate;
import org.apache.camel.quarkus.test.support.certificate.TestCertificates;
+import org.apache.camel.quarkus.test.support.sftp.SftpTestResource;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
diff --git a/integration-tests-jvm/mina-sftp/pom.xml
b/integration-tests/mina-sftp/pom.xml
similarity index 58%
rename from integration-tests-jvm/mina-sftp/pom.xml
rename to integration-tests/mina-sftp/pom.xml
index d1011db104..d957e51ff9 100644
--- a/integration-tests-jvm/mina-sftp/pom.xml
+++ b/integration-tests/mina-sftp/pom.xml
@@ -37,6 +37,10 @@
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-mina-sftp</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-log</artifactId>
+ </dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
@@ -53,9 +57,54 @@
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
+
+ <!-- test dependencies - camel-quarkus -->
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-integration-test-support</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-integration-tests-support-sftp</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-integration-tests-support-certificate-generator</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<profiles>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <properties>
+ <quarkus.native.enabled>true</quarkus.native.enabled>
+ </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>
<profile>
<id>virtualDependencies</id>
<activation>
@@ -78,6 +127,19 @@
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-log-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
</profile>
</profiles>
diff --git
a/integration-tests/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpResource.java
b/integration-tests/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpResource.java
new file mode 100644
index 0000000000..e0f84b8853
--- /dev/null
+++
b/integration-tests/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpResource.java
@@ -0,0 +1,412 @@
+/*
+ * 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.mina.sftp.it;
+
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.apache.camel.CamelContext;
+import org.apache.camel.ConsumerTemplate;
+import org.apache.camel.Exchange;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.file.remote.mina.MinaSftpConfiguration;
+import org.apache.camel.component.file.remote.mina.MinaSftpEndpoint;
+import org.jboss.logging.Logger;
+
+@Path("/mina-sftp")
+@ApplicationScoped
+public class MinaSftpResource {
+
+ private static final Logger LOG = Logger.getLogger(MinaSftpResource.class);
+
+ private static final String COMPONENT_MINA_SFTP = "mina-sftp";
+ private static final long TIMEOUT_MS = 1000;
+
+ @Inject
+ CamelContext context;
+
+ @Inject
+ ProducerTemplate producerTemplate;
+
+ @Inject
+ ConsumerTemplate consumerTemplate;
+
+ @Path("/load/component/mina-sftp")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response loadComponentMinaSftp() throws Exception {
+ /* This is an autogenerated test */
+ if (context.getComponent(COMPONENT_MINA_SFTP) != null) {
+ return Response.ok().build();
+ }
+ LOG.warnf("Could not load [%s] from the Camel context",
COMPONENT_MINA_SFTP);
+ return Response.status(500, COMPONENT_MINA_SFTP + " could not be
loaded from the Camel context").build();
+ }
+
+ @Path("/get/{fileName: .+}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFile(@PathParam("fileName") String fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFile(@PathParam("fileName") String fileName, String
fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin",
fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/append/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response appendToFile(@PathParam("fileName") String fileName,
String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&fileExist=Append",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .ok()
+ .build();
+ }
+
+ @Path("/consumeWithNoop/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String consumeFileWithNoop(@PathParam("fileName") String fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&localWorkDirectory=target&fileName="
+ + fileName + "&noop=true",
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/consumeWithMove/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String consumeFileWithMove(@PathParam("fileName") String fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&localWorkDirectory=target&fileName="
+ + fileName + "&move=${file:name}.done",
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/consumeWithDelete/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String consumeFileWithDelete(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&localWorkDirectory=target&fileName="
+ + fileName + "&delete=true",
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/delete/{fileName: .+}")
+ @DELETE
+ public void deleteFile(@PathParam("fileName") String fileName) {
+ consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&delete=true&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/moveToDoneFile/{fileName}")
+ @PUT
+ public void moveToDoneFile(@PathParam("fileName") String fileName) {
+ consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&move=${headers.CamelFileName}.done&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/privateKey/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithPrivateKey(@PathParam("fileName") String
fileName, String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=target/certs/ftp.key",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/privateKey/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithPrivateKey(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=target/certs/ftp.key&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/privateKeyEncrypted/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithEncryptedPrivateKey(@PathParam("fileName")
String fileName, String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=target/certs/ftp-encrypted.key&privateKeyPassphrase=password",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/privateKeyEncrypted/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithEncryptedPrivateKey(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=target/certs/ftp-encrypted.key&privateKeyPassphrase=password&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/certificate/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithCertificate(@PathParam("fileName") String
fileName, String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=src/test/resources/test-key-rsa.key&certFile=src/test/resources/test-key-rsa-cert.pub",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/certificate/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithCertificate(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=src/test/resources/test-key-rsa.key&certFile=src/test/resources/test-key-rsa-cert.pub&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/certificateUri/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithCertificateUri(@PathParam("fileName") String
fileName, String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:src/test/resources/test-key-rsa.key&certUri=file:src/test/resources/test-key-rsa-cert.pub",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/certificateUri/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithCertificateUri(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:src/test/resources/test-key-rsa.key&certUri=file:src/test/resources/test-key-rsa-cert.pub&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/certificateBytes/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithCertificateBytes(@PathParam("fileName")
String fileName, String fileContent)
+ throws Exception {
+ byte[] certBytes =
Files.readAllBytes(Paths.get("src/test/resources/test-key-rsa-cert.pub"));
+ byte[] keyBytes =
Files.readAllBytes(Paths.get("src/test/resources/test-key-rsa.key"));
+
+ String uri =
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp";
+ MinaSftpEndpoint endpoint = context.getEndpoint(uri,
MinaSftpEndpoint.class);
+ MinaSftpConfiguration config = (MinaSftpConfiguration)
endpoint.getConfiguration();
+ config.setCertBytes(certBytes);
+ config.setPrivateKey(keyBytes);
+
+ producerTemplate.sendBodyAndHeader(endpoint, fileContent,
Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/certificateBytes/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithCertificateBytes(@PathParam("fileName") String
fileName) throws Exception {
+ byte[] certBytes =
Files.readAllBytes(Paths.get("src/test/resources/test-key-rsa-cert.pub"));
+ byte[] keyBytes =
Files.readAllBytes(Paths.get("src/test/resources/test-key-rsa.key"));
+
+ String uri =
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?localWorkDirectory=target&fileName="
+ + fileName;
+ MinaSftpEndpoint endpoint = context.getEndpoint(uri,
MinaSftpEndpoint.class);
+ MinaSftpConfiguration config = (MinaSftpConfiguration)
endpoint.getConfiguration();
+ config.setCertBytes(certBytes);
+ config.setPrivateKey(keyBytes);
+
+ return consumerTemplate.receiveBody(endpoint, TIMEOUT_MS,
String.class);
+ }
+
+ @Path("/compression/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithCompression(@PathParam("fileName") String
fileName, String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&compression=6",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/compression/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithCompression(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&compression=6&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/streamDownload/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithStreamDownload(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&streamDownload=true&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/customCipher/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithCustomCipher(@PathParam("fileName") String
fileName, String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&preferredAuthentications=password&ciphers=aes256-ctr,aes128-ctr",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/customCipher/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithCustomCipher(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&preferredAuthentications=password&ciphers=aes256-ctr,aes128-ctr&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/cipherGcm/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithGcmCipher(@PathParam("fileName") String
fileName, String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&preferredAuthentications=password&[email protected],[email protected]",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/cipherGcm/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithGcmCipher(@PathParam("fileName") String fileName)
{
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&preferredAuthentications=password&[email protected],[email protected]&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+ @Path("/cipherChaCha20/create/{fileName}")
+ @POST
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response createFileWithChaCha20Cipher(@PathParam("fileName") String
fileName, String fileContent)
+ throws Exception {
+ producerTemplate.sendBodyAndHeader(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&preferredAuthentications=password&[email protected]",
+ fileContent,
+ Exchange.FILE_NAME, fileName);
+ return Response
+ .created(new URI("https://camel.apache.org/"))
+ .build();
+ }
+
+ @Path("/cipherChaCha20/get/{fileName}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getFileWithChaCha20Cipher(@PathParam("fileName") String
fileName) {
+ return consumerTemplate.receiveBody(
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&preferredAuthentications=password&[email protected]&localWorkDirectory=target&fileName="
+ + fileName,
+ TIMEOUT_MS,
+ String.class);
+ }
+
+}
diff --git
a/integration-tests-jvm/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
b/integration-tests/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpIT.java
similarity index 70%
rename from
integration-tests-jvm/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
rename to
integration-tests/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpIT.java
index 5817d488f3..291334d954 100644
---
a/integration-tests-jvm/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
+++
b/integration-tests/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpIT.java
@@ -16,19 +16,8 @@
*/
package org.apache.camel.quarkus.component.mina.sftp.it;
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
-import org.junit.jupiter.api.Test;
-
-@QuarkusTest
-class MinaSftpTest {
-
- @Test
- void loadComponentMinaSftp() {
- /* A simple autogenerated test */
- RestAssured.get("/mina-sftp/load/component/mina-sftp")
- .then()
- .statusCode(200);
- }
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+@QuarkusIntegrationTest
+class MinaSftpIT extends MinaSftpTest {
}
diff --git
a/integration-tests/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
b/integration-tests/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
new file mode 100644
index 0000000000..34882dcfa9
--- /dev/null
+++
b/integration-tests/mina-sftp/src/test/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpTest.java
@@ -0,0 +1,417 @@
+/*
+ * 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.mina.sftp.it;
+
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import io.smallrye.certs.Format;
+import io.smallrye.certs.junit5.Certificate;
+import org.apache.camel.quarkus.test.support.certificate.TestCertificates;
+import org.apache.camel.quarkus.test.support.sftp.SftpTestResource;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+
+@TestCertificates(certificates = {
+ @Certificate(name = "ftp", formats = {
+ Format.PEM }, password = ""),
+ @Certificate(name = "ftp-encrypted", formats = {
+ Format.PEM }, password = "password"),
+ @Certificate(name = "ftp", formats = {
+ Format.PKCS12 }, password = "password") })
+@QuarkusTest
+@QuarkusTestResource(SftpTestResource.class)
+class MinaSftpTest {
+
+ @Test
+ void loadComponentMinaSftp() {
+ /* A simple autogenerated test */
+ RestAssured.get("/mina-sftp/load/component/mina-sftp")
+ .then()
+ .statusCode(200);
+ }
+
+ @Test
+ void testMinaSftpComponent() {
+
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Hello Camel Quarkus MINA SFTP")
+ .post("/mina-sftp/create/hello.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/get/hello.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Hello Camel Quarkus MINA SFTP"));
+
+ RestAssured.put("/mina-sftp/moveToDoneFile/hello.txt")
+ .then()
+ .statusCode(204);
+
+ RestAssured.get("/mina-sftp/get/hello.txt")
+ .then()
+ .statusCode(204);
+
+ RestAssured.get("/mina-sftp/get/hello.txt.done")
+ .then()
+ .statusCode(200)
+ .body(is("Hello Camel Quarkus MINA SFTP"));
+
+ RestAssured.delete("/mina-sftp/delete/hello.txt.done")
+ .then()
+ .statusCode(204);
+
+ RestAssured.get("/mina-sftp/get/hello.txt.done")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testPrivateKeyAuthentication() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Private Key Test")
+ .post("/mina-sftp/privateKey/create/privatekey.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/privateKey/get/privatekey.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Private Key Test"));
+
+ RestAssured.delete("/mina-sftp/delete/privatekey.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testEncryptedPrivateKeyAuthentication() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Encrypted Private Key Test")
+ .post("/mina-sftp/privateKeyEncrypted/create/encrypted.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/privateKeyEncrypted/get/encrypted.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Encrypted Private Key Test"));
+
+ RestAssured.delete("/mina-sftp/delete/encrypted.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testCompression() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Compressed content test - this is a longer text to
demonstrate compression")
+ .post("/mina-sftp/compression/create/compressed.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/compression/get/compressed.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Compressed content test - this is a longer text to
demonstrate compression"));
+
+ RestAssured.delete("/mina-sftp/delete/compressed.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testStreamDownload() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Stream download test content")
+ .post("/mina-sftp/create/stream.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/streamDownload/get/stream.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Stream download test content"));
+
+ RestAssured.delete("/mina-sftp/delete/stream.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testCustomCipherConfiguration() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Custom cipher test - AES256-CTR")
+ .post("/mina-sftp/customCipher/create/cipher.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/customCipher/get/cipher.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Custom cipher test - AES256-CTR"));
+
+ RestAssured.delete("/mina-sftp/delete/cipher.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testGcmCipher() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("GCM cipher test - Authenticated Encryption")
+ .post("/mina-sftp/cipherGcm/create/gcm.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/cipherGcm/get/gcm.txt")
+ .then()
+ .statusCode(200)
+ .body(is("GCM cipher test - Authenticated Encryption"));
+
+ RestAssured.delete("/mina-sftp/delete/gcm.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testChaCha20Cipher() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("ChaCha20 cipher test - Modern high-performance cipher")
+ .post("/mina-sftp/cipherChaCha20/create/chacha20.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/cipherChaCha20/get/chacha20.txt")
+ .then()
+ .statusCode(200)
+ .body(is("ChaCha20 cipher test - Modern high-performance
cipher"));
+
+ RestAssured.delete("/mina-sftp/delete/chacha20.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testBasicConsumerRoute() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Consumer route test content")
+ .post("/mina-sftp/create/consumer-test.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/consumeWithNoop/consumer-test.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Consumer route test content"));
+
+ RestAssured.get("/mina-sftp/get/consumer-test.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Consumer route test content"));
+
+ RestAssured.delete("/mina-sftp/delete/consumer-test.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testConsumerWithMoveAfterProcessing() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Move after processing test")
+ .post("/mina-sftp/create/move-test.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/consumeWithMove/move-test.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Move after processing test"));
+
+ RestAssured.get("/mina-sftp/get/move-test.txt")
+ .then()
+ .statusCode(204);
+
+ RestAssured.get("/mina-sftp/get/move-test.txt.done")
+ .then()
+ .statusCode(200)
+ .body(is("Move after processing test"));
+
+ RestAssured.delete("/mina-sftp/delete/move-test.txt.done")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testConsumerWithDeleteAfterProcessing() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Delete after processing test")
+ .post("/mina-sftp/create/delete-test.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/consumeWithDelete/delete-test.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Delete after processing test"));
+
+ RestAssured.get("/mina-sftp/get/delete-test.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testConsumerToProducer() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Integration route test content")
+ .post("/mina-sftp/create/integration-source.txt")
+ .then()
+ .statusCode(201);
+
+ String content =
RestAssured.get("/mina-sftp/consumeWithDelete/integration-source.txt")
+ .then()
+ .statusCode(200)
+ .extract()
+ .asString();
+
+ RestAssured.get("/mina-sftp/get/integration-source.txt")
+ .then()
+ .statusCode(204);
+
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body(content)
+ .post("/mina-sftp/create/integration-destination.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/get/integration-destination.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Integration route test content"));
+
+ RestAssured.delete("/mina-sftp/delete/integration-destination.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testFileExistAppend() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("First line\n")
+ .post("/mina-sftp/create/append-test.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Second line\n")
+ .post("/mina-sftp/append/append-test.txt")
+ .then()
+ .statusCode(200);
+
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Third line\n")
+ .post("/mina-sftp/append/append-test.txt")
+ .then()
+ .statusCode(200);
+
+ RestAssured.get("/mina-sftp/get/append-test.txt")
+ .then()
+ .statusCode(200)
+ .body(is("First line\nSecond line\nThird line\n"));
+
+ RestAssured.delete("/mina-sftp/delete/append-test.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testCertificateAuthentication() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Certificate authentication test")
+ .post("/mina-sftp/certificate/create/certificate-test.txt")
+ .then()
+ .statusCode(201);
+
+ RestAssured.get("/mina-sftp/certificate/get/certificate-test.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Certificate authentication test"));
+
+ RestAssured.delete("/mina-sftp/delete/certificate-test.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testCertificateAuthenticationWithUri() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Certificate URI authentication test")
+
.post("/mina-sftp/certificateUri/create/certificate-uri-test.txt")
+ .then()
+ .statusCode(201);
+
+
RestAssured.get("/mina-sftp/certificateUri/get/certificate-uri-test.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Certificate URI authentication test"));
+
+ RestAssured.delete("/mina-sftp/delete/certificate-uri-test.txt")
+ .then()
+ .statusCode(204);
+ }
+
+ @Test
+ void testCertificateAuthenticationWithBytes() {
+ RestAssured.given()
+ .contentType(ContentType.TEXT)
+ .body("Certificate bytes authentication test")
+
.post("/mina-sftp/certificateBytes/create/certificate-bytes-test.txt")
+ .then()
+ .statusCode(201);
+
+
RestAssured.get("/mina-sftp/certificateBytes/get/certificate-bytes-test.txt")
+ .then()
+ .statusCode(200)
+ .body(is("Certificate bytes authentication test"));
+
+ RestAssured.delete("/mina-sftp/delete/certificate-bytes-test.txt")
+ .then()
+ .statusCode(204);
+ }
+
+}
diff --git
a/integration-tests/mina-sftp/src/test/resources/generate-certificates.sh
b/integration-tests/mina-sftp/src/test/resources/generate-certificates.sh
new file mode 100755
index 0000000000..8780f21483
--- /dev/null
+++ b/integration-tests/mina-sftp/src/test/resources/generate-certificates.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+#
+# 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.
+#
+
+#
+# Script to generate OpenSSH certificate files for SFTP integration tests
+#
+# This script creates:
+# - test-key-rsa.key: RSA private key (2048 bits)
+# - test-key-rsa-cert.pub: OpenSSH certificate signed by a temporary CA
+#
+# The certificate is valid for 52 weeks and can be used for testing
+# certificate-based authentication with the mina-sftp component.
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+cd "$SCRIPT_DIR"
+
+echo "==================================================================="
+echo "Generating OpenSSH Certificates for MINA SFTP Integration Tests"
+echo "==================================================================="
+echo ""
+
+echo "Cleaning up existing files..."
+rm -f ca-key ca-key.pub test-key-rsa.key test-key-rsa.key.pub
test-key-rsa-cert.pub
+echo "Cleaned up existing files"
+
+echo "Generating temporary CA key pair..."
+ssh-keygen -t rsa -b 2048 -f ca-key -N "" -C "test-ca" > /dev/null 2>&1
+echo "Created ca-key and ca-key.pub"
+
+echo "Generating user RSA key pair..."
+ssh-keygen -t rsa -b 2048 -f test-key-rsa.key -N "" -C "test-rsa@test" >
/dev/null 2>&1
+echo "Created test-key-rsa.key and test-key-rsa.key.pub"
+
+echo "Signing public key with CA to create certificate..."
+ssh-keygen -s ca-key \
+ -I "test-user" \
+ -n testuser \
+ -V +520w \
+ test-key-rsa.key.pub > /dev/null 2>&1
+echo "Created test-key-rsa.key-cert.pub"
+
+echo "Renaming certificate to test-key-rsa-cert.pub..."
+mv test-key-rsa.key-cert.pub test-key-rsa-cert.pub
+echo "Renamed to test-key-rsa-cert.pub"
+
+echo "Cleaning up temporary files..."
+rm -f ca-key ca-key.pub test-key-rsa.key.pub
+echo "Removed CA keys and public key"
diff --git
a/integration-tests/mina-sftp/src/test/resources/test-key-rsa-cert.pub
b/integration-tests/mina-sftp/src/test/resources/test-key-rsa-cert.pub
new file mode 100644
index 0000000000..ba21c6c28b
--- /dev/null
+++ b/integration-tests/mina-sftp/src/test/resources/test-key-rsa-cert.pub
@@ -0,0 +1 @@
[email protected]
AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgwsB0wUJYWF7WQayMI3EFz63+rzdGxxmy6QmkXXigkbcAAAADAQABAAABAQCd2V7v8ELetZfmObUn3zP28B44AhcDnOdZHErgl1fe6e2Jmnja4BhdtZAG+XZEmKwlQnWNkRJfDs1/ryfP8xthcZIlklEb/6F2D2zmot5BnY6zzL6XWPtuTny1Ym7iah6KSPv9vS9nc2wcEA9BFu+CYHHWJYskv/PE/hwebae/upKafppCWJ97+Kdkc87Whsd1y2PxhhPPCbH/lOOOmzw2qTyxpYciHsr9NaBfoHRwvTWBdWjk6pYKtw+4gmWOmyAngOh9jcXeJ5pKUhWeJh5fmMrHL/mv/0DtrGQ2fhhrYZjIbkuha5EOFqurnXHjwwBz3Ey8JOhaF9UwQlCvOOWnAAAAAAAAAAAAAAA
[...]
diff --git a/integration-tests/mina-sftp/src/test/resources/test-key-rsa.key
b/integration-tests/mina-sftp/src/test/resources/test-key-rsa.key
new file mode 100644
index 0000000000..751cc308be
--- /dev/null
+++ b/integration-tests/mina-sftp/src/test/resources/test-key-rsa.key
@@ -0,0 +1,27 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEAndle7/BC3rWX5jm1J98z9vAeOAIXA5znWRxK4JdX3untiZp42uAY
+XbWQBvl2RJisJUJ1jZESXw7Nf68nz/MbYXGSJZJRG/+hdg9s5qLeQZ2Os8y+l1j7bk58tW
+Ju4moeikj7/b0vZ3NsHBAPQRbvgmBx1iWLJL/zxP4cHm2nv7qSmn6aQlife/inZHPO1obH
+dctj8YYTzwmx/5Tjjps8Nqk8saWHIh7K/TWgX6B0cL01gXVo5OqWCrcPuIJljpsgJ4DofY
+3F3ieaSlIVniYeX5jKxy/5r/9A7axkNn4Ya2GYyG5LoWuRDharq51x48MAc9xMvCToWhfV
+MEJQrzjlpwAAA8hfVSnxX1Up8QAAAAdzc2gtcnNhAAABAQCd2V7v8ELetZfmObUn3zP28B
+44AhcDnOdZHErgl1fe6e2Jmnja4BhdtZAG+XZEmKwlQnWNkRJfDs1/ryfP8xthcZIlklEb
+/6F2D2zmot5BnY6zzL6XWPtuTny1Ym7iah6KSPv9vS9nc2wcEA9BFu+CYHHWJYskv/PE/h
+webae/upKafppCWJ97+Kdkc87Whsd1y2PxhhPPCbH/lOOOmzw2qTyxpYciHsr9NaBfoHRw
+vTWBdWjk6pYKtw+4gmWOmyAngOh9jcXeJ5pKUhWeJh5fmMrHL/mv/0DtrGQ2fhhrYZjIbk
+uha5EOFqurnXHjwwBz3Ey8JOhaF9UwQlCvOOWnAAAAAwEAAQAAAQAwsx1GwqYm5vjH53r8
+I7F5GMkB96cZDsITrJZvZ1INbLfEEfwCb0wlMTyP4kw6Sq4lyrTQ6fa0jDEbmTMbxcHnVO
+5FmDhc/ofWkFjFaW9P6CfcUillMWdVN3LjVUynnxzwBid0t/cVoDc1C0FhkA1x+IZ2jtu4
+iV5QoyOSwbsU/CMKSQ6WOeGLJ8MMgGQgyiZ4/Y6Wjmr4daRYlC+VlFWRqv9aqYvCPBVwim
+jYQ/juwHeskk9nENOLMONx4D8zSObJmdm/QMEi0FvE6hkTNPczQez8Kq0XibsOfbBm2a1E
+tfHw09buG22V1nDv3MRnIolzD/8FDXv6rwFXyNJXc0E9AAAAgG+UjO3TGmT49yoZdiKmgB
+/aYftPl+Qh1BH7ucnZ9obw5xi6Y4wm15QzTBqqXSS3Src46Dt74FIWiDN1soKQh/1P9TlF
+iWOWcqpBafIm26b8zK1X9BC1TaCNwrEgiNXbOvJh3jqYI4ZiQBDid/2nQD3S4CSRSjK7rp
+ZsGDp5ooc2AAAAgQDZvrUm8w1FRlo6d0OcYbhLQxUOg6oUaSCikXFMQqhwnyzzx0M1F1A9
+vgASJZAcng476hV+bu99EW0XB85rUwanvigO3b2VtrI9jHx8X3Vsi1XJF8tGNLDUvzWWMP
+lKtIDPwfPkBS5bV6LOUa5Fa5JTTu821FR6hMyDhOr07O9cVQAAAIEAuZTJ88ChTgdwrbWy
+F2j1ah9nXaNtnKs3LNBP90U2ueq5hQp0rHUfpl1mwGM9aFSEd2jyYq91h0oMXG/baMngS+
+OP+M0AH80xDG3X9CW3PdhGEUaqXX9vozw5OQnd6RbGxW605t39XTL630p6mAHfmauYlBDe
+GKKHquT0B+ueNgsAAAANdGVzdC1yc2FAdGVzdAECAwQFBg==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index c4d86c0d13..a796b0e57b 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -178,6 +178,7 @@
<module>microprofile-health</module>
<module>milo</module>
<module>milvus</module>
+ <module>mina-sftp</module>
<module>minio</module>
<module>mllp</module>
<module>mongodb-grouped</module>
diff --git a/pom.xml b/pom.xml
index 669a36912d..341991664d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -88,6 +88,7 @@
<commons-collections.version>${commons-collections-version}</commons-collections.version>
<commons-collections4.version>${commons-collections4-version}</commons-collections4.version>
<commons-exec.version>${commons-exec-version}</commons-exec.version>
+ <commons-net.version>${commons-net-version}</commons-net.version>
<commons-validator.version>${commons-validator-version}</commons-validator.version>
<cxf.version>4.1.5</cxf.version><!-- @sync
io.quarkiverse.cxf:quarkus-cxf-parent:${quarkiverse-cxf.version}
prop:cxf.version -->
<dfdl-scala.version>2.12.20</dfdl-scala.version>
diff --git a/poms/bom-test/pom.xml b/poms/bom-test/pom.xml
index cd9be05aa9..03a469fec4 100644
--- a/poms/bom-test/pom.xml
+++ b/poms/bom-test/pom.xml
@@ -142,6 +142,11 @@
<artifactId>camel-quarkus-integration-tests-support-azure</artifactId>
<version>${camel-quarkus.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-integration-tests-support-sftp</artifactId>
+ <version>${camel-quarkus.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-integration-tests-support-jdbc</artifactId>
diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml
index a26afc017e..899265b51e 100644
--- a/poms/bom/pom.xml
+++ b/poms/bom/pom.xml
@@ -7959,6 +7959,11 @@
<artifactId>commons-collections4</artifactId>
<version>${commons-collections4.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-net</artifactId>
+ <version>${commons-net.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-full-pom.xml
b/poms/bom/src/main/generated/flattened-full-pom.xml
index 9aee7da858..8a0584c021 100644
--- a/poms/bom/src/main/generated/flattened-full-pom.xml
+++ b/poms/bom/src/main/generated/flattened-full-pom.xml
@@ -7842,6 +7842,11 @@
<artifactId>commons-collections4</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<version>4.5.0</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <artifactId>commons-net</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ <version>3.12.0</version><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+ </dependency>
<dependency>
<groupId>org.apache.cxf</groupId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
<artifactId>cxf-rt-frontend-jaxrs</artifactId><!--
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
diff --git a/poms/build-parent/pom.xml b/poms/build-parent/pom.xml
index 304a54bbb5..0b8a366f51 100644
--- a/poms/build-parent/pom.xml
+++ b/poms/build-parent/pom.xml
@@ -44,6 +44,11 @@
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
</dependency>
+ <dependency>
+ <groupId>commons-net</groupId>
+ <artifactId>commons-net</artifactId>
+ <version>${commons-net.version}</version>
+ </dependency>
<dependency>
<groupId>org.eclipse.transformer</groupId>
<artifactId>org.eclipse.transformer</artifactId>
diff --git a/tooling/scripts/test-categories.yaml
b/tooling/scripts/test-categories.yaml
index 64dd9fb7e6..7b9c9e3045 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -171,6 +171,7 @@ group-09:
- jt400-mocked
- kafka-sasl-ssl
- kafka-ssl
+ - mina-sftp
- paho
- management
- nats