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 c4835a5881 feat: Use test containers for SFTP/Mina-sftp tests and
remove certs from the repo
c4835a5881 is described below
commit c4835a5881c5691e6c09070f971c13aa7896323f
Author: Gaƫlle Fournier <[email protected]>
AuthorDate: Mon Jun 1 14:01:06 2026 +0200
feat: Use test containers for SFTP/Mina-sftp tests and remove certs from
the repo
* remove cert files and use testcontainers
* Add RSA certificate test to mina-sftp
* ssh remove net.i2p.crypto eddsa support
Fixes #8700
---
.../component/ftp/deployment/FtpProcessor.java | 1 +
.../component/ssh/deployment/SshProcessor.java | 33 +-
extensions/ssh/runtime/pom.xml | 6 -
.../ssh/runtime/SubstituteEdDSAEngine.java | 78 -----
integration-tests-support/sftp/pom.xml | 24 +-
.../test/support/sftp/SftpCertificates.java | 337 +++++++++++++++++++++
.../support/sftp/SftpHostCertTestResource.java | 225 +++++++-------
.../test/support/sftp/SftpTestResource.java | 236 ++++++++++-----
integration-tests/ftp/pom.xml | 20 +-
.../component/sftp/it/SftpCertificateManager.java | 98 ++++++
.../quarkus/component/sftp/it/SftpResource.java | 220 +++++++-------
.../ftp/src/main/resources/application.properties | 2 -
.../main/resources/certs/generate-certificates.sh | 104 -------
.../ftp/src/main/resources/certs/host-ca.pub | 1 -
.../src/main/resources/certs/host-key-rsa-cert.pub | 1 -
.../ftp/src/main/resources/certs/host-key-rsa.key | 27 --
.../src/main/resources/certs/test-key-rsa-cert.pub | 1 -
.../ftp/src/main/resources/certs/test-key-rsa.key | 27 --
integration-tests/mina-sftp/pom.xml | 20 +-
.../mina/sftp/it/MinaSftpCertificateManager.java | 133 ++++++++
.../component/mina/sftp/it/MinaSftpResource.java | 74 ++---
.../src/main/resources/application.properties | 17 --
.../main/resources/certs/generate-certificates.sh | 66 ----
.../src/main/resources/certs/test-key-rsa-cert.pub | 1 -
.../src/main/resources/certs/test-key-rsa.key | 27 --
.../component/mina/sftp/it/MinaSftpTest.java | 1 -
.../camel/quarkus/component/ssh/it/SshRoutes.java | 8 -
27 files changed, 1058 insertions(+), 730 deletions(-)
diff --git
a/extensions/ftp/deployment/src/main/java/org/apache/camel/quarkus/component/ftp/deployment/FtpProcessor.java
b/extensions/ftp/deployment/src/main/java/org/apache/camel/quarkus/component/ftp/deployment/FtpProcessor.java
index 218c96e6f6..e1a9bd4eb1 100644
---
a/extensions/ftp/deployment/src/main/java/org/apache/camel/quarkus/component/ftp/deployment/FtpProcessor.java
+++
b/extensions/ftp/deployment/src/main/java/org/apache/camel/quarkus/component/ftp/deployment/FtpProcessor.java
@@ -27,4 +27,5 @@ class FtpProcessor {
FeatureBuildItem feature() {
return new FeatureBuildItem(FEATURE);
}
+
}
diff --git
a/extensions/ssh/deployment/src/main/java/org/apache/camel/quarkus/component/ssh/deployment/SshProcessor.java
b/extensions/ssh/deployment/src/main/java/org/apache/camel/quarkus/component/ssh/deployment/SshProcessor.java
index f02cf1266a..8395b66cc0 100644
---
a/extensions/ssh/deployment/src/main/java/org/apache/camel/quarkus/component/ssh/deployment/SshProcessor.java
+++
b/extensions/ssh/deployment/src/main/java/org/apache/camel/quarkus/component/ssh/deployment/SshProcessor.java
@@ -19,6 +19,8 @@ package org.apache.camel.quarkus.component.ssh.deployment;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.Signature;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import javax.crypto.KeyAgreement;
@@ -33,7 +35,6 @@ import
io.quarkus.deployment.builditem.nativeimage.NativeImageProxyDefinitionBui
import
io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import
io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem;
-import net.i2p.crypto.eddsa.EdDSAEngine;
import org.apache.sshd.common.channel.ChannelListener;
import org.apache.sshd.common.forward.PortForwardingEventListener;
import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
@@ -51,15 +52,29 @@ class SshProcessor {
@BuildStep
void registerForReflection(BuildProducer<ReflectiveClassBuildItem>
reflectiveClasses) {
+ // Register standard Java security and SSHD classes
+ List<Class<?>> classes = new ArrayList<>(Arrays.asList(
+ KeyPairGenerator.class,
+ KeyAgreement.class,
+ KeyFactory.class,
+ Signature.class,
+ Mac.class,
+ Nio2ServiceFactoryFactory.class));
+
+ // Conditionally register net.i2p.crypto EdDSA classes only if present
on classpath.
+ // When net.i2p.crypto:eddsa is excluded, Apache SSHD 2.15+
automatically falls back
+ // to BouncyCastle for EdDSA support (see
BouncyCastleSecurityProviderRegistrar).
+ try {
+ classes.add(Class.forName("net.i2p.crypto.eddsa.EdDSAEngine",
false,
+ Thread.currentThread().getContextClassLoader()));
+ classes.add(Class.forName("net.i2p.crypto.eddsa.KeyFactory", false,
+ Thread.currentThread().getContextClassLoader()));
+ } catch (ClassNotFoundException e) {
+ // EdDSA classes not available - BouncyCastle will handle EdDSA
instead
+ }
+
reflectiveClasses.produce(
- ReflectiveClassBuildItem.builder(KeyPairGenerator.class,
- KeyAgreement.class,
- KeyFactory.class,
- Signature.class,
- Mac.class,
- Nio2ServiceFactoryFactory.class,
- EdDSAEngine.class,
-
net.i2p.crypto.eddsa.KeyFactory.class).methods().build());
+ ReflectiveClassBuildItem.builder(classes.toArray(new
Class<?>[0])).methods().build());
}
@BuildStep
diff --git a/extensions/ssh/runtime/pom.xml b/extensions/ssh/runtime/pom.xml
index e0ea4d8ad7..5eb235d5b2 100644
--- a/extensions/ssh/runtime/pom.xml
+++ b/extensions/ssh/runtime/pom.xml
@@ -48,12 +48,6 @@
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-support-bouncycastle</artifactId>
</dependency>
- <!-- TODO: Remove this as it's an optional dependency -->
- <!-- https://github.com/apache/camel-quarkus/issues/2212 -->
- <dependency>
- <groupId>net.i2p.crypto</groupId>
- <artifactId>eddsa</artifactId>
- </dependency>
<dependency>
<groupId>org.graalvm.sdk</groupId>
<artifactId>nativeimage</artifactId>
diff --git
a/extensions/ssh/runtime/src/main/java/org/apache/camel/quarkus/component/ssh/runtime/SubstituteEdDSAEngine.java
b/extensions/ssh/runtime/src/main/java/org/apache/camel/quarkus/component/ssh/runtime/SubstituteEdDSAEngine.java
deleted file mode 100644
index 3054c049cc..0000000000
---
a/extensions/ssh/runtime/src/main/java/org/apache/camel/quarkus/component/ssh/runtime/SubstituteEdDSAEngine.java
+++ /dev/null
@@ -1,78 +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.ssh.runtime;
-
-import java.security.*;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
-
-import com.oracle.svm.core.annotate.Alias;
-import com.oracle.svm.core.annotate.Substitute;
-import com.oracle.svm.core.annotate.TargetClass;
-import net.i2p.crypto.eddsa.EdDSAEngine;
-import net.i2p.crypto.eddsa.EdDSAKey;
-import net.i2p.crypto.eddsa.EdDSAPublicKey;
-
-/**
- * We're substituting those offending methods that would require the presence
of
- * net.i2p.crypto:eddsa library which is not supported by Camel SSH component
- */
-@TargetClass(EdDSAEngine.class)
-final class SubstituteEdDSAEngine {
-
- @Alias
- private MessageDigest digest;
-
- @Alias
- private EdDSAKey key;
-
- @Alias
- private void reset() {
- }
-
- @Substitute
- protected void engineInitVerify(PublicKey publicKey) throws
InvalidKeyException {
- reset();
- if (publicKey instanceof EdDSAPublicKey) {
- key = (EdDSAPublicKey) publicKey;
-
- if (digest == null) {
- // Instantiate the digest from the key parameters
- try {
- digest =
MessageDigest.getInstance(key.getParams().getHashAlgorithm());
- } catch (NoSuchAlgorithmException e) {
- throw new InvalidKeyException(
- "cannot get required digest " +
key.getParams().getHashAlgorithm() + " for private key.");
- }
- } else if
(!key.getParams().getHashAlgorithm().equals(digest.getAlgorithm()))
- throw new InvalidKeyException("Key hash algorithm does not
match chosen digest");
- } //following line differs from the original method
- else if (publicKey.getFormat().equals("X.509")) {
- // X509Certificate will sometimes contain an X509Key rather than
the EdDSAPublicKey itself; the contained
- // key is valid but needs to be instanced as an EdDSAPublicKey
before it can be used.
- EdDSAPublicKey parsedPublicKey;
- try {
- parsedPublicKey = new EdDSAPublicKey(new
X509EncodedKeySpec(publicKey.getEncoded()));
- } catch (InvalidKeySpecException ex) {
- throw new InvalidKeyException("cannot handle X.509 EdDSA
public key: " + publicKey.getAlgorithm());
- }
- engineInitVerify(parsedPublicKey);
- } else {
- throw new InvalidKeyException("cannot identify EdDSA public key: "
+ publicKey.getClass());
- }
- }
-}
diff --git a/integration-tests-support/sftp/pom.xml
b/integration-tests-support/sftp/pom.xml
index b7c543e7e2..aed30951b9 100644
--- a/integration-tests-support/sftp/pom.xml
+++ b/integration-tests-support/sftp/pom.xml
@@ -38,12 +38,8 @@
<artifactId>camel-quarkus-integration-test-support</artifactId>
</dependency>
<dependency>
- <groupId>org.apache.sshd</groupId>
- <artifactId>sshd-sftp</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.sshd</groupId>
- <artifactId>sshd-scp</artifactId>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>testcontainers</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
@@ -53,6 +49,22 @@
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
</dependency>
+ <!-- Apache SSHD for SSH certificate generation -->
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <!-- BouncyCastle for Ed25519 key generation -->
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk18on</artifactId>
+ </dependency>
</dependencies>
</project>
diff --git
a/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpCertificates.java
b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpCertificates.java
new file mode 100644
index 0000000000..acf83bfad2
--- /dev/null
+++
b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpCertificates.java
@@ -0,0 +1,337 @@
+/*
+ * 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.test.support.sftp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.spec.ECGenParameterSpec;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Collections;
+
+import org.apache.sshd.certificate.OpenSshCertificateBuilder;
+import org.apache.sshd.common.config.keys.OpenSshCertificate;
+import
org.apache.sshd.common.config.keys.writer.openssh.OpenSSHKeyEncryptionContext;
+import
org.apache.sshd.common.config.keys.writer.openssh.OpenSSHKeyPairResourceWriter;
+import org.jboss.logging.Logger;
+
+/**
+ * Generates SSH certificates using Apache SSHD for testing purposes.
+ */
+public class SftpCertificates {
+ private static final Logger LOGGER =
Logger.getLogger(SftpCertificates.class);
+
+ private final Path sshDir;
+ private final Path userCaKeyPath;
+ private final Path userCaPubKeyPath;
+ private final Path userCaRsaKeyPath;
+ private final Path userCaRsaPubKeyPath;
+ private final Path userKeyPath;
+ private final Path userPubKeyPath;
+ private final Path userCertPath;
+ private final Path hostCaKeyPath;
+ private final Path hostCaPubKeyPath;
+ private final Path hostKeyPath;
+ private final Path hostPubKeyPath;
+ private final Path hostCertPath;
+ private final Path ftpKeyPath;
+ private final Path ftpPubKeyPath;
+ private final Path ftpEncryptedKeyPath;
+ private final Path ftpEncryptedPubKeyPath;
+ private final Path userKeyRsaPath;
+ private final Path userPubKeyRsaPath;
+ private final Path userCertRsaPath;
+
+ // In-memory key pairs
+ private KeyPair userCaKeyPair;
+ private KeyPair userCaRsaKeyPair;
+ private KeyPair userKeyPair;
+ private KeyPair hostCaKeyPair;
+ private KeyPair hostKeyPair;
+ private KeyPair ftpKeyPair;
+ private KeyPair ftpEncryptedKeyPair;
+ private KeyPair userKeyRsaPair;
+
+ private SftpCertificates(Path sshDir) {
+ this.sshDir = sshDir;
+ this.userCaKeyPath = sshDir.resolve("user_ca");
+ this.userCaPubKeyPath = sshDir.resolve("user_ca.pub");
+ this.userCaRsaKeyPath = sshDir.resolve("user_ca_rsa");
+ this.userCaRsaPubKeyPath = sshDir.resolve("user_ca_rsa.pub");
+ this.userKeyPath = sshDir.resolve("user_key");
+ this.userPubKeyPath = sshDir.resolve("user_key.pub");
+ this.userCertPath = sshDir.resolve("user_key-cert.pub");
+ this.hostCaKeyPath = sshDir.resolve("host_ca");
+ this.hostCaPubKeyPath = sshDir.resolve("host_ca.pub");
+ this.hostKeyPath = sshDir.resolve("host_key");
+ this.hostPubKeyPath = sshDir.resolve("host_key.pub");
+ this.hostCertPath = sshDir.resolve("host_key-cert.pub");
+ this.ftpKeyPath = sshDir.resolve("ftp.key");
+ this.ftpPubKeyPath = sshDir.resolve("ftp.key.pub");
+ this.ftpEncryptedKeyPath = sshDir.resolve("ftp-encrypted.key");
+ this.ftpEncryptedPubKeyPath = sshDir.resolve("ftp-encrypted.key.pub");
+ this.userKeyRsaPath = sshDir.resolve("user_key_rsa");
+ this.userPubKeyRsaPath = sshDir.resolve("user_key_rsa.pub");
+ this.userCertRsaPath = sshDir.resolve("user_key_rsa-cert.pub");
+ }
+
+ /**
+ * Generate all required SSH certificates using Apache SSHD.
+ */
+ public static SftpCertificates generate(Path sshDir) throws Exception {
+ SftpCertificates certs = new SftpCertificates(sshDir);
+ certs.generateAll();
+ return certs;
+ }
+
+ private void generateAll() throws Exception {
+ // Register BouncyCastle provider for Ed25519 support
+ java.security.Security.addProvider(new
org.bouncycastle.jce.provider.BouncyCastleProvider());
+
+ SecureRandom random = new SecureRandom();
+
+ userCaKeyPair = generateEd25519KeyPair();
+ writeKeyPair(userCaKeyPair, userCaKeyPath, userCaPubKeyPath,
"user-ca-ed25519", null);
+ LOGGER.debug("Generated Ed25519 user CA key pair");
+
+ userCaRsaKeyPair = generateRsaKeyPair(2048);
+ writeKeyPair(userCaRsaKeyPair, userCaRsaKeyPath, userCaRsaPubKeyPath,
"user-ca-rsa", null);
+ LOGGER.debug("Generated RSA user CA key pair");
+
+ userKeyPair = generateEd25519KeyPair();
+ writeKeyPair(userKeyPair, userKeyPath, userPubKeyPath,
"test-user-ed25519", null);
+ LOGGER.debug("Generated Ed25519 user key pair");
+
+ OpenSshCertificate userCert =
OpenSshCertificateBuilder.userCertificate()
+ .serial(random.nextLong() & Long.MAX_VALUE)
+ .publicKey(userKeyPair.getPublic())
+ .id("test-user-ed25519")
+ .principals(Collections.singletonList("admin"))
+ .validAfter(Instant.now().minus(Duration.ofMinutes(1)))
+ .validBefore(Instant.now().plus(Duration.ofDays(365)))
+ .sign(userCaKeyPair);
+ writeCertificate(userCert, userCertPath, "test-user-ed25519");
+ LOGGER.debug("Signed Ed25519 user certificate with Ed25519 CA");
+
+ userKeyRsaPair = generateRsaKeyPair(2048);
+ writeKeyPair(userKeyRsaPair, userKeyRsaPath, userPubKeyRsaPath,
"test-user-rsa", null);
+ LOGGER.debug("Generated RSA user key pair");
+
+ OpenSshCertificate userCertRsa =
OpenSshCertificateBuilder.userCertificate()
+ .serial(random.nextLong() & Long.MAX_VALUE)
+ .publicKey(userKeyRsaPair.getPublic())
+ .id("test-user-rsa")
+ .principals(Collections.singletonList("admin"))
+ .validAfter(Instant.now().minus(Duration.ofMinutes(1)))
+ .validBefore(Instant.now().plus(Duration.ofDays(365)))
+ .sign(userCaRsaKeyPair, "rsa-sha2-512");
+ writeCertificate(userCertRsa, userCertRsaPath, "test-user-rsa");
+ LOGGER.debug("Signed RSA user certificate with RSA CA");
+
+ hostCaKeyPair = generateEd25519KeyPair();
+ writeKeyPair(hostCaKeyPair, hostCaKeyPath, hostCaPubKeyPath,
"host-ca", null);
+ LOGGER.debug("Generated host CA key pair");
+
+ hostKeyPair = generateEd25519KeyPair();
+ writeKeyPair(hostKeyPair, hostKeyPath, hostPubKeyPath, "sftp-server",
null);
+ LOGGER.debug("Generated host key pair");
+
+ OpenSshCertificate hostCert =
OpenSshCertificateBuilder.hostCertificate()
+ .serial(random.nextLong() & Long.MAX_VALUE)
+ .publicKey(hostKeyPair.getPublic())
+ .id("sftp-server")
+ .principals(Collections.singletonList("localhost"))
+ .validAfter(Instant.now().minus(Duration.ofMinutes(1)))
+ .validBefore(Instant.now().plus(Duration.ofDays(365)))
+ .sign(hostCaKeyPair);
+ writeCertificate(hostCert, hostCertPath, "sftp-server");
+ LOGGER.debug("Signed host certificate");
+
+ ftpKeyPair = generateRsaKeyPair(2048);
+ writeKeyPair(ftpKeyPair, ftpKeyPath, ftpPubKeyPath, "ftp-test", null);
+ LOGGER.debug("Generated ftp SSH key pair");
+
+ ftpEncryptedKeyPair = generateRsaKeyPair(2048);
+ writeKeyPair(ftpEncryptedKeyPair, ftpEncryptedKeyPath,
ftpEncryptedPubKeyPath, "ftp-encrypted-test", "password");
+ LOGGER.debug("Generated ftp-encrypted SSH key pair");
+ }
+
+ /**
+ * Generate an Ed25519 key pair using BouncyCastle provider.
+ */
+ private KeyPair generateEd25519KeyPair() throws GeneralSecurityException {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("Ed25519",
"BC");
+ return generator.generateKeyPair();
+ }
+
+ /**
+ * Generate an RSA key pair with the specified key size.
+ */
+ private KeyPair generateRsaKeyPair(int keySize) throws
GeneralSecurityException {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+ generator.initialize(keySize);
+ return generator.generateKeyPair();
+ }
+
+ /**
+ * Generate an ECDSA key pair with the specified curve.
+ */
+ private KeyPair generateEcdsaKeyPair(String curve) throws
GeneralSecurityException {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+ generator.initialize(new ECGenParameterSpec(curve));
+ return generator.generateKeyPair();
+ }
+
+ /**
+ * Write a key pair to files in OpenSSH format.
+ *
+ * @param keyPair the key pair to write
+ * @param privateKeyPath path for the private key file
+ * @param publicKeyPath path for the public key file
+ * @param comment comment to add to the keys
+ * @param password password for encrypting the private key (null for
no encryption)
+ */
+ private void writeKeyPair(KeyPair keyPair, Path privateKeyPath, Path
publicKeyPath, String comment, String password)
+ throws IOException, GeneralSecurityException {
+ OpenSSHKeyPairResourceWriter writer =
OpenSSHKeyPairResourceWriter.INSTANCE;
+
+ // Prepare encryption context if password is provided
+ OpenSSHKeyEncryptionContext encryptionContext = null;
+ if (password != null && !password.isEmpty()) {
+ encryptionContext = new OpenSSHKeyEncryptionContext();
+ encryptionContext.setPassword(password);
+ encryptionContext.setCipherName("AES");
+ encryptionContext.setCipherMode("CTR");
+ encryptionContext.setCipherType("256");
+ }
+
+ // Write private key
+ try (OutputStream out = Files.newOutputStream(privateKeyPath)) {
+ writer.writePrivateKey(keyPair, comment, encryptionContext, out);
+ }
+
+ // Write public key in standard OpenSSH format
+ String publicKeyLine =
org.apache.sshd.common.config.keys.PublicKeyEntry.toString(keyPair.getPublic())
+ " " + comment
+ + "\n";
+ Files.writeString(publicKeyPath, publicKeyLine);
+ }
+
+ /**
+ * Write a certificate to file in OpenSSH format.
+ *
+ * @param certificate the certificate to write
+ * @param certPath path for the certificate file
+ * @param comment comment to add to the certificate
+ */
+ private void writeCertificate(OpenSshCertificate certificate, Path
certPath, String comment)
+ throws Exception {
+ OpenSSHKeyPairResourceWriter writer =
OpenSSHKeyPairResourceWriter.INSTANCE;
+ try (OutputStream out = Files.newOutputStream(certPath)) {
+ writer.writePublicKey(certificate, comment, out);
+ }
+ }
+
+ public Path getUserCaPubKeyPath() {
+ return userCaPubKeyPath;
+ }
+
+ public Path getUserCaRsaPubKeyPath() {
+ return userCaRsaPubKeyPath;
+ }
+
+ public Path getUserPublicKeyPath() {
+ return userPubKeyPath;
+ }
+
+ public Path getUserPrivateKeyPath() {
+ return userKeyPath;
+ }
+
+ public Path getUserCertificatePath() {
+ return userCertPath;
+ }
+
+ public Path getHostCaPubKeyPath() {
+ return hostCaPubKeyPath;
+ }
+
+ public Path getHostPublicKeyPath() {
+ return hostPubKeyPath;
+ }
+
+ public Path getHostPrivateKeyPath() {
+ return hostKeyPath;
+ }
+
+ public Path getHostCertificatePath() {
+ return hostCertPath;
+ }
+
+ public byte[] getUserCertificateBytes() throws IOException {
+ return Files.readAllBytes(userCertPath);
+ }
+
+ public byte[] getUserPrivateKeyBytes() throws IOException {
+ return Files.readAllBytes(userKeyPath);
+ }
+
+ public String getHostCaPublicKey() throws IOException {
+ return Files.readString(hostCaPubKeyPath).trim();
+ }
+
+ public Path getFtpPrivateKeyPath() {
+ return ftpKeyPath;
+ }
+
+ public Path getFtpPublicKeyPath() {
+ return ftpPubKeyPath;
+ }
+
+ public Path getFtpEncryptedPrivateKeyPath() {
+ return ftpEncryptedKeyPath;
+ }
+
+ public Path getFtpEncryptedPublicKeyPath() {
+ return ftpEncryptedPubKeyPath;
+ }
+
+ public Path getUserRsaPrivateKeyPath() {
+ return userKeyRsaPath;
+ }
+
+ public Path getUserRsaPublicKeyPath() {
+ return userPubKeyRsaPath;
+ }
+
+ public Path getUserRsaCertificatePath() {
+ return userCertRsaPath;
+ }
+
+ public byte[] getUserRsaCertificateBytes() throws IOException {
+ return Files.readAllBytes(userCertRsaPath);
+ }
+
+ public byte[] getUserRsaPrivateKeyBytes() throws IOException {
+ return Files.readAllBytes(userKeyRsaPath);
+ }
+}
diff --git
a/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpHostCertTestResource.java
b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpHostCertTestResource.java
index 1f45db0327..0c20c43805 100644
---
a/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpHostCertTestResource.java
+++
b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpHostCertTestResource.java
@@ -16,155 +16,164 @@
*/
package org.apache.camel.quarkus.test.support.sftp;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.security.KeyPair;
-import java.security.PublicKey;
-import java.util.Collections;
-import java.util.List;
+import java.util.HashMap;
import java.util.Map;
+import java.util.stream.Stream;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
-import org.apache.camel.quarkus.test.AvailablePortFinder;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.config.keys.OpenSshCertificate;
-import org.apache.sshd.common.config.keys.PublicKeyEntry;
-import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
-import org.apache.sshd.common.keyprovider.KeyPairProvider;
-import org.apache.sshd.common.signature.BuiltinSignatures;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.scp.server.ScpCommandFactory;
-import org.apache.sshd.server.SshServer;
-import org.apache.sshd.sftp.server.SftpSubsystemFactory;
+import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.MountableFile;
/**
* SFTP test resource that presents host certificates for host certificate
verification testing.
- * This is separate from SftpTestResource to avoid interfering with other
tests.
+ * Uses containerized OpenSSH server configured with host certificates.
*/
public class SftpHostCertTestResource implements
QuarkusTestResourceLifecycleManager {
private static final Logger LOGGER =
Logger.getLogger(SftpHostCertTestResource.class);
+ private static final String USERNAME = "admin";
+ private static final String PASSWORD = "admin";
+ private static final int SFTP_PORT = 2222;
- private SshServer sshServer;
- private Path sftpHome;
+ private GenericContainer<?> container;
+ private Path tempDir;
@Override
public Map<String, String> start() {
try {
- final int port = AvailablePortFinder.getNextAvailable();
+ String opensshImage =
ConfigProvider.getConfig().getValue("openssh-server.container.image",
String.class);
+
+ tempDir = Files.createTempDirectory("sftp-hostcert-config-");
+ Path sshDir = tempDir.resolve("ssh");
+ Files.createDirectories(sshDir);
+
+ SftpCertificates certificates = SftpCertificates.generate(sshDir);
+ LOGGER.info("Generated SSH certificates with host cert in: " +
sshDir);
+
+ // Create custom sshd_config that uses host certificate and trusts
user CA
+ Path sshdConfigPath = createSshdConfig(sshDir);
+
+ // Start OpenSSH container with host certificate configuration
+ container = new GenericContainer<>(opensshImage)
+ .withExposedPorts(SFTP_PORT)
+ .withEnv("PASSWORD_ACCESS", "true")
+ .withEnv("USER_NAME", USERNAME)
+ .withEnv("USER_PASSWORD", PASSWORD)
+ .withEnv("SUDO_ACCESS", "false")
+ // Copy host certificate and key
+ .withCopyFileToContainer(
+
MountableFile.forHostPath(certificates.getHostPrivateKeyPath()),
+ "/config/ssh_host_ed25519_key")
+ .withCopyFileToContainer(
+
MountableFile.forHostPath(certificates.getHostCertificatePath()),
+ "/config/ssh_host_ed25519_key-cert.pub")
+ // Copy user CA public key for user cert verification
+ .withCopyFileToContainer(
+
MountableFile.forHostPath(certificates.getUserCaPubKeyPath()),
+ "/config/user_ca.pub")
+ // Copy custom sshd_config
+ .withCopyFileToContainer(
+ MountableFile.forHostPath(sshdConfigPath),
+ "/etc/ssh/sshd_config")
+ .waitingFor(Wait.forLogMessage(".*done.*", 1));
+
+ container.start();
+
+ Map<String, String> result = new HashMap<>();
+ result.put("camel.sftp.hostcert.test-port",
container.getMappedPort(SFTP_PORT).toString());
+
+ // Set system property for JVM mode AND return in map for native
mode command-line args
+ String hostCaPubKeyPath =
certificates.getHostCaPubKeyPath().toString();
+ System.setProperty("sftp.test.host.ca.pubkey", hostCaPubKeyPath);
+ result.put("sftp.test.host.ca.pubkey", hostCaPubKeyPath);
+
+ LOGGER.infof("SFTP host cert container started on port %d",
container.getMappedPort(SFTP_PORT));
+ return result;
- sftpHome = Files.createTempDirectory("sftp-hostcert-");
- Path adminHome = sftpHome.resolve("admin");
- Files.createDirectories(adminHome);
-
- VirtualFileSystemFactory factory = new VirtualFileSystemFactory();
- factory.setUserHomeDir("admin", adminHome.toAbsolutePath());
-
- sshServer = SshServer.setUpDefaultServer();
- sshServer.setPort(port);
-
- sshServer.setKeyPairProvider(createHostCertKeyPairProvider());
-
- sshServer.setSubsystemFactories(Collections.singletonList(new
SftpSubsystemFactory()));
- sshServer.setCommandFactory(new ScpCommandFactory());
- sshServer.setPasswordAuthenticator((username, password, session)
-> true);
- sshServer.setPublickeyAuthenticator((username, key, session) ->
true);
-
- // Add certificate signature factories
- List<NamedFactory<Signature>> signatureFactories =
sshServer.getSignatureFactories();
- signatureFactories.add(BuiltinSignatures.rsa_cert);
- signatureFactories.add(BuiltinSignatures.rsaSHA256_cert);
- signatureFactories.add(BuiltinSignatures.rsaSHA512_cert);
- signatureFactories.add(BuiltinSignatures.ed25519_cert);
- sshServer.setSignatureFactories(signatureFactories);
-
- sshServer.setFileSystemFactory(factory);
- sshServer.start();
-
- LOGGER.infof("SFTP server with host certificate started on port
%d", port);
-
- return Collections.singletonMap("camel.sftp.hostcert.test-port",
Integer.toString(port));
} catch (Exception e) {
- throw new RuntimeException("Failed to start SFTP server with host
certificate", e);
+ throw new RuntimeException("Failed to start SFTP host cert
container", e);
}
}
@Override
public void stop() {
try {
- if (sshServer != null) {
- sshServer.stop();
- LOGGER.info("SFTP server with host certificate stopped");
+ if (container != null) {
+ container.stop();
+ LOGGER.info("SFTP host cert container stopped");
}
} catch (Exception e) {
- LOGGER.warn("Failed to stop SFTP server", e);
+ LOGGER.warn("Failed to stop SFTP host cert container", e);
}
try {
- if (sftpHome != null && Files.exists(sftpHome)) {
- Files.walk(sftpHome)
- .sorted((a, b) -> -a.compareTo(b))
- .forEach(path -> {
- try {
- Files.delete(path);
- } catch (Exception e) {
- LOGGER.warn("Failed to delete SFTPHome file",
e);
- }
- });
+ if (tempDir != null && Files.exists(tempDir)) {
+ try (Stream<Path> pathStream = Files.walk(tempDir)) {
+ pathStream
+ .sorted((a, b) -> -a.compareTo(b))
+ .forEach(path -> {
+ try {
+ Files.delete(path);
+ } catch (IOException e) {
+ LOGGER.warn("Failed to delete temp file: "
+ path, e);
+ }
+ });
+ }
}
} catch (Exception e) {
- LOGGER.warnf("Failed to delete sftp home: %s, %s", sftpHome, e);
+ LOGGER.warn("Failed to delete temp directory: " + tempDir, e);
}
+ }
- AvailablePortFinder.releaseReservedPorts();
+ /**
+ * Create custom sshd_config that uses host certificate and trusts user CA.
+ */
+ private Path createSshdConfig(Path sshDir) throws IOException {
+ Path sshdConfig = sshDir.resolve("sshd_config");
+ String config = String.join("\n",
+ "# Custom sshd_config for host certificate testing",
+ "Port 2222",
+ "Protocol 2",
+ "HostKey /config/ssh_host_ed25519_key",
+ "HostCertificate /config/ssh_host_ed25519_key-cert.pub",
+ "",
+ "# User certificate authentication",
+ "TrustedUserCAKeys /config/user_ca.pub",
+ "PubkeyAuthentication yes",
+ "",
+ "# Password authentication",
+ "PasswordAuthentication yes",
+ "PermitRootLogin no",
+ "",
+ "# SFTP subsystem",
+ "Subsystem sftp internal-sftp",
+ "",
+ "# Logging",
+ "SyslogFacility AUTH",
+ "LogLevel INFO",
+ "");
+
+ Files.writeString(sshdConfig, config);
+ return sshdConfig;
}
/**
- * Creates a KeyPairProvider that wraps the host private key with the
OpenSSH host certificate.
+ * Returns the CA public key in OpenSSH format for use in known_hosts
@cert-authority entries.
*/
- private static KeyPairProvider createHostCertKeyPairProvider() {
+ public static String getHostCaPublicKey() {
try {
- // Load host private key from classpath (works in both JVM and
native mode)
- ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
-
- // Write host key to temp file (FileKeyPairProvider needs a file
path)
- Path tempHostKey = Files.createTempFile("host-key-rsa", ".key");
- try (var keyStream =
classLoader.getResourceAsStream("certs/host-key-rsa.key")) {
- if (keyStream == null) {
- throw new IllegalStateException("Host key resource not
found: certs/host-key-rsa.key");
- }
- Files.write(tempHostKey, keyStream.readAllBytes());
- }
-
- FileKeyPairProvider keyProvider = new
FileKeyPairProvider(tempHostKey);
- KeyPair originalKeyPair =
keyProvider.loadKeys(null).iterator().next();
-
- // Load host certificate from classpath
- String certLine;
- try (var certStream =
classLoader.getResourceAsStream("certs/host-key-rsa-cert.pub")) {
- if (certStream == null) {
- throw new IllegalStateException("Host certificate resource
not found: certs/host-key-rsa-cert.pub");
- }
- certLine = new String(certStream.readAllBytes()).trim();
- }
-
- PublicKey certKey =
PublicKeyEntry.parsePublicKeyEntry(certLine).resolvePublicKey(null, null, null);
-
- if (!(certKey instanceof OpenSshCertificate)) {
- throw new IllegalStateException("Host certificate file does
not contain an OpenSSH certificate");
+ String path = System.getProperty("sftp.test.host.ca.pubkey");
+ if (path == null) {
+ throw new IllegalStateException("Host CA public key path not
set. Test resource not started?");
}
-
- // Create a key pair with the certificate as the public key
- KeyPair certKeyPair = new KeyPair(certKey,
originalKeyPair.getPrivate());
-
- // Clean up temp file
- Files.deleteIfExists(tempHostKey);
-
- return KeyPairProvider.wrap(certKeyPair);
-
+ return
java.nio.file.Files.readString(java.nio.file.Path.of(path)).trim();
} catch (Exception e) {
- throw new RuntimeException("Failed to load host certificate key
pair", e);
+ throw new RuntimeException("Failed to get host CA public key", e);
}
}
}
diff --git
a/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpTestResource.java
b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpTestResource.java
index 784daf8293..503f7ede44 100644
---
a/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpTestResource.java
+++
b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpTestResource.java
@@ -16,114 +16,206 @@
*/
package org.apache.camel.quarkus.test.support.sftp;
-import java.io.File;
-import java.nio.charset.StandardCharsets;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
+import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
-import org.apache.camel.quarkus.test.AvailablePortFinder;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.config.keys.OpenSshCertificate;
-import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
-import org.apache.sshd.common.signature.BuiltinSignatures;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.scp.server.ScpCommandFactory;
-import org.apache.sshd.server.SshServer;
-import org.apache.sshd.sftp.server.SftpSubsystemFactory;
+import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.logging.Logger;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.MountableFile;
+/**
+ * SFTP test resource using containerized OpenSSH server.
+ * Supports password authentication and SSH certificate-based authentication.
+ */
public class SftpTestResource implements QuarkusTestResourceLifecycleManager {
private static final Logger LOGGER =
Logger.getLogger(SftpTestResource.class);
+ private static final String USERNAME = "admin";
+ private static final String PASSWORD = "admin";
+ private static final int SFTP_PORT = 2222;
- private static final String KNOWN_HOSTS = "[localhost]:%d ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAAAgQDdfIWeSV4o68dRrKS"
- +
"zFd/Bk51E65UTmmSrmW0O1ohtzi6HzsDPjXgCtlTt3FqTcfFfI92IlTr4JWqC9UK1QT1ZTeng0MkPQmv68hDANHbt5CpETZHjW5q4OOgWhV"
- + "vj5IyOC2NZHtKlJBkdsMAa15ouOOJLzBvAvbqOR/yUROsEiQ==";
-
- private SshServer sshServer;
- private Path sftpHome;
- private Path sshHome;
+ private GenericContainer<?> container;
+ private Path tempDir;
+ private static SftpCertificates certificates;
@Override
public Map<String, String> start() {
try {
- final int port = AvailablePortFinder.getNextAvailable();
-
- sftpHome = Files.createTempDirectory("sftp-");
- sshHome = sftpHome.resolve("admin/.ssh");
+ String opensshImage =
ConfigProvider.getConfig().getValue("openssh-server.container.image",
String.class);
+
+ // Create temp directory for SSH configuration
+ tempDir = Files.createTempDirectory("sftp-config-");
+ Path sshDir = tempDir.resolve("ssh");
+ Files.createDirectories(sshDir);
+
+ certificates = SftpCertificates.generate(sshDir);
+ LOGGER.info("Generated SSH certificates in: " + sshDir);
+
+ // Create custom sshd_config for certificate authentication
+ Path sshdConfigPath = createSshdConfig(sshDir);
+
+ // Create authorized_keys file with all public keys
+ Path authorizedKeysPath = createAuthorizedKeys(sshDir);
+
+ // Create combined trusted CA file (Ed25519 + RSA CAs)
+ Path trustedCaPath = createTrustedCaKeys(sshDir);
+
+ // Start OpenSSH container
+ container = new GenericContainer<>(opensshImage)
+ .withExposedPorts(SFTP_PORT)
+ .withEnv("PASSWORD_ACCESS", "true")
+ .withEnv("USER_NAME", USERNAME)
+ .withEnv("USER_PASSWORD", PASSWORD)
+ .withEnv("SUDO_ACCESS", "false")
+ // Copy trusted user CAs (Ed25519 + RSA) for certificate
verification
+ .withCopyFileToContainer(
+ MountableFile.forHostPath(trustedCaPath),
+ "/config/.ssh/trusted_user_cas.pub")
+ // Copy authorized_keys with all public keys
+ .withCopyFileToContainer(
+ MountableFile.forHostPath(authorizedKeysPath),
+ "/config/.ssh/authorized_keys")
+ // Copy custom sshd_config
+ .withCopyFileToContainer(
+ MountableFile.forHostPath(sshdConfigPath),
+ "/etc/ssh/sshd_config")
+ .waitingFor(Wait.forLogMessage(".*done.*", 1));
+
+ container.start();
+
+ Map<String, String> result = new HashMap<>();
+ result.put("camel.sftp.test-port",
container.getMappedPort(SFTP_PORT).toString());
+
+ // Set system properties for JVM mode AND return in map for native
mode command-line args
+ String userKeyPath =
certificates.getUserPrivateKeyPath().toString();
+ String userCertPath =
certificates.getUserCertificatePath().toString();
+ String userKeyRsaPath =
certificates.getUserRsaPrivateKeyPath().toString();
+ String userCertRsaPath =
certificates.getUserRsaCertificatePath().toString();
+ String ftpKeyPath = certificates.getFtpPrivateKeyPath().toString();
+ String ftpEncryptedKeyPath =
certificates.getFtpEncryptedPrivateKeyPath().toString();
+
+ System.setProperty("sftp.test.user.key", userKeyPath);
+ System.setProperty("sftp.test.user.cert", userCertPath);
+ System.setProperty("sftp.test.user.key.rsa", userKeyRsaPath);
+ System.setProperty("sftp.test.user.cert.rsa", userCertRsaPath);
+ System.setProperty("sftp.test.ftp.key", ftpKeyPath);
+ System.setProperty("sftp.test.ftp.encrypted.key",
ftpEncryptedKeyPath);
+
+ result.put("sftp.test.user.key", userKeyPath);
+ result.put("sftp.test.user.cert", userCertPath);
+ result.put("sftp.test.user.key.rsa", userKeyRsaPath);
+ result.put("sftp.test.user.cert.rsa", userCertRsaPath);
+ result.put("sftp.test.ftp.key", ftpKeyPath);
+ result.put("sftp.test.ftp.encrypted.key", ftpEncryptedKeyPath);
+
+ LOGGER.infof("SFTP container started on port %d",
container.getMappedPort(SFTP_PORT));
+ return result;
- Files.createDirectories(sshHome);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to start SFTP container", e);
+ }
+ }
- byte[] knownHostsBytes = String.format(KNOWN_HOSTS,
port).getBytes(StandardCharsets.UTF_8);
- Files.write(sshHome.resolve(".known_hosts"), knownHostsBytes);
+ /**
+ * Create custom sshd_config that enables certificate authentication.
+ */
+ private Path createSshdConfig(Path sshDir) throws IOException {
+ Path sshdConfig = sshDir.resolve("sshd_config");
+ String config = String.join("\n",
+ "# Custom sshd_config for SFTP testing",
+ "Port 2222",
+ "Protocol 2",
+ "",
+ "# Host keys",
+ "HostKey /config/ssh_host_rsa_key",
+ "HostKey /config/ssh_host_ed25519_key",
+ "",
+ "# Authentication",
+ "PubkeyAuthentication yes",
+ "PasswordAuthentication yes",
+ "PermitRootLogin no",
+ "",
+ "# User certificate authentication - trust certificates signed
by Ed25519 and RSA CAs",
+ "TrustedUserCAKeys /config/.ssh/trusted_user_cas.pub",
+ "",
+ "# Standard public key authentication uses authorized_keys",
+ "AuthorizedKeysFile /config/.ssh/authorized_keys",
+ "",
+ "# SFTP subsystem",
+ "Subsystem sftp internal-sftp",
+ "",
+ "# Logging",
+ "SyslogFacility AUTH",
+ "LogLevel DEBUG",
+ "");
+
+ Files.writeString(sshdConfig, config);
+ LOGGER.debug("Created sshd_config: " + sshdConfig);
+ return sshdConfig;
+ }
- VirtualFileSystemFactory factory = new VirtualFileSystemFactory();
- factory.setUserHomeDir("admin",
sftpHome.resolve("admin").toAbsolutePath());
+ /**
+ * Create trusted CA keys file with both Ed25519 and RSA CAs.
+ */
+ private Path createTrustedCaKeys(Path sshDir) throws IOException {
+ Path trustedCaKeys = sshDir.resolve("trusted_user_cas.pub");
- sshServer = SshServer.setUpDefaultServer();
- sshServer.setPort(port);
- sshServer.setKeyPairProvider(new
FileKeyPairProvider(Paths.get("target/certs/ftp.key")));
- sshServer.setSubsystemFactories(Collections.singletonList(new
SftpSubsystemFactory()));
- sshServer.setCommandFactory(new ScpCommandFactory());
- sshServer.setPasswordAuthenticator((username, password, session)
-> true);
+ String cas = Files.readString(certificates.getUserCaPubKeyPath()) +
+ Files.readString(certificates.getUserCaRsaPubKeyPath());
- // Accept both regular public keys and OpenSSH certificates
- sshServer.setPublickeyAuthenticator((username, key, session) -> {
- if (key instanceof OpenSshCertificate) {
- LOGGER.debug("Accepting OpenSSH certificate authentication
for user '" + username + "'");
- } else {
- LOGGER.debug("Accepting public key authentication for user
'" + username + "'");
- }
- return true;
- });
+ Files.writeString(trustedCaKeys, cas);
+ LOGGER.debug("Created trusted_user_cas.pub with Ed25519 and RSA CAs");
+ return trustedCaKeys;
+ }
- // Add certificate signature factories to support OpenSSH
certificates
- List<NamedFactory<Signature>> signatureFactories =
sshServer.getSignatureFactories();
- signatureFactories.add(BuiltinSignatures.rsa_cert);
- signatureFactories.add(BuiltinSignatures.rsaSHA256_cert);
- signatureFactories.add(BuiltinSignatures.rsaSHA512_cert);
- signatureFactories.add(BuiltinSignatures.ed25519_cert);
- sshServer.setSignatureFactories(signatureFactories);
+ /**
+ * Create authorized_keys file with all public keys for testing.
+ */
+ private Path createAuthorizedKeys(Path sshDir) throws IOException {
+ Path authorizedKeys = sshDir.resolve("authorized_keys");
- sshServer.setFileSystemFactory(factory);
- sshServer.start();
+ String keys = Files.readString(certificates.getUserPublicKeyPath()) +
+ Files.readString(certificates.getFtpPublicKeyPath()) +
+ Files.readString(certificates.getFtpEncryptedPublicKeyPath());
- return Collections.singletonMap("camel.sftp.test-port",
Integer.toString(port));
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ Files.writeString(authorizedKeys, keys);
+ LOGGER.debug("Created authorized_keys with " + 3 + " keys");
+ return authorizedKeys;
}
@Override
public void stop() {
try {
- if (sshServer != null) {
- sshServer.stop();
+ if (container != null) {
+ container.stop();
+ LOGGER.info("SFTP container stopped");
}
} catch (Exception e) {
- LOGGER.warn("Failed to stop FTP server due to {}", e);
+ LOGGER.warn("Failed to stop SFTP container", e);
}
try {
- if (sftpHome != null) {
- try (Stream<Path> files = Files.walk(sftpHome)) {
- files
- .sorted(Comparator.reverseOrder())
- .map(Path::toFile)
- .forEach(File::delete);
+ if (tempDir != null && Files.exists(tempDir)) {
+ try (Stream<Path> pathStream = Files.walk(tempDir)) {
+ pathStream
+ .sorted((a, b) -> -a.compareTo(b))
+ .forEach(path -> {
+ try {
+ Files.delete(path);
+ } catch (IOException e) {
+ LOGGER.warn("Failed to delete temp file: "
+ path, e);
+ }
+ });
}
}
} catch (Exception e) {
- LOGGER.warn("Failed delete sftp home: {}, {}", sftpHome, e);
+ LOGGER.warn("Failed to delete temp directory: " + tempDir, e);
}
-
- AvailablePortFinder.releaseReservedPorts();
}
}
diff --git a/integration-tests/ftp/pom.xml b/integration-tests/ftp/pom.xml
index 69ccb3f440..6eb8e88cf8 100644
--- a/integration-tests/ftp/pom.xml
+++ b/integration-tests/ftp/pom.xml
@@ -43,6 +43,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-integration-tests-support-sftp</artifactId>
+ </dependency>
<!-- test dependencies -->
<dependency>
@@ -62,11 +66,6 @@
<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>
@@ -163,6 +162,17 @@
</dependency>
</dependencies>
</profile>
+ <profile>
+ <id>skip-testcontainers-tests</id>
+ <activation>
+ <property>
+ <name>skip-testcontainers-tests</name>
+ </property>
+ </activation>
+ <properties>
+ <skipTests>true</skipTests>
+ </properties>
+ </profile>
</profiles>
</project>
diff --git
a/integration-tests/ftp/src/main/java/org/apache/camel/quarkus/component/sftp/it/SftpCertificateManager.java
b/integration-tests/ftp/src/main/java/org/apache/camel/quarkus/component/sftp/it/SftpCertificateManager.java
new file mode 100644
index 0000000000..2715eb7c11
--- /dev/null
+++
b/integration-tests/ftp/src/main/java/org/apache/camel/quarkus/component/sftp/it/SftpCertificateManager.java
@@ -0,0 +1,98 @@
+/*
+ * 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.sftp.it;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import io.quarkus.runtime.Startup;
+import jakarta.enterprise.context.ApplicationScoped;
+import org.jboss.logging.Logger;
+
+/**
+ * Manages SSH certificates for SFTP integration tests.
+ * Uses certificates generated by the containerized SFTP test resource.
+ */
+@ApplicationScoped
+@Startup
+public class SftpCertificateManager {
+ private static final Logger LOGGER =
Logger.getLogger(SftpCertificateManager.class);
+
+ private Path certsDir;
+
+ public SftpCertificateManager() {
+ try {
+ initializeCertificates();
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to initialize SFTP
certificates", e);
+ }
+ }
+
+ private void initializeCertificates() throws Exception {
+ LOGGER.info("Setting up SFTP certificate files from test resource");
+
+ Path classpathCerts = Path.of("target", "classes", "certs");
+ Files.createDirectories(classpathCerts);
+
+ certsDir = classpathCerts;
+
+ String userKeyPath = System.getProperty("sftp.test.user.key");
+ String userCertPath = System.getProperty("sftp.test.user.cert");
+
+ if (userKeyPath == null || userCertPath == null) {
+ throw new IllegalStateException(
+ "Certificate paths not set. Test resource not started?
sftp.test.user.key=" + userKeyPath
+ + ", sftp.test.user.cert=" + userCertPath);
+ }
+
+ byte[] privateKeyBytes = Files.readAllBytes(Path.of(userKeyPath));
+ byte[] certificateBytes = Files.readAllBytes(Path.of(userCertPath));
+
+ Files.write(classpathCerts.resolve("test-key-rsa.key"),
privateKeyBytes);
+ Files.write(classpathCerts.resolve("test-key-rsa-cert.pub"),
certificateBytes);
+
+ LOGGER.infof("SFTP certificate files created in: %s", classpathCerts);
+ }
+
+ public Path getCertsDir() {
+ return certsDir;
+ }
+
+ public byte[] getUserPrivateKeyBytes() {
+ try {
+ String path = System.getProperty("sftp.test.user.key");
+ if (path == null) {
+ throw new IllegalStateException("Certificate path not set.
Test resource not started?");
+ }
+ return Files.readAllBytes(Path.of(path));
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to read user private key
bytes", e);
+ }
+ }
+
+ public byte[] getUserCertificateBytes() {
+ try {
+ String path = System.getProperty("sftp.test.user.cert");
+ if (path == null) {
+ throw new IllegalStateException("Certificate path not set.
Test resource not started?");
+ }
+ return Files.readAllBytes(Path.of(path));
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to read user certificate
bytes", e);
+ }
+ }
+}
diff --git
a/integration-tests/ftp/src/main/java/org/apache/camel/quarkus/component/sftp/it/SftpResource.java
b/integration-tests/ftp/src/main/java/org/apache/camel/quarkus/component/sftp/it/SftpResource.java
index 0a890acd93..5c28cfc99e 100644
---
a/integration-tests/ftp/src/main/java/org/apache/camel/quarkus/component/sftp/it/SftpResource.java
+++
b/integration-tests/ftp/src/main/java/org/apache/camel/quarkus/component/sftp/it/SftpResource.java
@@ -16,7 +16,6 @@
*/
package org.apache.camel.quarkus.component.sftp.it;
-import java.io.InputStream;
import java.net.URI;
import jakarta.enterprise.context.ApplicationScoped;
@@ -38,6 +37,9 @@ import org.apache.camel.ProducerTemplate;
import org.apache.camel.component.file.remote.SftpConfiguration;
import org.apache.camel.component.file.remote.SftpEndpoint;
+import static java.nio.file.Files.*;
+import static java.util.logging.Logger.*;
+
@Path("/sftp")
@ApplicationScoped
public class SftpResource {
@@ -53,12 +55,15 @@ public class SftpResource {
@Inject
ConsumerTemplate consumerTemplate;
+ @Inject
+ SftpCertificateManager certificateManager;
+
@Path("/get/{fileName}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getFile(@PathParam("fileName") String fileName) {
return consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&localWorkDirectory=target&fileName="
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&useUserKnownHostsFile=false&localWorkDirectory=target&fileName="
+ fileName,
TIMEOUT_MS,
String.class);
@@ -69,7 +74,9 @@ public class SftpResource {
@Consumes(MediaType.TEXT_PLAIN)
public Response createFile(@PathParam("fileName") String fileName, String
fileContent)
throws Exception {
-
producerTemplate.sendBodyAndHeader("sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin",
fileContent,
+ producerTemplate.sendBodyAndHeader(
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&useUserKnownHostsFile=false",
+ fileContent,
Exchange.FILE_NAME, fileName);
return Response
.created(new URI("https://camel.apache.org/"))
@@ -80,7 +87,8 @@ public class SftpResource {
@DELETE
public void deleteFile(@PathParam("fileName") String fileName) {
consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&delete=true&fileName="
+ fileName,
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&useUserKnownHostsFile=false&delete=true&fileName="
+ + fileName,
TIMEOUT_MS,
String.class);
}
@@ -89,7 +97,7 @@ public class SftpResource {
@PUT
public void moveToDoneFile(@PathParam("fileName") String fileName) {
consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&move=${headers.CamelFileName}.done&fileName="
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?password=admin&useUserKnownHostsFile=false&move=${headers.CamelFileName}.done&fileName="
+ fileName,
TIMEOUT_MS,
String.class);
@@ -101,7 +109,7 @@ public class SftpResource {
public Response createFileWithCertificate(@PathParam("fileName") String
fileName, String fileContent)
throws Exception {
producerTemplate.sendBodyAndHeader(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub",
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:target/classes/certs/test-key-rsa.key&certUri=file:target/classes/certs/test-key-rsa-cert.pub&useUserKnownHostsFile=false",
fileContent,
Exchange.FILE_NAME, fileName);
return Response
@@ -114,7 +122,7 @@ public class SftpResource {
@Produces(MediaType.TEXT_PLAIN)
public String getFileWithCertificate(@PathParam("fileName") String
fileName) {
return consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub&localWorkDirectory=target&fileName="
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:target/classes/certs/test-key-rsa.key&certUri=file:target/classes/certs/test-key-rsa-cert.pub&useUserKnownHostsFile=false&localWorkDirectory=target&fileName="
+ fileName,
TIMEOUT_MS,
String.class);
@@ -126,7 +134,7 @@ public class SftpResource {
public Response createFileWithCertificateFile(@PathParam("fileName")
String fileName, String fileContent)
throws Exception {
producerTemplate.sendBodyAndHeader(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=target/classes/certs/test-key-rsa.key&certFile=target/classes/certs/test-key-rsa-cert.pub",
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=target/classes/certs/test-key-rsa.key&certFile=target/classes/certs/test-key-rsa-cert.pub&useUserKnownHostsFile=false",
fileContent,
Exchange.FILE_NAME, fileName);
return Response
@@ -139,7 +147,7 @@ public class SftpResource {
@Produces(MediaType.TEXT_PLAIN)
public String getFileWithCertificateFile(@PathParam("fileName") String
fileName) {
return consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=target/classes/certs/test-key-rsa.key&certFile=target/classes/certs/test-key-rsa-cert.pub&localWorkDirectory=target&fileName="
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyFile=target/classes/certs/test-key-rsa.key&certFile=target/classes/certs/test-key-rsa-cert.pub&useUserKnownHostsFile=false&localWorkDirectory=target&fileName="
+ fileName,
TIMEOUT_MS,
String.class);
@@ -151,54 +159,32 @@ public class SftpResource {
public Response createFileWithCertificateBytes(@PathParam("fileName")
String fileName, String fileContent)
throws Exception {
- ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
- try (InputStream certStream =
classLoader.getResourceAsStream("certs/test-key-rsa-cert.pub");
- InputStream keyStream =
classLoader.getResourceAsStream("certs/test-key-rsa.key")) {
- if (certStream == null) {
- throw new RuntimeException("Failed reading cert file");
- }
-
- if (keyStream == null) {
- throw new RuntimeException("Failed reading key file");
- }
-
- String uri =
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp";
- SftpEndpoint endpoint = context.getEndpoint(uri,
SftpEndpoint.class);
- SftpConfiguration config = endpoint.getConfiguration();
- config.setCertBytes(certStream.readAllBytes());
- config.setPrivateKey(keyStream.readAllBytes());
-
- producerTemplate.sendBodyAndHeader(endpoint, fileContent,
Exchange.FILE_NAME, fileName);
- return Response
- .created(new URI("https://camel.apache.org/"))
- .build();
- }
+ String uri = "sftp://admin@localhost:{{camel.sftp.test-port}}/sftp";
+ SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+ SftpConfiguration config = endpoint.getConfiguration();
+
+ config.setCertBytes(certificateManager.getUserCertificateBytes());
+ config.setPrivateKey(certificateManager.getUserPrivateKeyBytes());
+
+ 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 {
- ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
- try (InputStream certStream =
classLoader.getResourceAsStream("certs/test-key-rsa-cert.pub");
- InputStream keyStream =
classLoader.getResourceAsStream("certs/test-key-rsa.key")) {
- if (certStream == null) {
- throw new RuntimeException("Failed reading cert file");
- }
-
- if (keyStream == null) {
- throw new RuntimeException("Failed reading key file");
- }
-
- String uri =
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?localWorkDirectory=target&fileName="
- + fileName;
- SftpEndpoint endpoint = context.getEndpoint(uri,
SftpEndpoint.class);
- SftpConfiguration config = endpoint.getConfiguration();
- config.setCertBytes(certStream.readAllBytes());
- config.setPrivateKey(keyStream.readAllBytes());
-
- return consumerTemplate.receiveBody(endpoint, TIMEOUT_MS,
String.class);
- }
+ String uri =
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?localWorkDirectory=target&fileName="
+ + fileName;
+ SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+ SftpConfiguration config = endpoint.getConfiguration();
+
+ config.setCertBytes(certificateManager.getUserCertificateBytes());
+ config.setPrivateKey(certificateManager.getUserPrivateKeyBytes());
+
+ return consumerTemplate.receiveBody(endpoint, TIMEOUT_MS,
String.class);
}
@Path("/certificateWithCaAlgorithms/create/{fileName}")
@@ -207,7 +193,7 @@ public class SftpResource {
public Response
createFileWithCertificateAndCaAlgorithms(@PathParam("fileName") String
fileName, String fileContent)
throws Exception {
producerTemplate.sendBodyAndHeader(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub&caSignatureAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-rsa",
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:target/classes/certs/test-key-rsa.key&certUri=file:target/classes/certs/test-key-rsa-cert.pub&useUserKnownHostsFile=false&caSignatureAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-rsa",
fileContent,
Exchange.FILE_NAME, fileName);
return Response
@@ -220,7 +206,7 @@ public class SftpResource {
@Produces(MediaType.TEXT_PLAIN)
public String getFileWithCertificateAndCaAlgorithms(@PathParam("fileName")
String fileName) {
return consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub&caSignatureAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-rsa&localWorkDirectory=target&fileName="
+
"sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:target/classes/certs/test-key-rsa.key&certUri=file:target/classes/certs/test-key-rsa-cert.pub&useUserKnownHostsFile=false&caSignatureAlgorithms=rsa-sha2-512,rsa-sha2-256,ssh-rsa&localWorkDirectory=target&fileName="
+ fileName,
TIMEOUT_MS,
String.class);
@@ -231,12 +217,16 @@ public class SftpResource {
@Consumes(MediaType.TEXT_PLAIN)
public Response createFileWithHostCertVerification(@PathParam("fileName")
String fileName, String fileContent)
throws Exception {
- String knownHostsFile = createHostCaKnownHostsFile();
+ byte[] knownHostsContent = getHostCaKnownHostsContent();
String port =
context.resolvePropertyPlaceholders("{{camel.sftp.hostcert.test-port}}");
String uri = "sftp://admin@localhost:" + port
- +
"/sftp?password=admin&strictHostKeyChecking=yes&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa&knownHostsFile="
- + knownHostsFile;
- producerTemplate.sendBodyAndHeader(uri, fileContent,
Exchange.FILE_NAME, fileName);
+ +
"/sftp?password=admin&strictHostKeyChecking=no&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa";
+
+ SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+ SftpConfiguration config = endpoint.getConfiguration();
+ config.setKnownHosts(knownHostsContent);
+
+ producerTemplate.sendBodyAndHeader(endpoint, fileContent,
Exchange.FILE_NAME, fileName);
return Response
.created(new URI("https://camel.apache.org/"))
.build();
@@ -246,23 +236,33 @@ public class SftpResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getFileWithHostCertVerification(@PathParam("fileName")
String fileName) throws Exception {
- String knownHostsFile = createHostCaKnownHostsFile();
- return consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.hostcert.test-port}}/sftp?password=admin&strictHostKeyChecking=yes&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa&knownHostsFile="
- + knownHostsFile +
"&localWorkDirectory=target&fileName=" + fileName,
- TIMEOUT_MS,
- String.class);
+ byte[] knownHostsContent = getHostCaKnownHostsContent();
+ String port =
context.resolvePropertyPlaceholders("{{camel.sftp.hostcert.test-port}}");
+ String uri = "sftp://admin@localhost:" + port
+ +
"/sftp?password=admin&strictHostKeyChecking=no&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa&localWorkDirectory=target&fileName="
+ + fileName;
+
+ SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+ SftpConfiguration config = endpoint.getConfiguration();
+ config.setKnownHosts(knownHostsContent);
+
+ return consumerTemplate.receiveBody(endpoint, TIMEOUT_MS,
String.class);
}
@Path("/hostcert/delete/{fileName}")
@DELETE
public Response deleteFileWithHostCert(@PathParam("fileName") String
fileName) throws Exception {
- String knownHostsFile = createHostCaKnownHostsFile();
- consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.hostcert.test-port}}/sftp?password=admin&strictHostKeyChecking=yes&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa&knownHostsFile="
- + knownHostsFile + "&delete=true&fileName=" + fileName,
- TIMEOUT_MS,
- String.class);
+ byte[] knownHostsContent = getHostCaKnownHostsContent();
+ String port =
context.resolvePropertyPlaceholders("{{camel.sftp.hostcert.test-port}}");
+ String uri = "sftp://admin@localhost:" + port
+ +
"/sftp?password=admin&strictHostKeyChecking=no&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa&delete=true&fileName="
+ + fileName;
+
+ SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+ SftpConfiguration config = endpoint.getConfiguration();
+ config.setKnownHosts(knownHostsContent);
+
+ consumerTemplate.receiveBody(endpoint, TIMEOUT_MS, String.class);
return Response.noContent().build();
}
@@ -271,12 +271,16 @@ public class SftpResource {
@Consumes(MediaType.TEXT_PLAIN)
public Response createFileWithHostCertAndAlgorithms(@PathParam("fileName")
String fileName, String fileContent)
throws Exception {
- String knownHostsFile = createHostCaKnownHostsFile();
- producerTemplate.sendBodyAndHeader(
-
"sftp://admin@localhost:{{camel.sftp.hostcert.test-port}}/sftp?password=admin&strictHostKeyChecking=yes&useUserKnownHostsFile=false&knownHostsFile="
- + knownHostsFile +
"&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256",
- fileContent,
- Exchange.FILE_NAME, fileName);
+ byte[] knownHostsContent = getHostCaKnownHostsContent();
+ String port =
context.resolvePropertyPlaceholders("{{camel.sftp.hostcert.test-port}}");
+ String uri = "sftp://admin@localhost:" + port
+ +
"/sftp?password=admin&strictHostKeyChecking=no&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256";
+
+ SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+ SftpConfiguration config = endpoint.getConfiguration();
+ config.setKnownHosts(knownHostsContent);
+
+ producerTemplate.sendBodyAndHeader(endpoint, fileContent,
Exchange.FILE_NAME, fileName);
return Response
.created(new URI("https://camel.apache.org/"))
.build();
@@ -286,57 +290,51 @@ public class SftpResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String getFileWithHostCertAndAlgorithms(@PathParam("fileName")
String fileName) throws Exception {
- String knownHostsFile = createHostCaKnownHostsFile();
- return consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.hostcert.test-port}}/sftp?password=admin&strictHostKeyChecking=yes&useUserKnownHostsFile=false&knownHostsFile="
- + knownHostsFile
- +
"&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256&localWorkDirectory=target&fileName="
- + fileName,
- TIMEOUT_MS,
- String.class);
+ byte[] knownHostsContent = getHostCaKnownHostsContent();
+ String port =
context.resolvePropertyPlaceholders("{{camel.sftp.hostcert.test-port}}");
+ String uri = "sftp://admin@localhost:" + port
+ +
"/sftp?password=admin&strictHostKeyChecking=no&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256&localWorkDirectory=target&fileName="
+ + fileName;
+
+ SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+ SftpConfiguration config = endpoint.getConfiguration();
+ config.setKnownHosts(knownHostsContent);
+
+ return consumerTemplate.receiveBody(endpoint, TIMEOUT_MS,
String.class);
}
@Path("/hostcertWithAlgorithms/delete/{fileName}")
@DELETE
public Response deleteFileWithHostCertAndAlgorithms(@PathParam("fileName")
String fileName) throws Exception {
- String knownHostsFile = createHostCaKnownHostsFile();
- consumerTemplate.receiveBody(
-
"sftp://admin@localhost:{{camel.sftp.hostcert.test-port}}/sftp?password=admin&strictHostKeyChecking=yes&useUserKnownHostsFile=false&knownHostsFile="
- + knownHostsFile
- +
"&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256&delete=true&fileName="
- + fileName,
- TIMEOUT_MS,
- String.class);
+ byte[] knownHostsContent = getHostCaKnownHostsContent();
+ String port =
context.resolvePropertyPlaceholders("{{camel.sftp.hostcert.test-port}}");
+ String uri = "sftp://admin@localhost:" + port
+ +
"/sftp?password=admin&strictHostKeyChecking=no&useUserKnownHostsFile=false&caSignatureAlgorithms=ssh-ed25519,rsa-sha2-512,rsa-sha2-256&delete=true&fileName="
+ + fileName;
+
+ SftpEndpoint endpoint = context.getEndpoint(uri, SftpEndpoint.class);
+ SftpConfiguration config = endpoint.getConfiguration();
+ config.setKnownHosts(knownHostsContent);
+
+ consumerTemplate.receiveBody(endpoint, TIMEOUT_MS, String.class);
return Response.noContent().build();
}
/**
- * Creates a known_hosts file with @cert-authority entry for the host CA.
+ * Creates known_hosts content with @cert-authority entry for the host CA.
* This allows the client to verify the server's host certificate.
+ * Returns the content as a byte array to avoid JSch's global host key
cache
+ * that persists across JSch instances when using file-based known_hosts.
*/
- private String createHostCaKnownHostsFile() throws Exception {
- String resourcePath = "certs/host-ca.pub";
- ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
-
- try (InputStream stream =
classLoader.getResourceAsStream(resourcePath)) {
- if (stream == null) {
- throw new RuntimeException("Failed to load host CA public key
from: " + resourcePath);
- }
- return processHostCaStream(stream);
- }
- }
-
- private String processHostCaStream(InputStream hostCaStream) throws
Exception {
- String hostCaPubKey = new String(hostCaStream.readAllBytes()).trim();
+ private byte[] getHostCaKnownHostsContent() throws Exception {
+ String hostCaPubKey =
org.apache.camel.quarkus.test.support.sftp.SftpHostCertTestResource.getHostCaPublicKey();
String port =
context.resolvePropertyPlaceholders("{{camel.sftp.hostcert.test-port}}");
- // Create known_hosts with @cert-authority entry
String knownHostsContent = String.format("@cert-authority
[localhost]:%s %s%n", port, hostCaPubKey);
- // Use temp directory instead of "target" which may not exist in
native mode runtime
- java.nio.file.Path knownHostsPath =
java.nio.file.Files.createTempFile("known_hosts_hostcert", ".txt");
- java.nio.file.Files.writeString(knownHostsPath, knownHostsContent);
+ getLogger(SftpResource.class.getName()).fine(
+ "Created known_hosts content:\n" + knownHostsContent);
- return knownHostsPath.toAbsolutePath().toString();
+ return
knownHostsContent.getBytes(java.nio.charset.StandardCharsets.UTF_8);
}
}
diff --git a/integration-tests/ftp/src/main/resources/application.properties
b/integration-tests/ftp/src/main/resources/application.properties
index 25bfaf1cfa..8fcaf03aa5 100644
--- a/integration-tests/ftp/src/main/resources/application.properties
+++ b/integration-tests/ftp/src/main/resources/application.properties
@@ -17,5 +17,3 @@
# Change to INFO level to get insights about commands run on the FTP server
quarkus.log.category."org.apache.ftpserver".level = WARNING
-
-quarkus.native.resources.includes=certs/test-key-rsa.key,certs/test-key-rsa-cert.pub,certs/host-ca.pub,certs/host-key-rsa.key,certs/host-key-rsa-cert.pub
diff --git
a/integration-tests/ftp/src/main/resources/certs/generate-certificates.sh
b/integration-tests/ftp/src/main/resources/certs/generate-certificates.sh
deleted file mode 100755
index 8e9079b3e7..0000000000
--- a/integration-tests/ftp/src/main/resources/certs/generate-certificates.sh
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/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:
-# USER CERTIFICATES:
-# - test-key-rsa.key: RSA private key (2048 bits)
-# - test-key-rsa-cert.pub: OpenSSH user certificate signed by user CA
-#
-# HOST CERTIFICATES:
-# - host-ca.pub: Host CA public key (for @cert-authority in known_hosts)
-# - host-key-rsa.key: RSA host private key (2048 bits)
-# - host-key-rsa-cert.pub: OpenSSH host certificate signed by host CA
-#
-# The certificates are valid for 52 weeks and can be used for testing
-# certificate-based authentication with the FTP component.
-#
-
-set -e
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-cd "$SCRIPT_DIR"
-
-echo "==================================================================="
-echo "Generating OpenSSH Certificates for FTP Integration Tests"
-echo "==================================================================="
-echo ""
-
-echo "Cleaning up existing files..."
-rm -f user-ca user-ca.pub test-key-rsa.key test-key-rsa.key.pub
test-key-rsa-cert.pub
-rm -f host-ca host-ca.pub host-key-rsa.key host-key-rsa.key.pub
host-key-rsa-cert.pub
-echo "Cleaned up existing files"
-
-echo ""
-echo "--- USER CERTIFICATE GENERATION ---"
-echo ""
-
-echo "Generating user CA key pair..."
-ssh-keygen -t rsa -b 2048 -f user-ca -N "" -C "user-ca" > /dev/null 2>&1
-echo "Created user-ca and user-ca.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 user public key with user CA to create certificate..."
-ssh-keygen -s user-ca \
- -I "test-user" \
- -n admin \
- -V +520w \
- test-key-rsa.key.pub > /dev/null 2>&1
-echo "Created test-key-rsa.key-cert.pub"
-
-echo "Renaming user 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 ""
-echo "--- HOST CERTIFICATE GENERATION ---"
-echo ""
-
-echo "Generating host CA key pair..."
-ssh-keygen -t ed25519 -f host-ca -N "" -C "host-ca" > /dev/null 2>&1
-echo "Created host-ca and host-ca.pub"
-
-echo "Generating host RSA key pair..."
-ssh-keygen -t rsa -b 2048 -f host-key-rsa.key -N "" -C "sftp-server@localhost"
> /dev/null 2>&1
-echo "Created host-key-rsa.key and host-key-rsa.key.pub"
-
-echo "Signing host public key with host CA to create host certificate..."
-ssh-keygen -s host-ca \
- -I "sftp-server" \
- -h \
- -n localhost \
- -V +520w \
- host-key-rsa.key.pub > /dev/null 2>&1
-echo "Created host-key-rsa.key-cert.pub"
-
-echo "Renaming host certificate to host-key-rsa-cert.pub..."
-mv host-key-rsa.key-cert.pub host-key-rsa-cert.pub
-echo "Renamed to host-key-rsa-cert.pub"
-
-echo ""
-echo "Cleaning up temporary files..."
-rm -f user-ca user-ca.pub test-key-rsa.key.pub
-rm -f host-ca host-key-rsa.key.pub
-echo "Removed CA private keys and public keys"
diff --git a/integration-tests/ftp/src/main/resources/certs/host-ca.pub
b/integration-tests/ftp/src/main/resources/certs/host-ca.pub
deleted file mode 100644
index d0a10f97cf..0000000000
--- a/integration-tests/ftp/src/main/resources/certs/host-ca.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-ed25519
AAAAC3NzaC1lZDI1NTE5AAAAIITv5DGdGNCNkU+DMJsMsAsFoufh4yO5DB2PK48eUmqq host-ca
diff --git
a/integration-tests/ftp/src/main/resources/certs/host-key-rsa-cert.pub
b/integration-tests/ftp/src/main/resources/certs/host-key-rsa-cert.pub
deleted file mode 100644
index 79c92a7e12..0000000000
--- a/integration-tests/ftp/src/main/resources/certs/host-key-rsa-cert.pub
+++ /dev/null
@@ -1 +0,0 @@
[email protected]
AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgqfpKfP1HcEq0OkSV20BryP+RpxsjCw3QYoLiO7G8p7sAAAADAQABAAABAQCktIEA/teg39lFRRPsFNVfbE93LCj7cewNUjZX+xoHWpBWA6FfaM1xBFmx99W0SAq9TwX8RC8yNzZAYOY4HQIwJYP9NNskMXrV4efQ/HFxg/OGETKDLi/bFgGEJPzIUX+vwLw+RVBcH8HhxHbhvCX/TBliZ6StOlIgoYi/2RKKp9uh3EmOU5gHozNz0jdzRPgVVQvgQvrW7E+2PS/GI67IUxElZSaI8qYFslXbw+iyQSdBg+ZqFl8Z9HVQweV/H5w0o1+87lWkaSIQxJccbmTcaub4Q+KWLci4qALE7yKLnVpuPJxe7zNV/uqd7fh85v5pl8MxQasZLduPf2AyoM1rAAAAAAAAAAAAAAA
[...]
diff --git a/integration-tests/ftp/src/main/resources/certs/host-key-rsa.key
b/integration-tests/ftp/src/main/resources/certs/host-key-rsa.key
deleted file mode 100644
index a8cff6531f..0000000000
--- a/integration-tests/ftp/src/main/resources/certs/host-key-rsa.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
-NhAAAAAwEAAQAAAQEApLSBAP7XoN/ZRUUT7BTVX2xPdywo+3HsDVI2V/saB1qQVgOhX2jN
-cQRZsffVtEgKvU8F/EQvMjc2QGDmOB0CMCWD/TTbJDF61eHn0PxxcYPzhhEygy4v2xYBhC
-T8yFF/r8C8PkVQXB/B4cR24bwl/0wZYmekrTpSIKGIv9kSiqfbodxJjlOYB6Mzc9I3c0T4
-FVUL4EL61uxPtj0vxiOuyFMRJWUmiPKmBbJV28PoskEnQYPmahZfGfR1UMHlfx+cNKNfvO
-5VpGkiEMSXHG5k3Grm+EPili3IuKgCxO8ii51abjycXu8zVf7qne34fOb+aZfDMUGrGS3b
-j39gMqDNawAAA9CCNbkKgjW5CgAAAAdzc2gtcnNhAAABAQCktIEA/teg39lFRRPsFNVfbE
-93LCj7cewNUjZX+xoHWpBWA6FfaM1xBFmx99W0SAq9TwX8RC8yNzZAYOY4HQIwJYP9NNsk
-MXrV4efQ/HFxg/OGETKDLi/bFgGEJPzIUX+vwLw+RVBcH8HhxHbhvCX/TBliZ6StOlIgoY
-i/2RKKp9uh3EmOU5gHozNz0jdzRPgVVQvgQvrW7E+2PS/GI67IUxElZSaI8qYFslXbw+iy
-QSdBg+ZqFl8Z9HVQweV/H5w0o1+87lWkaSIQxJccbmTcaub4Q+KWLci4qALE7yKLnVpuPJ
-xe7zNV/uqd7fh85v5pl8MxQasZLduPf2AyoM1rAAAAAwEAAQAAAQBERCqKGpaOL+nSm7iP
-q+zqga6IMw4DdisENHSgz8twi9lyRUvwCzTHqKlyqcnyUL/eyi+taSd0tUyvr1oMnP1ork
-wAOZWw8S88Ekeup8tvZOUdRuh8VbrxIDRdrKT3dEwrsQN0/e66WFFYfcFWe9D1+Xk1/8ZS
-JG+g5cMT3WmhfRpBmIRZT3nHQTdjkrVIsK1dkbgCbxQBX/hKD/nV0AC/HjBbqx7MVvpK4N
-MKy+Prg/JUvy51GtUeQNZw92Gc7osLpFAzh2apgMhK1ZbWyPjrb/mQ/NXVG6ETuW+3ktwh
-qLLGPjwG/eE+UgWqn1LFgHINpD5y8NbuQ7bCkM5ADaF9AAAAgCIkD2uKemGJpnbEHBGVOO
-sRoP5TGDMPwueagpH8JPll6GfQo7NzxZQJttp4FDCmzbbTN6u7Jk7f8UHprhhzk//Lgm+a
-Ds1qGN11WA32MFCUJixtgc3re1W4nGF3BIshv4tScQVpMcBhDBtSJSzeVpHfeB+k2hzkK2
-/TCbMAHjmZAAAAgQDPbPrfiAbSjmCOjgf/aa82D73Rry/wL4d6bZTi2wwxu3HmzuA0G7L8
-qGV9UIEJ5jFHbQq/wP46XpiIESfkg+PmrUGOwZQ22cjpsPzxJzysvK3oYiuXduE8uz+c/F
-HDx1ONNeDB011k3h1JRcquYrU5SMqWnZLF/vnyvqQgywLXNwAAAIEAy0Z0WJFIiMYJTf4N
-Wa79DbsDutVei72QpoAwMlzBouD2YBArxznCsVC3rVKPVBlUTT2oszCfwQLo3fMjZs3yjW
-SrKc2/EDex8drZg+w262mX+bDQZD+PI1LgrpF7L5e5//id4On5ie6cwIc+8RJRelqhrftT
-T0lFiZ4C2JhdrW0AAAAVc2Z0cC1zZXJ2ZXJAbG9jYWxob3N0AQIDBAUG
------END OPENSSH PRIVATE KEY-----
diff --git
a/integration-tests/ftp/src/main/resources/certs/test-key-rsa-cert.pub
b/integration-tests/ftp/src/main/resources/certs/test-key-rsa-cert.pub
deleted file mode 100644
index fa138337ce..0000000000
--- a/integration-tests/ftp/src/main/resources/certs/test-key-rsa-cert.pub
+++ /dev/null
@@ -1 +0,0 @@
[email protected]
AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgWeZP/HKtZqoYUuTZBJDuYgLpWoFI881IQ2mL7gMIVrIAAAADAQABAAABAQCQ6auYkjIBrtHexpzxGkfWoDU0IeRiye2HjGKZa7fHRdYYaQBstJXcnPgzcgOY70dzYe5A9WorWhi+33YWrox6k16WeeYREcogRZ12M0hnEZQa74J5yUHDxHGofHrgh4SIPqE/HOukC8X5LGYV5VPD4wabFdBxbpuPLuPcddWMhZCdd9OqXGizk5nwLhIOM7N3A5kDxn2NtyBPt3WsxCM8Y4d+yWR6BeoUzhBDRFx2yw1aNLbj7aoc7sMPOJXgIJDI0nm1mcdmF1FQqnPlG4zmh9G1B7B8cZfQ8kz+Q+GrFGkgPSwRqZ14+CUfymutuJzcU7hBDdfgbBu5UWnade7dAAAAAAAAAAAAAAA
[...]
diff --git a/integration-tests/ftp/src/main/resources/certs/test-key-rsa.key
b/integration-tests/ftp/src/main/resources/certs/test-key-rsa.key
deleted file mode 100644
index ac6440d774..0000000000
--- a/integration-tests/ftp/src/main/resources/certs/test-key-rsa.key
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
-NhAAAAAwEAAQAAAQEAkOmrmJIyAa7R3sac8RpH1qA1NCHkYsnth4ximWu3x0XWGGkAbLSV
-3Jz4M3IDmO9Hc2HuQPVqK1oYvt92Fq6MepNelnnmERHKIEWddjNIZxGUGu+CeclBw8RxqH
-x64IeEiD6hPxzrpAvF+SxmFeVTw+MGmxXQcW6bjy7j3HXVjIWQnXfTqlxos5OZ8C4SDjOz
-dwOZA8Z9jbcgT7d1rMQjPGOHfslkegXqFM4QQ0RcdssNWjS24+2qHO7DDziV4CCQyNJ5tZ
-nHZhdRUKpz5RuM5ofRtQewfHGX0PJM/kPhqxRpID0sEamdePglH8prrbic3FO4QQ3X4Gwb
-uVFp2nXu3QAAA8h2OWSFdjlkhQAAAAdzc2gtcnNhAAABAQCQ6auYkjIBrtHexpzxGkfWoD
-U0IeRiye2HjGKZa7fHRdYYaQBstJXcnPgzcgOY70dzYe5A9WorWhi+33YWrox6k16WeeYR
-EcogRZ12M0hnEZQa74J5yUHDxHGofHrgh4SIPqE/HOukC8X5LGYV5VPD4wabFdBxbpuPLu
-PcddWMhZCdd9OqXGizk5nwLhIOM7N3A5kDxn2NtyBPt3WsxCM8Y4d+yWR6BeoUzhBDRFx2
-yw1aNLbj7aoc7sMPOJXgIJDI0nm1mcdmF1FQqnPlG4zmh9G1B7B8cZfQ8kz+Q+GrFGkgPS
-wRqZ14+CUfymutuJzcU7hBDdfgbBu5UWnade7dAAAAAwEAAQAAAQAOPtJOEM0WqkNaVYb3
-EqDOQfiI8+36IiSWByBoOZUa40wdITFX/lafFdU2ZXZiEd+hwZZEz3tM4LH/DYOTzjvkDt
-mlDD2oHuoSSxWkGX18GFfJYBMg+r5aytRrfjUsHlZSeGmshSDLAxdGm+07KMyXvJkZJMdV
-Z0ymgjMHKJRCGHdSmsLsNhMFgaLdqsFqogdZOS/ctPuCRpGLPPTDqnXGqXN2DHumHvBsek
-kl5kM2cbb1mqCpN2r6YQX/iQZMI8iufWrIXK3Au30QLmR9opQit/dISYC7GO3N6LEFN9lV
-BjtHzNLRGhnyirAuSvtRcsM/LwxxEnZSSwJcEINDsu8hAAAAgQCj3PPoWb/Jvy7T474Qrd
-lbPBPc5ADmUNcrb7YWA9OtZsZ7dh2ZkAuCyRYNzbuKXwA9ktouQ0mMcvLdVhGMJKE0+ewm
-WtMWcs0n4qTXdb9MPCOuuYSS9HGNAUeDAy1ZGdonHhN9X+EDt+NW7QdYlYNnqXqpUgnruU
-6dMXex8Tg9CAAAAIEAxQTnYT/eyDSsqiDfpAN2mNaAbfB3iZfhGCqkhC7M5Uq/F4+/Kte1
-UgCOtvO8pOpLT6cSxJvnLuDFK9ZBX1SrdbgRYViFUCXc1we02t62nrwjrH8zyjAfOTdc6d
-2MVmQdihshK+q46c8kkxWbAjJ5HY/G8spTyXsbyuDI9PVZOa0AAACBALxLc/R+R4ls+Y7m
-tMRVWG7qzDMqexJEyeZMHV+8LwORExPdepI4u4CZLSUM4FgOAH1p9H9j+f8bf9KvcCMCBt
-1sgEZTw2tfkhWG/T14yrQjl5+bezU1yPdFx7xWyH1QozbqPl4hihTQAenv1WzXiC/PHG6s
-3v7E8gkor5VpG4/xAAAADXRlc3QtcnNhQHRlc3QBAgMEBQ==
------END OPENSSH PRIVATE KEY-----
diff --git a/integration-tests/mina-sftp/pom.xml
b/integration-tests/mina-sftp/pom.xml
index 7689bdff9f..466ba6f77c 100644
--- a/integration-tests/mina-sftp/pom.xml
+++ b/integration-tests/mina-sftp/pom.xml
@@ -43,6 +43,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+
<artifactId>camel-quarkus-integration-tests-support-sftp</artifactId>
+ </dependency>
<!-- test dependencies -->
<dependency>
@@ -62,11 +66,6 @@
<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>
@@ -140,5 +139,16 @@
</dependency>
</dependencies>
</profile>
+ <profile>
+ <id>skip-testcontainers-tests</id>
+ <activation>
+ <property>
+ <name>skip-testcontainers-tests</name>
+ </property>
+ </activation>
+ <properties>
+ <skipTests>true</skipTests>
+ </properties>
+ </profile>
</profiles>
</project>
diff --git
a/integration-tests/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpCertificateManager.java
b/integration-tests/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpCertificateManager.java
new file mode 100644
index 0000000000..ece5118ee4
--- /dev/null
+++
b/integration-tests/mina-sftp/src/main/java/org/apache/camel/quarkus/component/mina/sftp/it/MinaSftpCertificateManager.java
@@ -0,0 +1,133 @@
+/*
+ * 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.nio.file.Files;
+import java.nio.file.Path;
+
+import io.quarkus.runtime.Startup;
+import jakarta.enterprise.context.ApplicationScoped;
+import org.jboss.logging.Logger;
+
+import static java.nio.file.StandardCopyOption.*;
+
+/**
+ * Manages SSH certificates for MINA SFTP integration tests.
+ * Uses certificates generated by the containerized SFTP test resource.
+ */
+@ApplicationScoped
+@Startup
+public class MinaSftpCertificateManager {
+ private static final Logger LOGGER =
Logger.getLogger(MinaSftpCertificateManager.class);
+
+ private Path certsDir;
+
+ public MinaSftpCertificateManager() {
+ try {
+ initializeCertificates();
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to initialize MINA SFTP
certificates", e);
+ }
+ }
+
+ private void initializeCertificates() throws Exception {
+ LOGGER.info("Setting up MINA SFTP certificate files from test
resource");
+
+ Path targetCerts = Path.of("target", "certs");
+ Path classpathCerts = Path.of("target", "classes", "certs");
+ Files.createDirectories(targetCerts);
+ Files.createDirectories(classpathCerts);
+
+ certsDir = targetCerts;
+
+ String userKeyPath = System.getProperty("sftp.test.user.key");
+ String userCertPath = System.getProperty("sftp.test.user.cert");
+ String userKeyRsaPath = System.getProperty("sftp.test.user.key.rsa");
+ String userCertRsaPath = System.getProperty("sftp.test.user.cert.rsa");
+ String ftpKeyPath = System.getProperty("sftp.test.ftp.key");
+ String ftpEncryptedKeyPath =
System.getProperty("sftp.test.ftp.encrypted.key");
+
+ if (userKeyPath == null || userCertPath == null || userKeyRsaPath ==
null || userCertRsaPath == null
+ || ftpKeyPath == null || ftpEncryptedKeyPath == null) {
+ throw new IllegalStateException(
+ "Certificate paths not set. Test resource not started?
sftp.test.user.key=" + userKeyPath
+ + ", sftp.test.user.cert=" + userCertPath
+ + ", sftp.test.user.key.rsa=" + userKeyRsaPath
+ + ", sftp.test.user.cert.rsa=" + userCertRsaPath
+ + ", sftp.test.ftp.key=" + ftpKeyPath
+ + ", sftp.test.ftp.encrypted.key=" +
ftpEncryptedKeyPath);
+ }
+
+ // Ed25519 certificate files
+ byte[] ed25519PrivateKeyBytes =
Files.readAllBytes(Path.of(userKeyPath));
+ byte[] ed25519CertificateBytes =
Files.readAllBytes(Path.of(userCertPath));
+
+ Files.write(targetCerts.resolve("test-key-ed25519.key"),
ed25519PrivateKeyBytes);
+ Files.write(targetCerts.resolve("test-key-ed25519-cert.pub"),
ed25519CertificateBytes);
+ Files.write(classpathCerts.resolve("test-key-ed25519.key"),
ed25519PrivateKeyBytes);
+ Files.write(classpathCerts.resolve("test-key-ed25519-cert.pub"),
ed25519CertificateBytes);
+
+ // RSA certificate files
+ byte[] rsaPrivateKeyBytes =
Files.readAllBytes(Path.of(userKeyRsaPath));
+ byte[] rsaCertificateBytes =
Files.readAllBytes(Path.of(userCertRsaPath));
+
+ Files.write(targetCerts.resolve("test-key-rsa.key"),
rsaPrivateKeyBytes);
+ Files.write(targetCerts.resolve("test-key-rsa-cert.pub"),
rsaCertificateBytes);
+ Files.write(classpathCerts.resolve("test-key-rsa.key"),
rsaPrivateKeyBytes);
+ Files.write(classpathCerts.resolve("test-key-rsa-cert.pub"),
rsaCertificateBytes);
+
+ Path ftpKeySource = Path.of(ftpKeyPath);
+ Files.copy(ftpKeySource, targetCerts.resolve("ftp.key"),
REPLACE_EXISTING);
+ Files.copy(ftpKeySource, classpathCerts.resolve("ftp.key"),
REPLACE_EXISTING);
+
+ Path ftpEncryptedKeySource = Path.of(ftpEncryptedKeyPath);
+ Files.copy(ftpEncryptedKeySource,
targetCerts.resolve("ftp-encrypted.key"),
+ REPLACE_EXISTING);
+ Files.copy(ftpEncryptedKeySource,
classpathCerts.resolve("ftp-encrypted.key"),
+ REPLACE_EXISTING);
+
+ LOGGER.infof("MINA SFTP certificate files created in: %s and %s",
targetCerts, classpathCerts);
+ }
+
+ public Path getCertsDir() {
+ return certsDir;
+ }
+
+ public byte[] getUserPrivateKeyBytes() {
+ try {
+ String path = System.getProperty("sftp.test.user.key");
+ if (path == null) {
+ throw new IllegalStateException("Certificate path not set.
Test resource not started?");
+ }
+ return Files.readAllBytes(Path.of(path));
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to read user private key
bytes", e);
+ }
+ }
+
+ public byte[] getUserCertificateBytes() {
+ try {
+ String path = System.getProperty("sftp.test.user.cert");
+ if (path == null) {
+ throw new IllegalStateException("Certificate path not set.
Test resource not started?");
+ }
+ return Files.readAllBytes(Path.of(path));
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to read user certificate
bytes", e);
+ }
+ }
+}
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
index 3f6963305e..b2433e1043 100644
---
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
@@ -16,7 +16,6 @@
*/
package org.apache.camel.quarkus.component.mina.sftp.it;
-import java.io.InputStream;
import java.net.URI;
import jakarta.enterprise.context.ApplicationScoped;
@@ -57,6 +56,9 @@ public class MinaSftpResource {
@Inject
ConsumerTemplate consumerTemplate;
+ @Inject
+ MinaSftpCertificateManager certificateManager;
+
@Path("/load/component/mina-sftp")
@GET
@Produces(MediaType.TEXT_PLAIN)
@@ -216,7 +218,7 @@ public class MinaSftpResource {
public Response createFileWithCertificate(@PathParam("fileName") String
fileName, String fileContent)
throws Exception {
producerTemplate.sendBodyAndHeader(
-
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub",
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:target/classes/certs/test-key-rsa.key&certUri=file:target/classes/certs/test-key-rsa-cert.pub",
fileContent,
Exchange.FILE_NAME, fileName);
return Response
@@ -229,7 +231,7 @@ public class MinaSftpResource {
@Produces(MediaType.TEXT_PLAIN)
public String getFileWithCertificate(@PathParam("fileName") String
fileName) {
return consumerTemplate.receiveBody(
-
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub&localWorkDirectory=target&fileName="
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:target/classes/certs/test-key-rsa.key&certUri=file:target/classes/certs/test-key-rsa-cert.pub&localWorkDirectory=target&fileName="
+ fileName,
TIMEOUT_MS,
String.class);
@@ -241,7 +243,7 @@ public class MinaSftpResource {
public Response createFileWithCertificateUri(@PathParam("fileName") String
fileName, String fileContent)
throws Exception {
producerTemplate.sendBodyAndHeader(
-
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub",
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:target/classes/certs/test-key-rsa.key&certUri=file:target/classes/certs/test-key-rsa-cert.pub",
fileContent,
Exchange.FILE_NAME, fileName);
return Response
@@ -254,7 +256,7 @@ public class MinaSftpResource {
@Produces(MediaType.TEXT_PLAIN)
public String getFileWithCertificateUri(@PathParam("fileName") String
fileName) {
return consumerTemplate.receiveBody(
-
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub&localWorkDirectory=target&fileName="
+
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=file:target/classes/certs/test-key-rsa.key&certUri=file:target/classes/certs/test-key-rsa-cert.pub&localWorkDirectory=target&fileName="
+ fileName,
TIMEOUT_MS,
String.class);
@@ -266,54 +268,32 @@ public class MinaSftpResource {
public Response createFileWithCertificateBytes(@PathParam("fileName")
String fileName, String fileContent)
throws Exception {
- ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
- try (InputStream certStream =
classLoader.getResourceAsStream("certs/test-key-rsa-cert.pub");
- InputStream keyStream =
classLoader.getResourceAsStream("certs/test-key-rsa.key")) {
- if (certStream == null) {
- throw new RuntimeException("Failed reading cert file");
- }
-
- if (keyStream == null) {
- throw new RuntimeException("Failed reading key file");
- }
-
- String uri =
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp";
- MinaSftpEndpoint endpoint = context.getEndpoint(uri,
MinaSftpEndpoint.class);
- MinaSftpConfiguration config = endpoint.getConfiguration();
- config.setCertBytes(certStream.readAllBytes());
- config.setPrivateKey(keyStream.readAllBytes());
-
- producerTemplate.sendBodyAndHeader(endpoint, fileContent,
Exchange.FILE_NAME, fileName);
- return Response
- .created(new URI("https://camel.apache.org/"))
- .build();
- }
+ String uri =
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp";
+ MinaSftpEndpoint endpoint = context.getEndpoint(uri,
MinaSftpEndpoint.class);
+ MinaSftpConfiguration config = endpoint.getConfiguration();
+
+ config.setCertBytes(certificateManager.getUserCertificateBytes());
+ config.setPrivateKey(certificateManager.getUserPrivateKeyBytes());
+
+ 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 {
- ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
- try (InputStream certStream =
classLoader.getResourceAsStream("certs/test-key-rsa-cert.pub");
- InputStream keyStream =
classLoader.getResourceAsStream("certs/test-key-rsa.key")) {
- if (certStream == null) {
- throw new RuntimeException("Failed reading cert file");
- }
-
- if (keyStream == null) {
- throw new RuntimeException("Failed reading key file");
- }
-
- String uri =
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?localWorkDirectory=target&fileName="
- + fileName;
- MinaSftpEndpoint endpoint = context.getEndpoint(uri,
MinaSftpEndpoint.class);
- MinaSftpConfiguration config = endpoint.getConfiguration();
- config.setCertBytes(certStream.readAllBytes());
- config.setPrivateKey(keyStream.readAllBytes());
-
- return consumerTemplate.receiveBody(endpoint, TIMEOUT_MS,
String.class);
- }
+ String uri =
"mina-sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?localWorkDirectory=target&fileName="
+ + fileName;
+ MinaSftpEndpoint endpoint = context.getEndpoint(uri,
MinaSftpEndpoint.class);
+ MinaSftpConfiguration config = endpoint.getConfiguration();
+
+ config.setCertBytes(certificateManager.getUserCertificateBytes());
+ config.setPrivateKey(certificateManager.getUserPrivateKeyBytes());
+
+ return consumerTemplate.receiveBody(endpoint, TIMEOUT_MS,
String.class);
}
@Path("/compression/create/{fileName}")
diff --git
a/integration-tests/mina-sftp/src/main/resources/application.properties
b/integration-tests/mina-sftp/src/main/resources/application.properties
deleted file mode 100644
index 59099f9fb7..0000000000
--- a/integration-tests/mina-sftp/src/main/resources/application.properties
+++ /dev/null
@@ -1,17 +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.
-## ---------------------------------------------------------------------------
-quarkus.native.resources.includes=certs/test-key-rsa.key,certs/test-key-rsa-cert.pub
\ No newline at end of file
diff --git
a/integration-tests/mina-sftp/src/main/resources/certs/generate-certificates.sh
b/integration-tests/mina-sftp/src/main/resources/certs/generate-certificates.sh
deleted file mode 100755
index 8780f21483..0000000000
---
a/integration-tests/mina-sftp/src/main/resources/certs/generate-certificates.sh
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/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/main/resources/certs/test-key-rsa-cert.pub
b/integration-tests/mina-sftp/src/main/resources/certs/test-key-rsa-cert.pub
deleted file mode 100644
index ba21c6c28b..0000000000
--- a/integration-tests/mina-sftp/src/main/resources/certs/test-key-rsa-cert.pub
+++ /dev/null
@@ -1 +0,0 @@
[email protected]
AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgwsB0wUJYWF7WQayMI3EFz63+rzdGxxmy6QmkXXigkbcAAAADAQABAAABAQCd2V7v8ELetZfmObUn3zP28B44AhcDnOdZHErgl1fe6e2Jmnja4BhdtZAG+XZEmKwlQnWNkRJfDs1/ryfP8xthcZIlklEb/6F2D2zmot5BnY6zzL6XWPtuTny1Ym7iah6KSPv9vS9nc2wcEA9BFu+CYHHWJYskv/PE/hwebae/upKafppCWJ97+Kdkc87Whsd1y2PxhhPPCbH/lOOOmzw2qTyxpYciHsr9NaBfoHRwvTWBdWjk6pYKtw+4gmWOmyAngOh9jcXeJ5pKUhWeJh5fmMrHL/mv/0DtrGQ2fhhrYZjIbkuha5EOFqurnXHjwwBz3Ey8JOhaF9UwQlCvOOWnAAAAAAAAAAAAAAA
[...]
diff --git
a/integration-tests/mina-sftp/src/main/resources/certs/test-key-rsa.key
b/integration-tests/mina-sftp/src/main/resources/certs/test-key-rsa.key
deleted file mode 100644
index 751cc308be..0000000000
--- a/integration-tests/mina-sftp/src/main/resources/certs/test-key-rsa.key
+++ /dev/null
@@ -1,27 +0,0 @@
------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/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
index 0a5be73756..153f421bae 100644
---
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
@@ -42,7 +42,6 @@ class MinaSftpTest {
@Test
void loadComponentMinaSftp() {
- /* A simple autogenerated test */
RestAssured.get("/mina-sftp/load/component/mina-sftp")
.then()
.statusCode(200);
diff --git
a/integration-tests/ssh/src/main/java/org/apache/camel/quarkus/component/ssh/it/SshRoutes.java
b/integration-tests/ssh/src/main/java/org/apache/camel/quarkus/component/ssh/it/SshRoutes.java
index 75b51ffc7e..e70b336dc6 100644
---
a/integration-tests/ssh/src/main/java/org/apache/camel/quarkus/component/ssh/it/SshRoutes.java
+++
b/integration-tests/ssh/src/main/java/org/apache/camel/quarkus/component/ssh/it/SshRoutes.java
@@ -17,12 +17,9 @@
package org.apache.camel.quarkus.component.ssh.it;
import java.nio.file.Paths;
-import java.security.Security;
-import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Named;
-import net.i2p.crypto.eddsa.EdDSASecurityProvider;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.ssh.SshComponent;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
@@ -41,11 +38,6 @@ public class SshRoutes extends RouteBuilder {
@ConfigProperty(name = "ssh.password")
String password;
- @PostConstruct
- public void init() {
- Security.addProvider(new EdDSASecurityProvider());
- }
-
@Override
public void configure() throws Exception {
// Route without SSL