0

I have to establish the SFTP connection within a Spring Boot app that runs from a WAR file. Before posting this I’ve tried the suggestions from the following threads:


The application is built as a WAR file, and I used the JSch library in order to establish the SFTP connection. The setup for this library implies usage of its addIdentity method, where the first argument/parameter should be the path to the Private Key file (the content is not passed directly).

If I run the app within and IDE, then the SFTP connection can be established and it works. But if I build the app as a WAR file, and I run it from that WAR file, then the SFTP connection cannot be established, because the Private Key file cannot be found.

I run the WAR file by executing this command within a CLI, from the location of that WAR file: java -jar test_sftp_in_war_file-0.0.1-SNAPSHOT.war

The Private Key file was added to the resources directory from the Spring Boot project.

This image contains the structure of the Private Key, generated using PuttyGen with RSA encryption (not OpenSSH)

This image contains the location of the Private Key within the generated WAR file

The passphrase is being read and passed correctly. The issue is the path to the Private Key file.


I use the pom.xml file, with the following Maven dependencies:

<?xml ...>
    <packaging>war</packaging>  <!-- to build the project as a WAR file -->
    <name>test_sftp_in_war_file</name>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- dependency for the JSch SFTP library -->
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-sftp</artifactId>
            <version>5.5.15</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

This is the code that I've tried:

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletContext;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.FileOutputStream;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import java.net.URL;
import java.net.URLDecoder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@Slf4j
@RequiredArgsConstructor
public class SftpExample {

    private final ServletContext context;

    public static void main(String[] args) throws JSchException, IOException {
        SpringApplication.run(TestSftpInWarFileApplication.class, args);
    }

