diff --git a/drivers/jsch/pom.xml b/drivers/jsch/pom.xml
index cfa79c40a2..de7522d121 100644
--- a/drivers/jsch/pom.xml
+++ b/drivers/jsch/pom.xml
@@ -44,6 +44,14 @@
+
+ localhost
+ 22
+
+
+
+
+
org.jclouds
@@ -62,6 +70,17 @@
test-jar
test
+
+ org.jclouds.driver
+ jclouds-slf4j
+ ${project.version}
+
+
+ ch.qos.logback
+ logback-classic
+ 0.9.30
+ test
+
com.jcraft
jsch
@@ -89,4 +108,66 @@
+
+
+ live
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration
+ integration-test
+
+ test
+
+
+
+
+ none
+
+
+ **/*IntegrationTest.java
+ **/*LiveTest.java
+
+
+
+ file.encoding
+ UTF-8
+
+
+ test.ssh.host
+ ${test.ssh.host}
+
+
+ test.ssh.port
+ ${test.ssh.port}
+
+
+ test.ssh.username
+ ${test.ssh.username}
+
+
+ test.ssh.keyfile
+ ${test.ssh.keyfile}
+
+
+ test.ssh.password
+ ${test.ssh.password}
+
+
+
+
+
+
+
+
+
+
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 426956da02..6c7c56a21b 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
@@ -25,6 +25,8 @@ import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.base.Predicates.or;
import static com.google.common.base.Throwables.getCausalChain;
import static com.google.common.collect.Iterables.any;
+import static org.jclouds.crypto.SshKeys.fingerprintPrivateKey;
+import static org.jclouds.crypto.SshKeys.sha1PrivateKey;
import java.io.IOException;
import java.io.InputStream;
@@ -90,6 +92,7 @@ public class JschSshClient implements SshClient {
private final int port;
private final String username;
private final String password;
+ private final String toString;
@Inject(optional = true)
@Named("jclouds.ssh.max-retries")
@@ -131,6 +134,14 @@ public class JschSshClient implements SshClient {
this.timeout = timeout;
this.password = password;
this.privateKey = privateKey;
+ if ( privateKey==null ) {
+ this.toString = String.format("%s:password@%s:%d", username, host, port);
+ } else {
+ String fingerPrint = fingerprintPrivateKey(new String(privateKey));
+ String sha1 = sha1PrivateKey(new String(privateKey));
+ this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", username, fingerPrint, sha1, host,
+ port);
+ }
}
@Override
@@ -182,7 +193,7 @@ public class JschSshClient implements SshClient {
@Override
public String toString() {
- return String.format("Session(%s)", JschSshClient.this.toString());
+ return String.format("Session(timeout=%d)", timeout);
}
};
@@ -237,7 +248,7 @@ public class JschSshClient implements SshClient {
@Override
public String toString() {
- return "ChannelSftp(" + JschSshClient.this.toString() + ")";
+ return "ChannelSftp()";
}
};
@@ -263,7 +274,7 @@ public class JschSshClient implements SshClient {
@Override
public String toString() {
- return "Payload(" + JschSshClient.this.toString() + ")[" + path + "]";
+ return "Payload(path=[" + path + "])";
}
};
@@ -301,7 +312,7 @@ public class JschSshClient implements SshClient {
@Override
public String toString() {
- return "Put(" + JschSshClient.this.toString() + ")[" + path + "]";
+ return "Put(path=[" + path + "])";
}
};
@@ -354,7 +365,7 @@ public class JschSshClient implements SshClient {
@Override
public String toString() {
- return String.format("%s@%s:%d", username, host, port);
+ return toString;
}
@PreDestroy
@@ -389,7 +400,7 @@ public class JschSshClient implements SshClient {
@Override
public String toString() {
- return "ChannelExec(" + JschSshClient.this.toString() + ")";
+ return "ChannelExec()";
}
};
@@ -437,7 +448,7 @@ public class JschSshClient implements SshClient {
@Override
public String toString() {
- return "ExecResponse(" + JschSshClient.this.toString() + ")[" + command + "]";
+ return "ExecResponse(command=[" + command + "])";
}
}
diff --git a/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshClientLiveTest.java b/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshClientLiveTest.java
index 70a9574274..7e2b57f035 100644
--- a/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshClientLiveTest.java
+++ b/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/JschSshClientLiveTest.java
@@ -24,11 +24,13 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.net.InetAddress;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.domain.Credentials;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
@@ -44,7 +46,7 @@ import com.google.inject.Injector;
*
* @author Adrian Cole
*/
-@Test(groups = "live")
+@Test(groups = "live", testName = "JschSshClientLiveTest" )
public class JschSshClientLiveTest {
protected static final String sshHost = System.getProperty("test.ssh.host", "localhost");
protected static final String sshPort = System.getProperty("test.ssh.port", "22");
@@ -106,7 +108,7 @@ public class JschSshClientLiveTest {
};
} else {
- Injector i = Guice.createInjector(new JschSshClientModule());
+ Injector i = Guice.createInjector(new JschSshClientModule(), new SLF4JLoggingModule());
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
SshClient connection;
if (sshKeyFile != null && !sshKeyFile.trim().equals("")) {
@@ -139,7 +141,8 @@ public class JschSshClientLiveTest {
public void testExecHostname() throws IOException {
ExecResponse response = setupClient().exec("hostname");
assertEquals(response.getError(), "");
- assertEquals(response.getOutput().trim(), sshHost);
+ assertEquals(response.getOutput().trim(), "localhost".equals(sshHost) ? InetAddress.getLocalHost().getHostName()
+ : sshHost);
}
}
\ No newline at end of file
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 4ca2408ac4..86d7d1bfcc 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
@@ -21,8 +21,11 @@ package org.jclouds.ssh.jsch;
import java.io.IOException;
import java.net.ConnectException;
import java.net.UnknownHostException;
+import java.util.Properties;
+import com.google.inject.AbstractModule;
import org.jclouds.domain.Credentials;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.ssh.SshClient;
@@ -38,6 +41,8 @@ import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.SftpException;
+import static com.google.inject.name.Names.bindProperties;
+
/**
*
* @author Adrian Cole
@@ -49,11 +54,20 @@ public class JschSshClientTest {
@BeforeTest
public void setupSsh() throws UnknownHostException {
- ssh = createClient();
+ ssh = createClient(new Properties());
}
protected JschSshClient createClient() throws UnknownHostException {
- Injector i = Guice.createInjector(module());
+ return createClient(new Properties());
+ }
+
+ protected JschSshClient createClient(final Properties props) throws UnknownHostException {
+ Injector i = Guice.createInjector(module(), new AbstractModule() {
+ @Override
+ protected void configure() {
+ bindProperties(binder(), props);
+ }
+ }, new SLF4JLoggingModule());
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
JschSshClient ssh = JschSshClient.class.cast(factory.create(new IPSocket("localhost", 22), new Credentials(
"username", "password")));
@@ -83,6 +97,13 @@ public class JschSshClientTest {
assert ssh1.shouldRetry(new AuthorizationException("problem", null));
}
+ public void testOnlyRetryAuthWhenSetViaProperties() throws UnknownHostException {
+ Properties props = new Properties();
+ props.setProperty("jclouds.ssh.retry-auth", "true");
+ JschSshClient ssh1 = createClient(props);
+ assert ssh1.shouldRetry(new AuthorizationException("problem", null));
+ }
+
public void testExceptionMessagesRetry() {
assert !ssh.shouldRetry(new NullPointerException(""));
assert !ssh.shouldRetry(new NullPointerException((String) null));
@@ -107,12 +128,40 @@ public class JschSshClientTest {
assert !ssh.causalChainHasMessageContaining(new NullPointerException()).apply(" End of IO Stream Read");
}
+ // Seems to be using oauth now instead of bouncycastle and is more strict.
+ // Commands used to generate this key are:
+ // openssl dsaparam -outform PEM 2048 > dsaparams
+ // openssl gendsa -aes256 -out privkey.pem dsaparams
+ private static final String key = "-----BEGIN DSA PRIVATE KEY-----\n" +
+ "Proc-Type: 4,ENCRYPTED\n" +
+ "DEK-Info: AES-256-CBC,8C3A84B8BDA9FE69AAB4A322D7795161\n" +
+ "\n" +
+ "B8nuwNIcw5UtV9gGX2LiOq5OZ0uDgWsRon/mmWu+8EFd6X1aautVw8pCZuNusNkS\n" +
+ "GZlO1JBIgKdX6Qqx0cPsirFB7GTNbBVHOIMqYbmQKW5Ju+n+NkNIomDJDJqBWknE\n" +
+ "ZIkegznvdLN11r6F4jreusnVepSNYeRwKxA5KAT0S6XsgVFKSJZIyJj8EKZl/25D\n" +
+ "a7LKoYRlf5QK+Q1/zmMyZcCt0irIMcHxslpVlyATajAADB0hwBl4Xh0H3oHR3PU1\n" +
+ "xhsliYTARGov6Wn7adDCG9zWDzO7cX3941ub0FPoDdPLxGkmwqEwijF1XWvYbIUC\n" +
+ "EBjomG3pwjC1kfoqAYJhThi8vmQYtFyCagcZMauHDKuqwUr1o3jS51PBe3bKeg4M\n" +
+ "dP/JSTiTAUGtwV/MobThQFvCWJm22jIR6Eb0IYPcncUQuZ1QO2piwSvMUZZYCFX/\n" +
+ "uY7fHkPZyBkZIrxGc91jhSQlo8qsVBIThJpLYI2M2PjKxTzsgZ2mWWK/Zm7pVqqI\n" +
+ "ldTJ1cpSMb2/9BsXF0CWvzaC4qN5Ymmrp152M4ZEnsRN3ycd9wFCD2cM7w5frj4Z\n" +
+ "3Q3M9/qNYuPfHddJa1DIkYpZxTTzOo4BBWx2O32D3in+2YZWjBgdxej17hKVkmUR\n" +
+ "C432CtEqUYAtVv//3TZ47hYsywvvVEX/3ljcCObrHKDha6i3SwXMqe1tL3BYexOn\n" +
+ "LS8aGQ148oekWaSWYrXCo0gjuJgY3hJZKUHoKdhvyW/FZG3rMjk5NlU9IwjMweqz\n" +
+ "Bznl7sMxHqtW4BPV9fM4uaiM8LOMkIm6euu/1a2o///TaEgFr/H1ybLdcg8Au1Iy\n" +
+ "sH68Xn+pmkx1bdVCCpi44EtAEHrpX11AC+cuvu8KG0A+Tpy3WW7YXYkregEQM3kF\n" +
+ "XzzyJfHuZKvM7qXsMnt/T5VCYX1LSEtXFABFMHDsPC9qs1LVLdSC5U0Ux0Ac0Sqq\n" +
+ "MRG2Yc8hDOPvPOmiqD9OK9PC6fa+bbMEtlS2O5Cd0l+hoE8OD1EFP1hAGQ0ivjZT\n" +
+ "zMJXBUVUtYAkrpU6NcY+ub7IyYBR3wOWSAUbolx3K4p2o8k3MGFdLHb4dGvypIv2\n" +
+ "oHhZLNLYGPrAN2g0gpNmlepDS1aG6422770O/Eh1bDXDyGYJRW3INwWenN8KbuYd\n" +
+ "-----END DSA PRIVATE KEY-----";
+
public void testPrivateKeyWithPassphrase() throws UnknownHostException {
- Injector i = Guice.createInjector(module());
+ Injector i = Guice.createInjector(module(),new SLF4JLoggingModule());
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")));
+ "username", key)));
ssh.connect();
assert false; // this code should never be reached.
} catch (SshException e) {
diff --git a/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/config/JschSshClientModuleTest.java b/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/config/JschSshClientModuleTest.java
index 413dd796d1..fd2b628953 100644
--- a/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/config/JschSshClientModuleTest.java
+++ b/drivers/jsch/src/test/java/org/jclouds/ssh/jsch/config/JschSshClientModuleTest.java
@@ -21,6 +21,7 @@ package org.jclouds.ssh.jsch.config;
import java.net.UnknownHostException;
import org.jclouds.domain.Credentials;
+import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.ssh.SshClient;
import org.jclouds.ssh.jsch.JschSshClient;
@@ -39,7 +40,7 @@ public class JschSshClientModuleTest {
public void testConfigureBindsClient() throws UnknownHostException {
- Injector i = Guice.createInjector(new JschSshClientModule());
+ Injector i = Guice.createInjector(new JschSshClientModule(), new SLF4JLoggingModule());
SshClient.Factory factory = i.getInstance(SshClient.Factory.class);
SshClient connection = factory.create(new IPSocket("localhost", 22), new Credentials("username", "password"));
assert connection instanceof JschSshClient;
diff --git a/drivers/jsch/src/test/resources/logback.xml b/drivers/jsch/src/test/resources/logback.xml
new file mode 100644
index 0000000000..d7a1f1accc
--- /dev/null
+++ b/drivers/jsch/src/test/resources/logback.xml
@@ -0,0 +1,15 @@
+
+
+
+ target/test-data/jclouds-ssh.log
+ true
+
+ %-4relative [%thread] %-5level %logger{35} - %msg%n
+
+
+
+
+
+
+
+