4

I have a camel application which connects to SFTP server using SSH Private key. If i read the id_rsa file from a file, i was able to connect to the server. As given in this example, it is working with loading from a file.

registry.put("privateKey", getBytesFromFile("./src/main/resources/id_rsa"));

private byte[] getBytesFromFile(String filename) throws IOException {
    InputStream input;
    input = new FileInputStream(new File(filename));
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    IOHelper.copyAndCloseInput(input, output);
    return output.toByteArray();
}

I want to provide the private key dynamically at runtime. That means in application.yaml in spring-boot application, which will be replaced by docker container environment variables.

@Value("${sftp_private_key}")
private String privateKey;

registry.put("privateKey", privateKey.getBytes());

I am getting this exception

org.apache.camel.component.file.GenericFileOperationFailedException: Cannot connect to sftp://<user>@<sftp_server>:22
    at org.apache.camel.component.file.remote.SftpOperations.connect(SftpOperations.java:146) ~[camel-ftp-2.19.1.jar:2.19.1]
    at org.apache.camel.component.file.remote.RemoteFileConsumer.connectIfNecessary(RemoteFileConsumer.java:203) [camel-ftp-2.19.1.jar:2.19.1]
    at org.apache.camel.component.file.remote.RemoteFileConsumer.recoverableConnectIfNecessary(RemoteFileConsumer.java:171) [camel-ftp-2.19.1.jar:2.19.1]
    at org.apache.camel.component.file.remote.RemoteFileConsumer.prePollCheck(RemoteFileConsumer.java:59) [camel-ftp-2.19.1.jar:2.19.1]
    at org.apache.camel.component.file.GenericFileConsumer.poll(GenericFileConsumer.java:110) [camel-core-2.19.1.jar:2.19.1]
    at org.apache.camel.impl.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:174) [camel-core-2.19.1.jar:2.19.1]
    at org.apache.camel.impl.ScheduledPollConsumer.run(ScheduledPollConsumer.java:101) [camel-core-2.19.1.jar:2.19.1]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_121]
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_121]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_121]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]
Caused by: com.jcraft.jsch.JSchException: invalid privatekey: [B@5e200110
    at com.jcraft.jsch.KeyPair.load(KeyPair.java:757) ~[jsch-0.1.54.jar:na]
    at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:46) ~[jsch-0.1.54.jar:na]
    at com.jcraft.jsch.JSch.addIdentity(JSch.java:442) ~[jsch-0.1.54.jar:na]
    at org.apache.camel.component.file.remote.SftpOperations.createSession(SftpOperations.java:220) ~[camel-ftp-2.19.1.jar:2.19.1]
    at org.apache.camel.component.file.remote.SftpOperations.connect(SftpOperations.java:115) ~[camel-ftp-2.19.1.jar:2.19.1]
    ... 13 common frames omitted

After some debugging, i understand that its an issue with \n characters. If i read from a file the private key contains \n characters. But if i read from .yaml file, it does not have \n characters. I replaced all new lines into \n characters and converted it into single line. Still it's not working.

How can i provide this value in application.yaml which is equivalent to reading from that file?

Gangaraju
  • 4,406
  • 9
  • 45
  • 77
  • "invalid privatekey: [B@5e200110" The "[B@5e200110" is the string returned by the byte array's `toString()` method. Somewhere, your code is calling `toString()` on your byte array, when it should probably be constructing a string from the bytes instead. – Kenster Jul 31 '17 at 14:04

2 Answers2

12

As explained here, it is working with |

Example application.yaml:

sftp_private_key: |
                  ----BEGIN RSA PRIVATE KEY-----
                     Remaining part of key
                  -----END RSA PRIVATE KEY-----
Gangaraju
  • 4,406
  • 9
  • 45
  • 77
  • 1
    what if we use properties file? – Kalpesh Soni Oct 18 '18 at 21:40
  • If you are not able to put the private key directly into the yml file for security concerns, this alternative solution here might be useful for getting the key from an environment variable, https://stackoverflow.com/a/69904488/2200690 – Suketu Bhuta Nov 09 '21 at 21:59
-3

Maybe it will be helpful:

Here is a part of my code which read PublicKey from given path:

import com.google.common.io.BaseEncoding;
import java.io.DataInputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

public class PublicKeyReader {

    public static PublicKey get(String filename)
            throws Exception {

        InputStream is = PublicKeyReader.class.getResourceAsStream("/keystore/" + filename);

        DataInputStream dis = new DataInputStream(is);

        byte[] keyBytes = new byte[is.available()];
        dis.readFully(keyBytes);
        dis.close();

        String base64 = new String(keyBytes);
        X509EncodedKeySpec spec
                = new X509EncodedKeySpec(BaseEncoding.base64().decode(base64));
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(spec);
    }
}
Martinus_
  • 160
  • 1
  • 3
  • 13