    public void fetchData() throws Exception {
        JSch jSch = new JSch();
        Session session = null;
        Channel channel = null;
        ChannelSftp channelSftp = null;
        String devServerPath = "/proprietary/path/on/sftp/server";

        String filePath;

        Path tempFile = null;
        InputStream inputStream;
        FileOutputStream out;

        try {
            // version 1
            /** => the filePath is retrieved, but the error occurs when it is passed to the addIdentity method
             * >>> filePath = C:\projects\test_sftp_in_war_file\target\private-key.ppk
             * com.jcraft.jsch.JSchException: java.io.FileNotFoundException: C:\projects\test_sftp_in_war_file\target\private-key.ppk
             * (The system cannot find the file specified)
             *         at com.jcraft.jsch.KeyPair.load(KeyPair.java:543)
             *         at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40)
             *         at com.jcraft.jsch.JSch.addIdentity(JSch.java:406)
             *         at com.jcraft.jsch.JSch.addIdentity(JSch.java:387)
             *         at com.example.test_sftp_in_war_file.SftpExample.fetchData(SftpExample.java:172)
             */
            filePath = Paths.get("private-key.ppk").toAbsolutePath().toString();

            // version 2
            /** => the filePath is retrieved, but the error occurs when it is passed to the addIdentity method
             * >>> filePath = jar:file:/C:/projects/test_sftp_in_war_file/target/test_sftp_in_war_file-0.0.1-SNAPSHOT.war!/WEB-INF/classes!/private-key.ppk
             * com.jcraft.jsch.JSchException: java.io.FileNotFoundException: jar:file:\C:\projects\test_sftp_in_war_file\target\test_sftp_in_war_file-0.0.1-SNAPSHOT.war!\WEB-INF\classes!\private-key.ppk
             * (The filename, directory name, or volume label syntax is incorrect)
             *         at com.jcraft.jsch.KeyPair.load(KeyPair.java:543)
             *         at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40)
             *         at com.jcraft.jsch.JSch.addIdentity(JSch.java:406)
             *         at com.jcraft.jsch.JSch.addIdentity(JSch.java:387)
             *         at com.example.test_sftp_in_war_file.SftpExample.fetchData(SftpExample.java:162)
             */
            filePath = this.getClass().getClassLoader().getResource("private-key.ppk").toExternalForm();

            // version 3
            /** => the filePath is retrieved, but the error occurs when it is passed to the addIdentity method
             * >>> filePath = file:/C:/projects/test_sftp_in_war_file/target/classes/private-key.ppk
             * java.lang.NullPointerException: null
             *         at com.jcraft.jsch.Util.checkTilde(Util.java:489) ~[jsch-0.1.55.jar!/:na]
             *         at com.jcraft.jsch.Util.fromFile(Util.java:506) ~[jsch-0.1.55.jar!/:na]
             *         at com.jcraft.jsch.KeyPair.load(KeyPair.java:540) ~[jsch-0.1.55.jar!/:na]
             *         at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40) ~[jsch-0.1.55.jar!/:na]
             *         at com.jcraft.jsch.JSch.addIdentity(JSch.java:406) ~[jsch-0.1.55.jar!/:na]
             *         at com.jcraft.jsch.JSch.addIdentity(JSch.java:387) ~[jsch-0.1.55.jar!/:na]
             *         at com.example.test_sftp_in_war_file.SftpExample.fetchData(SftpExample.java:148)
             */
            File privateKeyFile = new ClassPathResource("private-key.ppk").getFile();   // getting the file content
            filePath = privateKeyFile.toURI().toString();

            // version 4 => read the content and generate a new temporary file, and pass the path to that temp file
            /** => this workaround works when running the local WAR, but does not run in the cloud environment
             * >>> filePath = C:\Users\USER\AppData\Local\Temp\private-key_3ca449c2-0ed1-459c-a2cd-70f51f4023eb2105597171450888881.ppk
             */
            inputStream = new ClassPathResource("private-key.ppk").getInputStream();
            tempFile = File.createTempFile("private_key_" + UUID.randomUUID().toString(), ".ppk").toPath();
            out = new FileOutputStream(tempFile.toFile());
            IOUtils.copy(inputStream, out);
            filePath = tempFile.toFile().getAbsolutePath();

            // version 5
            /** => the filePath is retrieved, but the error occurs when it is passed to the addIdentity method
             * >>> filePath = file:\C:\projects\test_sftp_in_war_file\target\test_sftp_in_war_file-0.0.1-SNAPSHOT.war*\WEB-INF\classes\private-key.ppk
             * com.jcraft.jsch.JSchException: java.io.FileNotFoundException: file:\C:\projects\test_sftp_in_war_file\target\test_sftp_in_war_file-0.0.1-SNAPSHOT.war*\WEB-INF\classes\private-key.ppk
             * (The filename, directory name, or volume label syntax is incorrect)
             *      at com.jcraft.jsch.KeyPair.load(KeyPair.java:543)
             *      at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40)
             *      at com.jcraft.jsch.JSch.addIdentity(JSch.java:406)
             *      at com.jcraft.jsch.JSch.addIdentity(JSch.java:387)
             *      at com.example.test_sftp_in_war_file.SftpExample.fetchData(SftpExample.java:95)
             */
            URL resourceUrl = context.getResource("/WEB-INF/classes/private-key.ppk");
            filePath = resourceUrl.getPath();

            // version 6
             * >>> filePath = sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@704b2127
             * com.jcraft.jsch.JSchException: java.io.FileNotFoundException: sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@704b2127
             * (The system cannot find the file specified)
             *      at com.jcraft.jsch.KeyPair.load(KeyPair.java:543)
             *      at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40)
             *      at com.jcraft.jsch.JSch.addIdentity(JSch.java:406)
             *      at com.jcraft.jsch.JSch.addIdentity(JSch.java:387)
             *      at com.example.test_sftp_in_war_file.SftpExample.fetchData(SftpExample.java:95)
             */
            filePath = getClass().getResourceAsStream("/WEB-INF/classes/private-key.ppk").toString();

            // version 7
            /** => the filePath is retrieved, but the error occurs when it is passed to the addIdentity method
             * >>> filePath = file:\C:\projects\test_sftp_in_war_file\target\test_sftp_in_war_file-0.0.1-SNAPSHOT.war!\WEB-INF\classes!\private-key.ppk
             * com.jcraft.jsch.JSchException: java.io.FileNotFoundException: file:\C:\projects\test_sftp_in_war_file\target\test_sftp_in_war_file-0.0.1-SNAPSHOT.war!\WEB-INF\classes!\private-key.ppk
             * (The filename, directory name, or volume label syntax is incorrect)
             *      at com.jcraft.jsch.KeyPair.load(KeyPair.java:543)
             *      at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40)
             *      at com.jcraft.jsch.JSch.addIdentity(JSch.java:406)
             *      at com.jcraft.jsch.JSch.addIdentity(JSch.java:387)
             *      at com.example.test_sftp_in_war_file.SftpExample.fetchData(SftpExample.java:95)
             */
            filePath = getClass().getClassLoader().getResource("private-key.ppk").getPath();

            // version 8
            /**
             * java.lang.NullPointerException: null
             *      at com.jcraft.jsch.Util.checkTilde(Util.java:489)
             *      at com.jcraft.jsch.Util.fromFile(Util.java:506)
             */
            filePath = SftpExample.class.getResource("private-key.ppk").getPath();

            // version 9
            /**
             * java.lang.NullPointerException: null
             *      at com.jcraft.jsch.Util.checkTilde(Util.java:489)
             *      at com.jcraft.jsch.Util.fromFile(Util.java:506)
             */
            filePath = URLDecoder.decode(SftpExample.class.getResource("private-key.ppk").getPath(), "UTF-8");   // Application run failed: java.lang.NullPointerException: null

            // version 10
            /**
             * java.lang.NullPointerException: null
             *      at com.jcraft.jsch.Util.checkTilde(Util.java:489)
             *      at com.jcraft.jsch.Util.fromFile(Util.java:506)
             */
//          filePath = context.getRealPath("/WEB-INF/classes/private-key.ppk");

            log.info(">>> filePath = " + filePath);
        } catch (NullPointerException e) {
            // throw new Exception("Could not be retrieved the path for this file: " + "private-key.ppk");
            log.error(Arrays.toString(e.getStackTrace()));
        }

