This is an automated email from the ASF dual-hosted git repository. jamesnetherton pushed a commit to branch 3.33.x in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
commit 2936b358bccc7e504e9d1c1de1cf5178a5c7a2b9 Author: Gaelle Fournier <[email protected]> AuthorDate: Thu Apr 16 16:00:11 2026 +0200 feat: Add Camel SFTP certificate based authentication --- .../component/ftp/deployment/FtpProcessor.java | 20 ++ .../support/sftp/SftpHostCertTestResource.java | 170 ++++++++++++++ .../test/support/sftp/SftpTestResource.java | 25 +- .../quarkus/component/sftp/it/SftpResource.java | 252 +++++++++++++++++++++ .../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 +++ .../quarkus/component/sftp/it/SftpHostCertIT.java | 18 +- .../it/{SftpTest.java => SftpHostCertTest.java} | 50 ++-- .../camel/quarkus/component/sftp/it/SftpTest.java | 82 +++++++ 14 files changed, 742 insertions(+), 38 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..95ba66fac3 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 @@ -18,6 +18,7 @@ package org.apache.camel.quarkus.component.ftp.deployment; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; class FtpProcessor { @@ -27,4 +28,23 @@ class FtpProcessor { FeatureBuildItem feature() { return new FeatureBuildItem(FEATURE); } + + @BuildStep + ReflectiveClassBuildItem registerJSchCertificateClasses() { + // JSch OpenSSH certificate support classes for @cert-authority parsing in known_hosts + // The quarkus-jsch reflection config is missing several classes that JSch loads dynamically. + return ReflectiveClassBuildItem.builder( + "com.jcraft.jsch.KeyPairRSA", + "com.jcraft.jsch.KeyPairECDSA", + "com.jcraft.jsch.KeyPairEd25519", + "com.jcraft.jsch.KeyPairEd448", + "com.jcraft.jsch.KeyPairDSA", + "com.jcraft.jsch.KeyPairEdDSA", + "com.jcraft.jsch.KeyPairPKCS8", + "com.jcraft.jsch.jce.SignatureEd25519", + "com.jcraft.jsch.IdentityFile", + "com.jcraft.jsch.LocalIdentityRepository", + "com.jcraft.jsch.jce.KeyPairGenEdDSA") + .build(); + } } 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 new file mode 100644 index 0000000000..1f45db0327 --- /dev/null +++ b/integration-tests-support/sftp/src/main/java/org/apache/camel/quarkus/test/support/sftp/SftpHostCertTestResource.java @@ -0,0 +1,170 @@ +/* + * 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.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.Map; + +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.jboss.logging.Logger; + +/** + * SFTP test resource that presents host certificates for host certificate verification testing. + * This is separate from SftpTestResource to avoid interfering with other tests. + */ +public class SftpHostCertTestResource implements QuarkusTestResourceLifecycleManager { + private static final Logger LOGGER = Logger.getLogger(SftpHostCertTestResource.class); + + private SshServer sshServer; + private Path sftpHome; + + @Override + public Map<String, String> start() { + try { + final int port = AvailablePortFinder.getNextAvailable(); + + 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); + } + } + + @Override + public void stop() { + try { + if (sshServer != null) { + sshServer.stop(); + LOGGER.info("SFTP server with host certificate stopped"); + } + } catch (Exception e) { + LOGGER.warn("Failed to stop SFTP server", 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); + } + }); + } + } catch (Exception e) { + LOGGER.warnf("Failed to delete sftp home: %s, %s", sftpHome, e); + } + + AvailablePortFinder.releaseReservedPorts(); + } + + /** + * Creates a KeyPairProvider that wraps the host private key with the OpenSSH host certificate. + */ + private static KeyPairProvider createHostCertKeyPairProvider() { + 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"); + } + + // 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); + + } catch (Exception e) { + throw new RuntimeException("Failed to load host certificate key pair", 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 1a1994d1c6..784daf8293 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 @@ -23,13 +23,18 @@ 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.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; @@ -68,7 +73,25 @@ public class SftpTestResource implements QuarkusTestResourceLifecycleManager { sshServer.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory())); sshServer.setCommandFactory(new ScpCommandFactory()); sshServer.setPasswordAuthenticator((username, password, session) -> true); - sshServer.setPublickeyAuthenticator((username, key, session) -> true); + + // 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; + }); + + // 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); + sshServer.setFileSystemFactory(factory); sshServer.start(); 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 a87d8a358a..0a890acd93 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,6 +16,7 @@ */ package org.apache.camel.quarkus.component.sftp.it; +import java.io.InputStream; import java.net.URI; import jakarta.enterprise.context.ApplicationScoped; @@ -30,9 +31,12 @@ import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import org.apache.camel.CamelContext; import org.apache.camel.ConsumerTemplate; import org.apache.camel.Exchange; import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.file.remote.SftpConfiguration; +import org.apache.camel.component.file.remote.SftpEndpoint; @Path("/sftp") @ApplicationScoped @@ -40,6 +44,9 @@ public class SftpResource { private static final long TIMEOUT_MS = 1000; + @Inject + CamelContext context; + @Inject ProducerTemplate producerTemplate; @@ -87,4 +94,249 @@ public class SftpResource { TIMEOUT_MS, String.class); } + + @Path("/certificate/create/{fileName}") + @POST + @Consumes(MediaType.TEXT_PLAIN) + public Response createFileWithCertificate(@PathParam("fileName") String fileName, String fileContent) + throws Exception { + producerTemplate.sendBodyAndHeader( + "sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub", + fileContent, + Exchange.FILE_NAME, fileName); + return Response + .created(new URI("https://camel.apache.org/")) + .build(); + } + + @Path("/certificate/get/{fileName}") + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getFileWithCertificate(@PathParam("fileName") String fileName) { + return consumerTemplate.receiveBody( + "sftp://admin@localhost:{{camel.sftp.test-port}}/sftp?privateKeyUri=certs/test-key-rsa.key&certUri=certs/test-key-rsa-cert.pub&localWorkDirectory=target&fileName=" + + fileName, + TIMEOUT_MS, + String.class); + } + + @Path("/certificateFile/create/{fileName}") + @POST + @Consumes(MediaType.TEXT_PLAIN) + 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", + fileContent, + Exchange.FILE_NAME, fileName); + return Response + .created(new URI("https://camel.apache.org/")) + .build(); + } + + @Path("/certificateFile/get/{fileName}") + @GET + @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=" + + fileName, + TIMEOUT_MS, + String.class); + } + + @Path("/certificateBytes/create/{fileName}") + @POST + @Consumes(MediaType.TEXT_PLAIN) + public Response createFileWithCertificateBytes(@PathParam("fileName") String fileName, String fileContent) + throws Exception { + + 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(); + } + } + + @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); + } + } + + @Path("/certificateWithCaAlgorithms/create/{fileName}") + @POST + @Consumes(MediaType.TEXT_PLAIN) + 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", + fileContent, + Exchange.FILE_NAME, fileName); + return Response + .created(new URI("https://camel.apache.org/")) + .build(); + } + + @Path("/certificateWithCaAlgorithms/get/{fileName}") + @GET + @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=" + + fileName, + TIMEOUT_MS, + String.class); + } + + @Path("/hostcert/create/{fileName}") + @POST + @Consumes(MediaType.TEXT_PLAIN) + public Response createFileWithHostCertVerification(@PathParam("fileName") String fileName, String fileContent) + throws Exception { + String knownHostsFile = createHostCaKnownHostsFile(); + 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); + return Response + .created(new URI("https://camel.apache.org/")) + .build(); + } + + @Path("/hostcert/get/{fileName}") + @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); + } + + @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); + return Response.noContent().build(); + } + + @Path("/hostcertWithAlgorithms/create/{fileName}") + @POST + @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); + return Response + .created(new URI("https://camel.apache.org/")) + .build(); + } + + @Path("/hostcertWithAlgorithms/get/{fileName}") + @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); + } + + @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); + return Response.noContent().build(); + } + + /** + * Creates a known_hosts file with @cert-authority entry for the host CA. + * This allows the client to verify the server's host certificate. + */ + 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(); + 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); + + return knownHostsPath.toAbsolutePath().toString(); + } } diff --git a/integration-tests/ftp/src/main/resources/application.properties b/integration-tests/ftp/src/main/resources/application.properties index 8fcaf03aa5..25bfaf1cfa 100644 --- a/integration-tests/ftp/src/main/resources/application.properties +++ b/integration-tests/ftp/src/main/resources/application.properties @@ -17,3 +17,5 @@ # 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 new file mode 100755 index 0000000000..8e9079b3e7 --- /dev/null +++ b/integration-tests/ftp/src/main/resources/certs/generate-certificates.sh @@ -0,0 +1,104 @@ +#!/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 new file mode 100644 index 0000000000..d0a10f97cf --- /dev/null +++ b/integration-tests/ftp/src/main/resources/certs/host-ca.pub @@ -0,0 +1 @@ +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 new file mode 100644 index 0000000000..79c92a7e12 --- /dev/null +++ b/integration-tests/ftp/src/main/resources/certs/host-key-rsa-cert.pub @@ -0,0 +1 @@ [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 new file mode 100644 index 0000000000..a8cff6531f --- /dev/null +++ b/integration-tests/ftp/src/main/resources/certs/host-key-rsa.key @@ -0,0 +1,27 @@ +-----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 new file mode 100644 index 0000000000..fa138337ce --- /dev/null +++ b/integration-tests/ftp/src/main/resources/certs/test-key-rsa-cert.pub @@ -0,0 +1 @@ [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 new file mode 100644 index 0000000000..ac6440d774 --- /dev/null +++ b/integration-tests/ftp/src/main/resources/certs/test-key-rsa.key @@ -0,0 +1,27 @@ +-----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/extensions/ftp/deployment/src/main/java/org/apache/camel/quarkus/component/ftp/deployment/FtpProcessor.java b/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpHostCertIT.java similarity index 69% copy from extensions/ftp/deployment/src/main/java/org/apache/camel/quarkus/component/ftp/deployment/FtpProcessor.java copy to integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpHostCertIT.java index 218c96e6f6..2562a13d33 100644 --- a/extensions/ftp/deployment/src/main/java/org/apache/camel/quarkus/component/ftp/deployment/FtpProcessor.java +++ b/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpHostCertIT.java @@ -14,17 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.quarkus.component.ftp.deployment; +package org.apache.camel.quarkus.component.sftp.it; -import io.quarkus.deployment.annotations.BuildStep; -import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.test.junit.QuarkusIntegrationTest; -class FtpProcessor { - - private static final String FEATURE = "camel-ftp"; - - @BuildStep - FeatureBuildItem feature() { - return new FeatureBuildItem(FEATURE); - } +/** + * Integration tests for SFTP host certificate verification in native mode. + */ +@QuarkusIntegrationTest +class SftpHostCertIT extends SftpHostCertTest { } diff --git a/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java b/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpHostCertTest.java similarity index 59% copy from integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java copy to integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpHostCertTest.java index 58e2e8aede..45745414f1 100644 --- a/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java +++ b/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpHostCertTest.java @@ -22,8 +22,9 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.smallrye.certs.Format; import io.smallrye.certs.junit5.Certificate; +import org.apache.camel.quarkus.test.DisabledIfFipsMode; import org.apache.camel.quarkus.test.support.certificate.TestCertificates; -import org.apache.camel.quarkus.test.support.sftp.SftpTestResource; +import org.apache.camel.quarkus.test.support.sftp.SftpHostCertTestResource; import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.is; @@ -34,50 +35,47 @@ import static org.hamcrest.CoreMatchers.is; @Certificate(name = "ftp", formats = { Format.PKCS12 }, password = "password") }) @QuarkusTest -@QuarkusTestResource(SftpTestResource.class) -class SftpTest { +@QuarkusTestResource(SftpHostCertTestResource.class) +class SftpHostCertTest { @Test - public void testSftpComponent() { - // Create a new file on the SFTP server + @DisabledIfFipsMode + public void testHostCertificateVerification() { RestAssured.given() .contentType(ContentType.TEXT) - .body("Hello Camel Quarkus SFTP") - .post("/sftp/create/hello.txt") + .body("Host certificate verification test") + .post("/sftp/hostcert/create/hostcert-test.txt") .then() .statusCode(201); - // Read file back from the SFTP server - RestAssured.get("/sftp/get/hello.txt") + RestAssured.get("/sftp/hostcert/get/hostcert-test.txt") .then() .statusCode(200) - .body(is("Hello Camel Quarkus SFTP")); + .body(is("Host certificate verification test")); - // Rename the file to {file}.done - RestAssured.put("/sftp/moveToDoneFile/hello.txt") + RestAssured.delete("/sftp/hostcert/delete/hostcert-test.txt") .then() .statusCode(204); + } - // Check that the file is no more present in its initial place - RestAssured.get("/sftp/get/hello.txt") + @Test + @DisabledIfFipsMode + public void testHostCertificateVerificationWithCaSignatureAlgorithms() { + // Test host certificate verification with specific CA signature algorithms + RestAssured.given() + .contentType(ContentType.TEXT) + .body("Host cert with CA algorithms test") + .post("/sftp/hostcertWithAlgorithms/create/hostcert-algo-test.txt") .then() - .statusCode(204); + .statusCode(201); - // Check that the file has been renamed to {file}.done - RestAssured.get("/sftp/get/hello.txt.done") + RestAssured.get("/sftp/hostcertWithAlgorithms/get/hostcert-algo-test.txt") .then() .statusCode(200) - .body(is("Hello Camel Quarkus SFTP")); + .body(is("Host cert with CA algorithms test")); - // Delete the {file}.done file - RestAssured.delete("/sftp/delete/hello.txt.done") - .then() - .statusCode(204); - - // Check that {file}.done file has been deleted from the SFTP server - RestAssured.get("/sftp/get/hello.txt.done") + RestAssured.delete("/sftp/hostcertWithAlgorithms/delete/hostcert-algo-test.txt") .then() .statusCode(204); } - } diff --git a/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java b/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java index 58e2e8aede..9d6186e9f7 100644 --- a/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java +++ b/integration-tests/ftp/src/test/java/org/apache/camel/quarkus/component/sftp/it/SftpTest.java @@ -22,6 +22,7 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.smallrye.certs.Format; import io.smallrye.certs.junit5.Certificate; +import org.apache.camel.quarkus.test.DisabledIfFipsMode; import org.apache.camel.quarkus.test.support.certificate.TestCertificates; import org.apache.camel.quarkus.test.support.sftp.SftpTestResource; import org.junit.jupiter.api.Test; @@ -38,6 +39,7 @@ import static org.hamcrest.CoreMatchers.is; class SftpTest { @Test + @DisabledIfFipsMode public void testSftpComponent() { // Create a new file on the SFTP server RestAssured.given() @@ -80,4 +82,84 @@ class SftpTest { .statusCode(204); } + @Test + @DisabledIfFipsMode + void testCertificateAuthentication() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body("Certificate authentication test") + .post("/sftp/certificate/create/certificate-test.txt") + .then() + .statusCode(201); + + RestAssured.get("/sftp/certificate/get/certificate-test.txt") + .then() + .statusCode(200) + .body(is("Certificate authentication test")); + + RestAssured.delete("/sftp/delete/certificate-test.txt") + .then() + .statusCode(204); + } + + @Test + @DisabledIfFipsMode + void testCertificateAuthenticationWithFile() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body("Certificate file authentication test") + .post("/sftp/certificateFile/create/certificate-file-test.txt") + .then() + .statusCode(201); + + RestAssured.get("/sftp/certificateFile/get/certificate-file-test.txt") + .then() + .statusCode(200) + .body(is("Certificate file authentication test")); + + RestAssured.delete("/sftp/delete/certificate-file-test.txt") + .then() + .statusCode(204); + } + + @Test + @DisabledIfFipsMode + void testCertificateAuthenticationWithBytes() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body("Certificate bytes authentication test") + .post("/sftp/certificateBytes/create/certificate-bytes-test.txt") + .then() + .statusCode(201); + + RestAssured.get("/sftp/certificateBytes/get/certificate-bytes-test.txt") + .then() + .statusCode(200) + .body(is("Certificate bytes authentication test")); + + RestAssured.delete("/sftp/delete/certificate-bytes-test.txt") + .then() + .statusCode(204); + } + + @Test + @DisabledIfFipsMode + void testCertificateAuthenticationWithCaSignatureAlgorithms() { + RestAssured.given() + .contentType(ContentType.TEXT) + .body("Certificate with CA signature algorithms test") + .post("/sftp/certificateWithCaAlgorithms/create/certificate-ca-algo-test.txt") + .then() + .statusCode(201); + + RestAssured.get("/sftp/certificateWithCaAlgorithms/get/certificate-ca-algo-test.txt") + .then() + .statusCode(200) + .body(is("Certificate with CA signature algorithms test")); + + RestAssured.delete("/sftp/delete/certificate-ca-algo-test.txt") + .then() + .statusCode(204); + } + }
