Updated Branches: refs/heads/master 0afe60315 -> 2194a4de2
CAMEL-6502 Allow usage of Java KeyPair for SSH public key authentication in SFTP with thanks to Stephan Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/2194a4de Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/2194a4de Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/2194a4de Branch: refs/heads/master Commit: 2194a4de229aed8b02ee187fec92ef8a81b1d2ce Parents: 0afe603 Author: Willem Jiang <ningji...@apache.org> Authored: Tue Jul 2 17:33:46 2013 +0800 Committer: Willem Jiang <ningji...@apache.org> Committed: Tue Jul 2 17:33:46 2013 +0800 ---------------------------------------------------------------------- .../file/remote/DSAKeyPairIdentity.java | 228 +++++++++++++++++++ .../file/remote/RSAKeyPairIdentity.java | 146 ++++++++++++ .../file/remote/SftpConfiguration.java | 10 + .../component/file/remote/SftpOperations.java | 21 ++ .../remote/sftp/SftpKeyPairDSAConsumeTest.java | 90 ++++++++ .../remote/sftp/SftpKeyPairRSAConsumeTest.java | 90 ++++++++ 6 files changed, 585 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/2194a4de/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/DSAKeyPairIdentity.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/DSAKeyPairIdentity.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/DSAKeyPairIdentity.java new file mode 100644 index 0000000..fa5cf11 --- /dev/null +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/DSAKeyPairIdentity.java @@ -0,0 +1,228 @@ +/** + * 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.component.file.remote; + +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; + +import com.jcraft.jsch.Identity; +import com.jcraft.jsch.JSchException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DSAKeyPairIdentity implements Identity { + private static final String ALGORITHM_TYPE = "ssh-dss"; + private final transient Logger log = LoggerFactory.getLogger(getClass()); + private KeyPair keyPair; + private String name; + + public DSAKeyPairIdentity(String name, KeyPair keyPair) { + this.name = name; + this.keyPair = keyPair; + } + + @Override + public boolean setPassphrase(byte[] passphrase) throws JSchException { + return true; + } + + @Override + public byte[] getPublicKeyBlob() { + DSAPublicKey publicKey = (DSAPublicKey) keyPair.getPublic(); + byte[] sshDss = ALGORITHM_TYPE.getBytes(); + + DSAParams dsaParams = publicKey.getParams(); + byte[] pArray = dsaParams.getP().toByteArray(); + byte[] qArray = dsaParams.getQ().toByteArray(); + byte[] gArray = dsaParams.getG().toByteArray(); + byte[] yArray = publicKey.getY().toByteArray(); + + byte[] result = new byte[sshDss.length + 4 + pArray.length + 4 + qArray.length + 4 + gArray.length + 4 + yArray.length + 4]; + int index = 0; + + byte[] intAsByteArray = ByteBuffer.allocate(4).putInt(sshDss.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(sshDss, 0, result, index, sshDss.length); + index += sshDss.length; + + intAsByteArray = ByteBuffer.allocate(4).putInt(pArray.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(pArray, 0, result, index, pArray.length); + index += pArray.length; + + intAsByteArray = ByteBuffer.allocate(4).putInt(qArray.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(qArray, 0, result, index, qArray.length); + index += qArray.length; + + intAsByteArray = ByteBuffer.allocate(4).putInt(gArray.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(gArray, 0, result, index, gArray.length); + index += gArray.length; + + intAsByteArray = ByteBuffer.allocate(4).putInt(yArray.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(yArray, 0, result, index, yArray.length); + + return result; + } + + @Override + public byte[] getSignature(byte[] data) { + try { + PrivateKey prvKey = (PrivateKey) keyPair.getPrivate(); + Signature sig; + sig = Signature.getInstance("SHA1withDSA"); + sig.initSign(prvKey); + sig.update(data); + byte[] sshDss = ALGORITHM_TYPE.getBytes(); + byte[] signature = sig.sign(); + + signature = convertDERToP1363(signature); + + byte[] result = new byte[sshDss.length + 4 + signature.length + 4]; + int index = 0; + + byte[] intAsByteArray = ByteBuffer.allocate(4).putInt(sshDss.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(sshDss, 0, result, index, sshDss.length); + index += sshDss.length; + + intAsByteArray = ByteBuffer.allocate(4).putInt(signature.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(signature, 0, result, index, signature.length); + + return result; + } catch (NoSuchAlgorithmException e) { + log.error("Cannot sign", e); + } catch (InvalidKeyException e) { + log.error("Cannot sign", e); + } catch (SignatureException e) { + log.error("Cannot sign", e); + } + return null; + } + + /** + * "The signature on m is (r, s). Message m and (r, s) should be sent to the + * verifier. We need to observe that both r and s are 20 bytes, since a + * modular reduction is being performed (steps 2 and 5) using q, a 160 bit + * value. This will gain significance later when we begin verifying messages + * between Crypto++ and C# (which use the IEEE P1363 signature format) and + * Java (which uses a DER encoding of a signature)." [taken from <a href= + * "http://www.codeproject.com/Articles/25590/Cryptographic-Interoperability-Digital-Signatures" + * >Cryptographic Interoperability Digital Signatures</a>] + * + * @param sig + * signature in DER format + * @return signature in P1363 format; SEQUENCE ::= { r INTEGER, s INTEGER } + */ + private byte[] convertDERToP1363(byte[] sig) { + int index = 3; + int len = sig[index++] & 0xff; + + byte[] r = new byte[len]; + System.arraycopy(sig, index, r, 0, r.length); + index = index + len + 1; + + len = sig[index++] & 0xff; + byte[] s = new byte[len]; + System.arraycopy(sig, index, s, 0, s.length); + + byte[] p1363Signature = new byte[40]; + if (r.length > 21 || (r.length == 21 && r[0] != 0)) { + // Reject - signature verification failed + } else if (r.length == 21) { + // r[0] = 0 + // r[1]'s high bit *should* be set + System.arraycopy(r, 1, p1363Signature, 0, 20); + } else if (r.length == 20) { + // r[0]'s high bit *should not* be set + System.arraycopy(r, 0, p1363Signature, 0, 20); + } else { + // fewer than 20 bytes + len = r.length; + int off = 20 - len; + System.arraycopy(r, 0, p1363Signature, off, len); + } + + if (s.length > 21 || (s.length == 21 && s[0] != 0)) { + // Reject - signature verification failed + p1363Signature = new byte[0]; + } else if (s.length == 21) { + // s[0] = 0 + // s[1]'s high bit *should* be set + System.arraycopy(s, 1, p1363Signature, 20, 20); + } else if (s.length == 20) { + // s[0]'s high bit *should not* be set + System.arraycopy(s, 0, p1363Signature, 20, 20); + } else { + // fewer than 20 bytes + len = s.length; + int off = 40 - len; + System.arraycopy(s, 0, p1363Signature, off, len); + } + + return p1363Signature; + } + + @Override + public boolean decrypt() { + return true; + } + + @Override + public String getAlgName() { + return ALGORITHM_TYPE; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isEncrypted() { + return false; + } + + @Override + public void clear() { + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2194a4de/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RSAKeyPairIdentity.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RSAKeyPairIdentity.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RSAKeyPairIdentity.java new file mode 100644 index 0000000..fe5131b --- /dev/null +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/RSAKeyPairIdentity.java @@ -0,0 +1,146 @@ +/** + * 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.component.file.remote; + +import java.nio.ByteBuffer; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.RSAPublicKey; + +import com.jcraft.jsch.Identity; +import com.jcraft.jsch.JSchException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + + +public class RSAKeyPairIdentity implements Identity { + private static final String ALGORITHM_TYPE = "ssh-rsa"; + private final transient Logger log = LoggerFactory.getLogger(getClass()); + + private KeyPair keyPair; + private String name; + + public RSAKeyPairIdentity(String name, KeyPair keyPair) { + this.name = name; + this.keyPair = keyPair; + } + + @Override + public boolean setPassphrase(byte[] passphrase) throws JSchException { + return true; + } + + @Override + public byte[] getPublicKeyBlob() { + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + byte[] sshRsa = ALGORITHM_TYPE.getBytes(); + byte[] eArray = publicKey.getPublicExponent().toByteArray(); + byte[] nArray = publicKey.getModulus().toByteArray(); + + byte[] result = new byte[sshRsa.length + 4 + eArray.length + 4 + nArray.length + 4]; + int index = 0; + + byte[] intAsByteArray = ByteBuffer.allocate(4).putInt(sshRsa.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(sshRsa, 0, result, index, sshRsa.length); + index += sshRsa.length; + + intAsByteArray = ByteBuffer.allocate(4).putInt(eArray.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(eArray, 0, result, index, eArray.length); + index += eArray.length; + + intAsByteArray = ByteBuffer.allocate(4).putInt(nArray.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(nArray, 0, result, index, nArray.length); + + return result; + } + + @Override + public byte[] getSignature(byte[] data) { + PrivateKey prvKey = keyPair.getPrivate(); + Signature sig; + try { + sig = Signature.getInstance("SHA1withRSA"); + sig.initSign(prvKey); + sig.update(data); + byte[] sshRsa = ALGORITHM_TYPE.getBytes(); + byte[] signature = sig.sign(); + byte[] result = new byte[sshRsa.length + 4 + signature.length + 4]; + int index = 0; + + byte[] intAsByteArray = ByteBuffer.allocate(4).putInt(sshRsa.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(sshRsa, 0, result, index, sshRsa.length); + index += sshRsa.length; + + intAsByteArray = ByteBuffer.allocate(4).putInt(signature.length).array(); + System.arraycopy(intAsByteArray, 0, result, index, 4); + index += 4; + + System.arraycopy(signature, 0, result, index, signature.length); + + return result; + } catch (NoSuchAlgorithmException e) { + log.error("Cannot sign", e); + } catch (InvalidKeyException e) { + log.error("Cannot sign", e); + } catch (SignatureException e) { + log.error("Cannot sign", e); + } + return null; + } + + @Override + public boolean decrypt() { + return true; + } + + @Override + public String getAlgName() { + return ALGORITHM_TYPE; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean isEncrypted() { + return false; + } + + @Override + public void clear() { + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2194a4de/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java index ebefc42..4569859 100644 --- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpConfiguration.java @@ -17,6 +17,7 @@ package org.apache.camel.component.file.remote; import java.net.URI; +import java.security.KeyPair; /** * Secure FTP configuration @@ -31,6 +32,7 @@ public class SftpConfiguration extends RemoteFileConfiguration { private String privateKeyUri; private byte[] privateKey; private String privateKeyPassphrase; + private KeyPair keyPair; private String strictHostKeyChecking = "no"; private int serverAliveInterval; private int serverAliveCountMax = 1; @@ -119,6 +121,14 @@ public class SftpConfiguration extends RemoteFileConfiguration { this.privateKeyPassphrase = privateKeyFilePassphrase; } + public KeyPair getKeyPair() { + return keyPair; + } + + public void setKeyPair(KeyPair keyPair) { + this.keyPair = keyPair; + } + public String getStrictHostKeyChecking() { return strictHostKeyChecking; } http://git-wip-us.apache.org/repos/asf/camel/blob/2194a4de/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java index a7ad773..cdf6e05 100644 --- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java @@ -24,6 +24,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.security.KeyPair; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; @@ -203,6 +208,22 @@ public class SftpOperations implements RemoteFileOperations<ChannelSftp.LsEntry> } } + if (sftpConfig.getKeyPair() != null) { + LOG.debug("Using private key information from key pair"); + KeyPair keyPair = sftpConfig.getKeyPair(); + if (keyPair.getPrivate() != null && keyPair.getPublic() != null) { + if (keyPair.getPrivate() instanceof RSAPrivateKey && keyPair.getPublic() instanceof RSAPublicKey) { + jsch.addIdentity(new RSAKeyPairIdentity("ID", keyPair), null); + } else if (keyPair.getPrivate() instanceof DSAPrivateKey && keyPair.getPublic() instanceof DSAPublicKey) { + jsch.addIdentity(new DSAKeyPairIdentity("ID", keyPair), null); + } else { + LOG.warn("Only RSA and DSA key pairs are supported"); + } + } else { + LOG.warn("PrivateKey and PublicKey in the KeyPair must be filled"); + } + } + if (isNotEmpty(sftpConfig.getKnownHostsFile())) { LOG.debug("Using knownhosts file: {}", sftpConfig.getKnownHostsFile()); jsch.setKnownHosts(sftpConfig.getKnownHostsFile()); http://git-wip-us.apache.org/repos/asf/camel/blob/2194a4de/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpKeyPairDSAConsumeTest.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpKeyPairDSAConsumeTest.java b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpKeyPairDSAConsumeTest.java new file mode 100644 index 0000000..860a935 --- /dev/null +++ b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpKeyPairDSAConsumeTest.java @@ -0,0 +1,90 @@ +/** + * 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.component.file.remote.sftp; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.util.IOHelper; +import org.junit.Test; + +public class SftpKeyPairDSAConsumeTest extends SftpServerTestSupport { + + @Test + public void testSftpSimpleConsume() throws Exception { + if (!canTest()) { + return; + } + + String expected = "Hello World"; + + // create file using regular file + template.sendBodyAndHeader("file://" + FTP_ROOT_DIR, expected, Exchange.FILE_NAME, "hello.txt"); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + mock.expectedHeaderReceived(Exchange.FILE_NAME, "hello.txt"); + mock.expectedBodiesReceived(expected); + + context.startRoute("foo"); + + assertMockEndpointsSatisfied(); + } + + 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(); + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry registry = super.createRegistry(); + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA"); + keyGen.initialize(1024); + KeyPair pair = keyGen.generateKeyPair(); + registry.bind("keyPair", pair); + registry.bind("knownHosts", getBytesFromFile("./src/test/resources/known_hosts")); + + return registry; + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("sftp://localhost:" + getPort() + "/" + FTP_ROOT_DIR + + "?username=admin&knownHosts=#knownHosts&keyPair=#keyPair&delay=10s&strictHostKeyChecking=yes&disconnect=true") + .routeId("foo").noAutoStartup() + .to("mock:result"); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2194a4de/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpKeyPairRSAConsumeTest.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpKeyPairRSAConsumeTest.java b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpKeyPairRSAConsumeTest.java new file mode 100644 index 0000000..4ecd089 --- /dev/null +++ b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpKeyPairRSAConsumeTest.java @@ -0,0 +1,90 @@ +/** + * 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.component.file.remote.sftp; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; + +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.util.IOHelper; +import org.junit.Test; + +public class SftpKeyPairRSAConsumeTest extends SftpServerTestSupport { + + @Test + public void testSftpSimpleConsume() throws Exception { + if (!canTest()) { + return; + } + + String expected = "Hello World"; + + // create file using regular file + template.sendBodyAndHeader("file://" + FTP_ROOT_DIR, expected, Exchange.FILE_NAME, "hello.txt"); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + mock.expectedHeaderReceived(Exchange.FILE_NAME, "hello.txt"); + mock.expectedBodiesReceived(expected); + + context.startRoute("foo"); + + assertMockEndpointsSatisfied(); + } + + 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(); + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry registry = super.createRegistry(); + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + KeyPair pair = keyGen.generateKeyPair(); + registry.bind("keyPair", pair); + registry.bind("knownHosts", getBytesFromFile("./src/test/resources/known_hosts")); + + return registry; + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("sftp://localhost:" + getPort() + "/" + FTP_ROOT_DIR + + "?username=admin&knownHosts=#knownHosts&keyPair=#keyPair&delay=10s&strictHostKeyChecking=yes&disconnect=true") + .routeId("foo").noAutoStartup() + .to("mock:result"); + } + }; + } +}