        try {
            jSch.addIdentity(filePath, "passphrase_is_correct");   // the error is generated at this line
            session = jSch.getSession("username", "host", 22);  // this is where the connection should be established
            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");  // by default, say that we trust the specified server (to not be required to explicitly say that we trust it for each connection)
            session.setConfig(config);
            session.connect();
            channel = session.openChannel("sftp");
            channel.connect();
            channelSftp = (ChannelSftp) channel;

            // other operations that occur once the SFTP connection is established

            log.info(">>> the SFTP connection was established successfully");
        } catch (JSchException e) {
            e.printStackTrace();
        } finally {
            if (session != null && channel != null) {
                channel.disconnect();
                session.disconnect();
            }

            inputStream.close();
            out.close();
        }
    }

    @EventListener(ContextRefreshedEvent.class) // waits to be finished the Spring Context initialization
    public void run1() throws Exception {
        this.fetchData();
    }
}

This is the stack trace that was generated for version 5:

2023-01-03 17:19:32.413 ERROR 25960 --- [           main] o.s.boot.SpringApplication               : Application run failed
Bean [com.example.test_sftp_in_war_file.SftpExample]
Method [public void com.example.test_sftp_in_war_file.SftpExample throws java.lang.Exception]
Method [public void com.example.test_sftp_in_war_file.TestSftpInWarFileApplication.run1() throws java.lang.Exception]
Resolved arguments:

        at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:361) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:229) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:166) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:938) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.24.jar!/:5.3.24]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.7.jar!/:2.7.7]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) ~[spring-boot-2.7.7.jar!/:2.7.7]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.7.jar!/:2.7.7]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) ~[spring-boot-2.7.7.jar!/:2.7.7]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303) ~[spring-boot-2.7.7.jar!/:2.7.7]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292) ~[spring-boot-2.7.7.jar!/:2.7.7]
        at com.example.test_sftp_in_war_file.TestSftpInWarFileApplication.main(TestSftpInWarFileApplication.java:42) ~[classes!/:0.0.1-SNAPSHOT]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[test_sftp_in_war_file-0.0.1-SNAPSHOT.war:0.0.1-SNAPSHOT]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[test_sftp_in_war_file-0.0.1-SNAPSHOT.war:0.0.1-SNAPSHOT]
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[test_sftp_in_war_file-0.0.1-SNAPSHOT.war:0.0.1-SNAPSHOT]
        at org.springframework.boot.loader.WarLauncher.main(WarLauncher.java:59) ~[test_sftp_in_war_file-0.0.1-SNAPSHOT.war:0.0.1-SNAPSHOT]
Caused by: java.lang.Exception: Could not be retrieved the path for this file: private-key.ppk
        at com.example.test_sftp_in_war_file.TestSftpInWarFileApplication.fetchData(TestSftpInWarFileApplication.java:86) ~[classes!/:0.0.1-SNAPSHOT]
        at com.example.test_sftp_in_war_file.TestSftpInWarFileApplication.run1(TestSftpInWarFileApplication.java:118) ~[classes!/:0.0.1-SNAPSHOT]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
        at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:344) ~[spring-context-5.3.24.jar!/:5.3.24]
        ... 24 common frames omitted

