diff --git a/core/src/main/java/org/jclouds/util/CredentialUtils.java b/core/src/main/java/org/jclouds/util/CredentialUtils.java index d16f87ef9d..b1beae24da 100644 --- a/core/src/main/java/org/jclouds/util/CredentialUtils.java +++ b/core/src/main/java/org/jclouds/util/CredentialUtils.java @@ -53,5 +53,8 @@ public class CredentialUtils { .startsWith(Pems.PRIVATE_PKCS8_MARKER)); } + public static boolean isPrivateKeyEncrypted(byte[] privateKey) { + return new String(privateKey).contains("Proc-Type: 4,ENCRYPTED"); + } } diff --git a/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshClient.java b/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshClient.java index 95812b516c..426956da02 100644 --- a/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshClient.java +++ b/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/JschSshClient.java @@ -47,6 +47,7 @@ import org.jclouds.net.IPSocket; import org.jclouds.rest.AuthorizationException; import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshException; +import org.jclouds.util.CredentialUtils; import org.jclouds.util.Strings2; import com.google.common.annotations.VisibleForTesting; @@ -167,6 +168,9 @@ public class JschSshClient implements SshClient { session.setPassword(password); } else { // jsch wipes out your private key + if (CredentialUtils.isPrivateKeyEncrypted(privateKey)) { + throw new IllegalArgumentException("JschSshClientModule does not support private keys that require a passphrase"); + } jsch.addIdentity(username, Arrays.copyOf(privateKey, privateKey.length), null, emptyPassPhrase); } java.util.Properties config = new java.util.Properties(); diff --git a/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshClientTest.java b/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshClientTest.java index bde540f81d..4ca2408ac4 100644 --- a/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshClientTest.java +++ b/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshClientTest.java @@ -26,6 +26,7 @@ import org.jclouds.domain.Credentials; import org.jclouds.net.IPSocket; import org.jclouds.rest.AuthorizationException; import org.jclouds.ssh.SshClient; +import org.jclouds.ssh.SshException; import org.jclouds.ssh.jsch.config.JschSshClientModule; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -105,4 +106,17 @@ public class JschSshClientTest { new JSchException("Session.connect: java.net.SocketException: Connection reset")).apply("java.net.Socket"); assert !ssh.causalChainHasMessageContaining(new NullPointerException()).apply(" End of IO Stream Read"); } + + public void testPrivateKeyWithPassphrase() throws UnknownHostException { + Injector i = Guice.createInjector(module()); + SshClient.Factory factory = i.getInstance(SshClient.Factory.class); + try { + JschSshClient ssh = JschSshClient.class.cast(factory.create(new IPSocket("localhost", 22), new Credentials( + "username", "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-128-CBC,123\n\n123"))); + ssh.connect(); + assert false; // this code should never be reached. + } catch (SshException e) { + // Success! + } + } } \ No newline at end of file