From 3afdc3550e7c98e5a2da18b7fb6eb83a5ac84a47 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sat, 8 Dec 2012 14:34:37 -0800 Subject: [PATCH] add support for jsch proxy --- .../org/jclouds/ssh/jsch/JschSshClient.java | 10 +- .../jclouds/ssh/jsch/SessionConnection.java | 98 +++++++++++++++---- .../ssh/jsch/config/JschSshClientModule.java | 13 ++- 3 files changed, 93 insertions(+), 28 deletions(-) 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 16e5ba912e..5b2565822d 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 @@ -50,6 +50,7 @@ import org.jclouds.http.handlers.BackoffLimitedRetryHandler; import org.jclouds.io.Payload; import org.jclouds.io.Payloads; import org.jclouds.logging.Logger; +import org.jclouds.proxy.ProxyConfig; import org.jclouds.rest.AuthorizationException; import org.jclouds.ssh.SshClient; import org.jclouds.ssh.SshException; @@ -123,7 +124,8 @@ public class JschSshClient implements SshClient { final String user; final String host; - public JschSshClient(BackoffLimitedRetryHandler backoffLimitedRetryHandler, HostAndPort socket, + + public JschSshClient(ProxyConfig proxyConfig, BackoffLimitedRetryHandler backoffLimitedRetryHandler, HostAndPort socket, LoginCredentials loginCredentials, int timeout) { this.user = checkNotNull(loginCredentials, "loginCredentials").getUser(); this.host = checkNotNull(socket, "socket").getHostText(); @@ -142,7 +144,7 @@ public class JschSshClient implements SshClient { fingerPrint, sha1, host, socket.getPort()); } sessionConnection = SessionConnection.builder().hostAndPort(HostAndPort.fromParts(host, socket.getPort())).loginCredentials( - loginCredentials).connectTimeout(timeout).sessionTimeout(timeout).build(); + loginCredentials).proxy(checkNotNull(proxyConfig, "proxyConfig")).connectTimeout(timeout).sessionTimeout(timeout).build(); } @Override @@ -467,8 +469,8 @@ public class JschSshClient implements SshClient { @Override public ExecChannel create() throws Exception { - this.sessionConnection = acquire(SessionConnection.builder().fromSessionConnection( - JschSshClient.this.sessionConnection).sessionTimeout(0).build()); + this.sessionConnection = acquire(SessionConnection.builder().from(JschSshClient.this.sessionConnection) + .sessionTimeout(0).build()); String channel = "exec"; executor = (ChannelExec) sessionConnection.openChannel(channel); executor.setCommand(command); diff --git a/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/SessionConnection.java b/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/SessionConnection.java index d95d53d3dc..49f03252dc 100644 --- a/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/SessionConnection.java +++ b/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/SessionConnection.java @@ -20,26 +20,35 @@ package org.jclouds.ssh.jsch; import static com.google.common.base.Objects.equal; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import org.jclouds.domain.Credentials; import org.jclouds.domain.LoginCredentials; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.proxy.ProxyConfig; import org.jclouds.ssh.jsch.JschSshClient.Connection; import com.google.common.base.Objects; +import com.google.common.base.Optional; import com.google.common.net.HostAndPort; import com.jcraft.jsch.JSch; +import com.jcraft.jsch.Proxy; +import com.jcraft.jsch.ProxyHTTP; +import com.jcraft.jsch.ProxySOCKS5; import com.jcraft.jsch.Session; -public class SessionConnection implements Connection { +public final class SessionConnection implements Connection { public static Builder builder() { return new Builder(); } - public static class Builder { + public final static class Builder { - protected HostAndPort hostAndPort; - protected LoginCredentials loginCredentials; - protected int connectTimeout; - protected int sessionTimeout; + private HostAndPort hostAndPort; + private LoginCredentials loginCredentials; + private Optional proxy = Optional.absent(); + private int connectTimeout; + private int sessionTimeout; /** * @see SessionConnection#getHostAndPort() @@ -57,6 +66,39 @@ public class SessionConnection implements Connection { return this; } + /** + * @see SessionConnection#getProxy() + */ + public Builder proxy(Proxy proxy) { + this.proxy = Optional.fromNullable(proxy); + return this; + } + + /** + * @see #proxy(Proxy) + */ + public Builder proxy(ProxyConfig proxyConfig) { + Optional proxyEndpoint = proxyConfig.getProxy(); + if (!proxyEndpoint.isPresent()) + return proxy((Proxy) null); + + Optional creds = proxyConfig.getCredentials(); + switch (proxyConfig.getType()) { + case HTTP: + ProxyHTTP httpProxy = new ProxyHTTP(proxyEndpoint.get().getHostText(), proxyEndpoint.get().getPort()); + if (creds.isPresent()) + httpProxy.setUserPasswd(creds.get().identity, creds.get().credential); + return proxy(httpProxy); + case SOCKS: + ProxySOCKS5 socksProxy = new ProxySOCKS5(proxyEndpoint.get().getHostText(), proxyEndpoint.get().getPort()); + if (creds.isPresent()) + socksProxy.setUserPasswd(creds.get().identity, creds.get().credential); + return proxy(socksProxy); + default: + throw new IllegalArgumentException(proxyConfig.getType() + " not supported"); + } + } + /** * @see SessionConnection#getConnectTimeout() */ @@ -74,27 +116,30 @@ public class SessionConnection implements Connection { } public SessionConnection build() { - return new SessionConnection(hostAndPort, loginCredentials, connectTimeout, sessionTimeout); + return new SessionConnection(hostAndPort, loginCredentials, proxy, connectTimeout, sessionTimeout); } - protected Builder fromSessionConnection(SessionConnection in) { - return hostAndPort(in.getHostAndPort()).connectTimeout(in.getConnectTimeout()).loginCredentials( - in.getLoginCredentials()); + public Builder from(SessionConnection in) { + return hostAndPort(in.hostAndPort).loginCredentials(in.loginCredentials).proxy(in.proxy.orNull()) + .connectTimeout(in.connectTimeout).sessionTimeout(in.sessionTimeout); } + } - private SessionConnection(HostAndPort hostAndPort, LoginCredentials loginCredentials, int connectTimeout, - int sessionTimeout) { - this.hostAndPort = hostAndPort; - this.loginCredentials = loginCredentials; + private SessionConnection(HostAndPort hostAndPort, LoginCredentials loginCredentials, Optional proxy, + int connectTimeout, int sessionTimeout) { + this.hostAndPort = checkNotNull(hostAndPort, "hostAndPort"); + this.loginCredentials = checkNotNull(loginCredentials, "loginCredentials for %", hostAndPort); this.connectTimeout = connectTimeout; this.sessionTimeout = sessionTimeout; + this.proxy = checkNotNull(proxy, "proxy for %", hostAndPort); } private static final byte[] emptyPassPhrase = new byte[0]; private final HostAndPort hostAndPort; private final LoginCredentials loginCredentials; + private final Optional proxy; private final int connectTimeout; private final int sessionTimeout; @@ -112,7 +157,7 @@ public class SessionConnection implements Connection { public Session create() throws Exception { JSch jsch = new JSch(); session = jsch - .getSession(loginCredentials.getUser(), hostAndPort.getHostText(), hostAndPort.getPortOrDefault(22)); + .getSession(loginCredentials.getUser(), hostAndPort.getHostText(), hostAndPort.getPortOrDefault(22)); if (sessionTimeout != 0) session.setTimeout(sessionTimeout); if (loginCredentials.getPrivateKey() == null) { @@ -126,6 +171,8 @@ public class SessionConnection implements Connection { java.util.Properties config = new java.util.Properties(); config.put("StrictHostKeyChecking", "no"); session.setConfig(config); + if (proxy.isPresent()) + session.setProxy(proxy.get()); session.connect(connectTimeout); return session; } @@ -145,6 +192,14 @@ public class SessionConnection implements Connection { return loginCredentials; } + /** + * + * @return proxy used for this connection + */ + public Optional getProxy() { + return proxy; + } + /** * * @return how long to wait for the initial connection to be made @@ -165,6 +220,7 @@ public class SessionConnection implements Connection { * * @return the current session or {@code null} if not connected */ + @Nullable public Session getSession() { return session; } @@ -177,7 +233,7 @@ public class SessionConnection implements Connection { return false; SessionConnection that = SessionConnection.class.cast(o); return equal(this.hostAndPort, that.hostAndPort) && equal(this.loginCredentials, that.loginCredentials) - && equal(this.session, that.session); + && equal(this.session, that.session); } @Override @@ -187,10 +243,12 @@ public class SessionConnection implements Connection { @Override public String toString() { - return Objects.toStringHelper("").add("hostAndPort", hostAndPort).add("loginUser", loginCredentials.getUser()) - .add("session", session != null ? session.hashCode() : null).add("connectTimeout", connectTimeout).add( - "sessionTimeout", sessionTimeout).toString(); + return Objects.toStringHelper("").omitNullValues() + .add("hostAndPort", hostAndPort).add("loginUser", loginCredentials.getUser()) + .add("session", session != null ? session.hashCode() : null) + .add("connectTimeout", connectTimeout) + .add("proxy", proxy.orNull()) + .add("sessionTimeout", sessionTimeout).toString(); } - } diff --git a/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/config/JschSshClientModule.java b/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/config/JschSshClientModule.java index 58ca3b1f0f..7330fc7dd4 100644 --- a/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/config/JschSshClientModule.java +++ b/drivers/jsch/src/main/java/org/jclouds/ssh/jsch/config/JschSshClientModule.java @@ -18,11 +18,14 @@ */ package org.jclouds.ssh.jsch.config; +import static com.google.common.base.Preconditions.checkNotNull; + import javax.inject.Named; import org.jclouds.Constants; import org.jclouds.domain.LoginCredentials; import org.jclouds.http.handlers.BackoffLimitedRetryHandler; +import org.jclouds.proxy.ProxyConfig; import org.jclouds.ssh.SshClient; import org.jclouds.ssh.config.ConfiguresSshClient; import org.jclouds.ssh.jsch.JschSshClient; @@ -49,18 +52,20 @@ public class JschSshClientModule extends AbstractModule { @Inject(optional = true) int timeout = 60000; + private final ProxyConfig proxyConfig; private final BackoffLimitedRetryHandler backoffLimitedRetryHandler; private final Injector injector; @Inject - public Factory(BackoffLimitedRetryHandler backoffLimitedRetryHandler, Injector injector) { - this.backoffLimitedRetryHandler = backoffLimitedRetryHandler; - this.injector = injector; + public Factory(ProxyConfig proxyConfig, BackoffLimitedRetryHandler backoffLimitedRetryHandler, Injector injector) { + this.proxyConfig = checkNotNull(proxyConfig, "proxyConfig"); + this.backoffLimitedRetryHandler = checkNotNull(backoffLimitedRetryHandler, "backoffLimitedRetryHandler"); + this.injector = checkNotNull(injector, "injector"); } @Override public SshClient create(HostAndPort socket, LoginCredentials credentials) { - SshClient client = new JschSshClient(backoffLimitedRetryHandler, socket, credentials, timeout); + SshClient client = new JschSshClient(proxyConfig, backoffLimitedRetryHandler, socket, credentials, timeout); injector.injectMembers(client);// add logger return client; }