This is the stack trace generated for version 6 and 7:

2023-01-04 11:09:30.661  INFO 29328 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8090 (http) with context path ''
2023-01-04 11:09:30.670  INFO 29328 --- [           main] c.e.t.TestSftpInWarFileApplication       : >>> filePath = sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@7cc9ce8
com.jcraft.jsch.JSchException: java.io.FileNotFoundException: sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@7cc9ce8 (The system cannot find the file specified)
        at com.jcraft.jsch.KeyPair.load(KeyPair.java:543)
        at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:40)
        at com.jcraft.jsch.JSch.addIdentity(JSch.java:406)
        at com.jcraft.jsch.JSch.addIdentity(JSch.java:387)
        at com.example.test_sftp_in_war_file.TestSftpInWarFileApplication.fetchData(TestSftpInWarFileApplication.java:90)
        at com.example.test_sftp_in_war_file.TestSftpInWarFileApplication.run1(TestSftpInWarFileApplication.java:118)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:344)
        at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:229)
        at org.springframework.context.event.ApplicationListenerMethodAdapter.onApplicationEvent(ApplicationListenerMethodAdapter.java:166)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378)
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:938)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1303)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1292)
        at com.example.test_sftp_in_war_file.TestSftpInWarFileApplication.main(TestSftpInWarFileApplication.java:42)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.WarLauncher.main(WarLauncher.java:59)
Caused by: java.io.FileNotFoundException: sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@7cc9ce8 (The system cannot find the file specified)
        at java.base/java.io.FileInputStream.open0(Native Method)
        at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
        at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
        at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112)
        at com.jcraft.jsch.Util.fromFile(Util.java:508)
        at com.jcraft.jsch.KeyPair.load(KeyPair.java:540)
        ... 34 more

  • Here you're swallowing your exception by rethrowing a generic one `throw new Exception("Could not be retrieved the path for this file: " + "private-key.ppk");`. What happens if, instead, you let your various attempts run? Do they all throw an exception that actually says they can't find the file? – Federico klez Culloca Jan 04 '23 at 09:40
  • 2
    Imo you are overcomplicating the question. You seem to have a problem with retrieving a file from the resources. Nothing to do with SFTP connection. You are scaring away those who know about the "resources", but do not know anything about "SFTP". Consider narrowing down the question (see [mcve]). – Martin Prikryl Jan 04 '23 at 09:41
  • 1
    You are trying to get a path that points into the war archive. Unless the container explodes the archive (and it is not required to do that) there may be no file, it could just be an entry in the war file. I would suggest reading the content (getResourceAsStream) and copying it to a file with a known path. Then you can use that file with JSch. Just take care to put the file somewhere where it is safe, i.e. not everybody with access to the server can read the secret key. You could make that folder location a configuration option. – ewramner Jan 04 '23 at 10:54
  • 2
    @ewramner Jsch can [read the key from memory](https://stackoverflow.com/q/33637481/850848). So if one can access the "resource as stream", one does not have to store the resource to a (temporary) file to use it in JSch. – Martin Prikryl Jan 04 '23 at 11:55
  • @FedericoklezCulloca when I tested a specific code snippet, I commented out the other versions. I've edited the question and added the stack traces with the specific errors for each version. – Pop Alexandru Jan 04 '23 at 12:00
  • 3
    @MartinPrikryl in that case the solution would be to read the resource as a stream (which really should work - there are tons of examples reading files from the class path) and pass it as bytes rather than as a path. Much better. – ewramner Jan 04 '23 at 12:09
  • @MartinPrikryl the retrieval of the file path works in most versions. The errors are thrown when the path is passed to the `addIdentity` method within JSch library. Because of this, I was thinking that it would be helpful to present the entire context. I've added the trimmed-down stack traces to each code snippet. Thank you very much for the last suggestion. – Pop Alexandru Jan 04 '23 at 12:11
  • @ewramner thank you very much for the suggestion. I tried something similar in version 4, where I read the content of the Private Key, then I create a Temporary file, and I pass to the `addIdentity` method the path to that temp file. This works locally, but I was thinking that there is another solution, to avoid this workaround. – Pop Alexandru Jan 04 '23 at 12:12
  • 1
    I will echo the suggestion to NOT create a temporary file. Read the data into memory using "resource as a stream", and avoid little bits of private key information being copied around where it needs to be cleaned up later. – JonathanDavidArndt Jan 04 '23 at 14:26

0 Answers0