mirror of https://github.com/apache/jclouds.git
JCLOUDS-516: Add ssh agent support via sch agentproxy
This commit is contained in:
parent
59c10e18e8
commit
63d6d97553
|
@ -17,6 +17,7 @@
|
|||
package org.jclouds.compute.functions;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -49,7 +50,7 @@ public class CreateSshClientOncePortIsListeningOnNode implements Function<NodeMe
|
|||
|
||||
@Inject(optional = true)
|
||||
SshClient.Factory sshFactory;
|
||||
|
||||
|
||||
private final OpenSocketFinder openSocketFinder;
|
||||
|
||||
private final long timeoutMs;
|
||||
|
@ -65,7 +66,7 @@ public class CreateSshClientOncePortIsListeningOnNode implements Function<NodeMe
|
|||
checkState(sshFactory != null, "ssh requested, but no SshModule configured");
|
||||
checkNotNull(node.getCredentials(), "no credentials found for node %s", node.getId());
|
||||
checkNotNull(node.getCredentials().identity, "no login identity found for node %s", node.getId());
|
||||
checkNotNull(node.getCredentials().credential, "no credential found for %s on node %s", node
|
||||
checkArgument(node.getCredentials().credential != null || sshFactory.isAgentAvailable(), "no credential or ssh agent found for %s on node %s", node
|
||||
.getCredentials().identity, node.getId());
|
||||
HostAndPort socket = openSocketFinder.findOpenSocketOnNode(node, node.getLoginPort(),
|
||||
timeoutMs, TimeUnit.MILLISECONDS);
|
||||
|
|
|
@ -29,9 +29,8 @@ import com.google.common.net.HostAndPort;
|
|||
public interface SshClient {
|
||||
|
||||
interface Factory {
|
||||
|
||||
SshClient create(HostAndPort socket, LoginCredentials credentials);
|
||||
|
||||
boolean isAgentAvailable();
|
||||
}
|
||||
|
||||
String getUsername();
|
||||
|
|
|
@ -228,7 +228,6 @@ public abstract class BaseComputeServiceLiveTest extends BaseComputeServiceConte
|
|||
NodeMetadata node = get(nodes, 0);
|
||||
LoginCredentials good = node.getCredentials();
|
||||
assert good.identity != null : nodes;
|
||||
assert good.credential != null : nodes;
|
||||
|
||||
for (Entry<? extends NodeMetadata, ExecResponse> response : client.runScriptOnNodesMatching(
|
||||
runningInGroup(group), "hostname",
|
||||
|
@ -507,7 +506,6 @@ public abstract class BaseComputeServiceLiveTest extends BaseComputeServiceConte
|
|||
assertNotNull(node.getCredentials());
|
||||
if (node.getCredentials().identity != null) {
|
||||
assertNotNull(node.getCredentials().identity);
|
||||
assertNotNull(node.getCredentials().credential);
|
||||
sshPing(node, taskName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ public class Pems {
|
|||
public static final String CERTIFICATE_X509_MARKER = "-----BEGIN CERTIFICATE-----";
|
||||
public static final String PUBLIC_X509_MARKER = "-----BEGIN PUBLIC KEY-----";
|
||||
public static final String PUBLIC_PKCS1_MARKER = "-----BEGIN RSA PUBLIC KEY-----";
|
||||
public static final String PROC_TYPE_ENCRYPTED = "Proc-Type: 4,ENCRYPTED";
|
||||
|
||||
private static class PemProcessor<T> implements ByteProcessor<T> {
|
||||
private interface ResultParser<T> {
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.jclouds.domain;
|
|||
import static org.jclouds.crypto.Pems.PRIVATE_PKCS1_MARKER;
|
||||
import static org.jclouds.crypto.Pems.PRIVATE_PKCS8_MARKER;
|
||||
|
||||
import org.jclouds.crypto.Pems;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
@ -155,6 +156,15 @@ public class LoginCredentials extends Credentials {
|
|||
return (privateKey != null) ? privateKey.orNull() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there is a private key attached that is not encrypted
|
||||
*/
|
||||
public boolean hasUnencryptedPrivateKey() {
|
||||
return getPrivateKey() != null
|
||||
&& !getPrivateKey().isEmpty()
|
||||
&& !getPrivateKey().contains(Pems.PROC_TYPE_ENCRYPTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the optional private ssh key of the user or null
|
||||
*/
|
||||
|
|
|
@ -86,6 +86,16 @@
|
|||
<artifactId>jsch</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch.agentproxy.jsch</artifactId>
|
||||
<version>0.0.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch.agentproxy.connector-factory</artifactId>
|
||||
<version>0.0.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
|
|
@ -56,6 +56,7 @@ import org.jclouds.util.Closeables2;
|
|||
import org.jclouds.util.Strings2;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Splitter;
|
||||
|
@ -66,6 +67,7 @@ import com.jcraft.jsch.ChannelExec;
|
|||
import com.jcraft.jsch.ChannelSftp;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
import com.jcraft.jsch.agentproxy.Connector;
|
||||
|
||||
/**
|
||||
* This class needs refactoring. It is not thread safe.
|
||||
|
@ -124,25 +126,28 @@ public class JschSshClient implements SshClient {
|
|||
|
||||
|
||||
public JschSshClient(ProxyConfig proxyConfig, BackoffLimitedRetryHandler backoffLimitedRetryHandler, HostAndPort socket,
|
||||
LoginCredentials loginCredentials, int timeout) {
|
||||
LoginCredentials loginCredentials, int timeout, Optional<Connector> agentConnector) {
|
||||
this.user = checkNotNull(loginCredentials, "loginCredentials").getUser();
|
||||
this.host = checkNotNull(socket, "socket").getHostText();
|
||||
checkArgument(socket.getPort() > 0, "ssh port must be greater then zero" + socket.getPort());
|
||||
checkArgument(loginCredentials.getPassword() != null || loginCredentials.getPrivateKey() != null,
|
||||
"you must specify a password or a key");
|
||||
checkArgument(loginCredentials.getPassword() != null || loginCredentials.hasUnencryptedPrivateKey() || agentConnector.isPresent(),
|
||||
"you must specify a password, a key or an SSH agent needs to be available");
|
||||
this.backoffLimitedRetryHandler = checkNotNull(backoffLimitedRetryHandler, "backoffLimitedRetryHandler");
|
||||
if (loginCredentials.getPrivateKey() == null) {
|
||||
if (loginCredentials.getPassword() != null) {
|
||||
this.toString = String.format("%s:pw[%s]@%s:%d", loginCredentials.getUser(),
|
||||
base16().lowerCase().encode(md5().hashString(loginCredentials.getPassword(), UTF_8).asBytes()), host,
|
||||
socket.getPort());
|
||||
} else {
|
||||
} else if (loginCredentials.hasUnencryptedPrivateKey()) {
|
||||
String fingerPrint = fingerprintPrivateKey(loginCredentials.getPrivateKey());
|
||||
String sha1 = sha1PrivateKey(loginCredentials.getPrivateKey());
|
||||
this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", loginCredentials.getUser(),
|
||||
fingerPrint, sha1, host, socket.getPort());
|
||||
fingerPrint, sha1, host, socket.getPort());
|
||||
} else {
|
||||
this.toString = String.format("%s:rsa[ssh-agent]@%s:%d", loginCredentials.getUser(), host, socket.getPort());
|
||||
}
|
||||
sessionConnection = SessionConnection.builder().hostAndPort(HostAndPort.fromParts(host, socket.getPort())).loginCredentials(
|
||||
loginCredentials).proxy(checkNotNull(proxyConfig, "proxyConfig")).connectTimeout(timeout).sessionTimeout(timeout).build();
|
||||
loginCredentials).proxy(checkNotNull(proxyConfig, "proxyConfig")).connectTimeout(timeout).sessionTimeout(timeout)
|
||||
.agentConnector(agentConnector).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
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;
|
||||
|
@ -34,8 +33,13 @@ import com.jcraft.jsch.Proxy;
|
|||
import com.jcraft.jsch.ProxyHTTP;
|
||||
import com.jcraft.jsch.ProxySOCKS5;
|
||||
import com.jcraft.jsch.Session;
|
||||
import com.jcraft.jsch.agentproxy.Connector;
|
||||
import com.jcraft.jsch.agentproxy.RemoteIdentityRepository;
|
||||
|
||||
public final class SessionConnection implements Connection<Session> {
|
||||
|
||||
private Optional<Connector> agentConnector;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
@ -47,6 +51,7 @@ public final class SessionConnection implements Connection<Session> {
|
|||
private Optional<Proxy> proxy = Optional.absent();
|
||||
private int connectTimeout;
|
||||
private int sessionTimeout;
|
||||
private Optional<Connector> agentConnector;
|
||||
|
||||
/**
|
||||
* @see SessionConnection#getHostAndPort()
|
||||
|
@ -114,7 +119,7 @@ public final class SessionConnection implements Connection<Session> {
|
|||
}
|
||||
|
||||
public SessionConnection build() {
|
||||
return new SessionConnection(hostAndPort, loginCredentials, proxy, connectTimeout, sessionTimeout);
|
||||
return new SessionConnection(hostAndPort, loginCredentials, proxy, connectTimeout, sessionTimeout, agentConnector);
|
||||
}
|
||||
|
||||
public Builder from(SessionConnection in) {
|
||||
|
@ -122,15 +127,21 @@ public final class SessionConnection implements Connection<Session> {
|
|||
.connectTimeout(in.connectTimeout).sessionTimeout(in.sessionTimeout);
|
||||
}
|
||||
|
||||
public Builder agentConnector(Optional<Connector> agentConnector) {
|
||||
this.agentConnector = agentConnector;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private SessionConnection(HostAndPort hostAndPort, LoginCredentials loginCredentials, Optional<Proxy> proxy,
|
||||
int connectTimeout, int sessionTimeout) {
|
||||
int connectTimeout, int sessionTimeout, Optional<Connector> agentConnector) {
|
||||
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);
|
||||
this.agentConnector = checkNotNull(agentConnector, "agentConnector for %", hostAndPort);
|
||||
}
|
||||
|
||||
private static final byte[] emptyPassPhrase = new byte[0];
|
||||
|
@ -160,11 +171,12 @@ public final class SessionConnection implements Connection<Session> {
|
|||
session.setTimeout(sessionTimeout);
|
||||
if (loginCredentials.getPrivateKey() == null) {
|
||||
session.setPassword(loginCredentials.getPassword());
|
||||
} else {
|
||||
checkArgument(!loginCredentials.getPrivateKey().contains("Proc-Type: 4,ENCRYPTED"),
|
||||
"JschSshClientModule does not support private keys that require a passphrase");
|
||||
} else if (loginCredentials.hasUnencryptedPrivateKey()) {
|
||||
byte[] privateKey = loginCredentials.getPrivateKey().getBytes();
|
||||
jsch.addIdentity(loginCredentials.getUser(), privateKey, null, emptyPassPhrase);
|
||||
} else if (agentConnector.isPresent()) {
|
||||
JSch.setConfig("PreferredAuthentications", "publickey");
|
||||
jsch.setIdentityRepository(new RemoteIdentityRepository(agentConnector.get()));
|
||||
}
|
||||
java.util.Properties config = new java.util.Properties();
|
||||
config.put("StrictHostKeyChecking", "no");
|
||||
|
|
|
@ -28,11 +28,15 @@ import org.jclouds.ssh.SshClient;
|
|||
import org.jclouds.ssh.config.ConfiguresSshClient;
|
||||
import org.jclouds.ssh.jsch.JschSshClient;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Scopes;
|
||||
import com.jcraft.jsch.agentproxy.AgentProxyException;
|
||||
import com.jcraft.jsch.agentproxy.Connector;
|
||||
import com.jcraft.jsch.agentproxy.ConnectorFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -50,6 +54,16 @@ public class JschSshClientModule extends AbstractModule {
|
|||
@Inject(optional = true)
|
||||
int timeout = 60000;
|
||||
|
||||
Optional<Connector> agentConnector = getAgentConnector();
|
||||
|
||||
Optional<Connector> getAgentConnector() {
|
||||
try {
|
||||
return Optional.of(ConnectorFactory.getDefault().createConnector());
|
||||
} catch (final AgentProxyException e) {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
private final ProxyConfig proxyConfig;
|
||||
private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
|
||||
private final Injector injector;
|
||||
|
@ -63,9 +77,14 @@ public class JschSshClientModule extends AbstractModule {
|
|||
|
||||
@Override
|
||||
public SshClient create(HostAndPort socket, LoginCredentials credentials) {
|
||||
SshClient client = new JschSshClient(proxyConfig, backoffLimitedRetryHandler, socket, credentials, timeout);
|
||||
SshClient client = new JschSshClient(proxyConfig, backoffLimitedRetryHandler, socket, credentials, timeout, getAgentConnector());
|
||||
injector.injectMembers(client);// add logger
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAgentAvailable() {
|
||||
return agentConnector.isPresent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,6 +104,16 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch.agentproxy.sshj</artifactId>
|
||||
<version>0.0.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch.agentproxy.connector-factory</artifactId>
|
||||
<version>0.0.7</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
|
|
@ -17,15 +17,19 @@
|
|||
package org.jclouds.sshj;
|
||||
|
||||
import static com.google.common.base.Objects.equal;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.inject.Named;
|
||||
|
||||
import net.schmizz.sshj.SSHClient;
|
||||
import net.schmizz.sshj.common.Buffer.BufferException;
|
||||
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
|
||||
import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
|
||||
import net.schmizz.sshj.userauth.method.AuthMethod;
|
||||
|
||||
import org.jclouds.domain.LoginCredentials;
|
||||
import org.jclouds.logging.Logger;
|
||||
|
@ -33,9 +37,18 @@ import org.jclouds.sshj.SshjSshClient.Connection;
|
|||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.HostAndPort;
|
||||
|
||||
import com.jcraft.jsch.agentproxy.AgentProxy;
|
||||
import com.jcraft.jsch.agentproxy.Connector;
|
||||
import com.jcraft.jsch.agentproxy.Identity;
|
||||
import com.jcraft.jsch.agentproxy.sshj.AuthAgent;
|
||||
|
||||
public class SSHClientConnection implements Connection<SSHClient> {
|
||||
private Optional<Connector> agentConnector;
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
@ -46,6 +59,7 @@ public class SSHClientConnection implements Connection<SSHClient> {
|
|||
protected LoginCredentials loginCredentials;
|
||||
protected int connectTimeout;
|
||||
protected int sessionTimeout;
|
||||
protected Optional<Connector> agentConnector;
|
||||
|
||||
/**
|
||||
* @see SSHClientConnection#getHostAndPort()
|
||||
|
@ -79,8 +93,16 @@ public class SSHClientConnection implements Connection<SSHClient> {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see SSHClientConnection#getAgentConnector()
|
||||
*/
|
||||
public Builder agentConnector(Optional<Connector> agentConnector) {
|
||||
this.agentConnector = agentConnector;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SSHClientConnection build() {
|
||||
return new SSHClientConnection(hostAndPort, loginCredentials, connectTimeout, sessionTimeout);
|
||||
return new SSHClientConnection(hostAndPort, loginCredentials, connectTimeout, sessionTimeout, agentConnector);
|
||||
}
|
||||
|
||||
protected Builder fromSSHClientConnection(SSHClientConnection in) {
|
||||
|
@ -90,11 +112,12 @@ public class SSHClientConnection implements Connection<SSHClient> {
|
|||
}
|
||||
|
||||
private SSHClientConnection(HostAndPort hostAndPort, LoginCredentials loginCredentials, int connectTimeout,
|
||||
int sessionTimeout) {
|
||||
this.hostAndPort = hostAndPort;
|
||||
this.loginCredentials = loginCredentials;
|
||||
int sessionTimeout, Optional<Connector> agentConnector) {
|
||||
this.hostAndPort = checkNotNull(hostAndPort, "hostAndPort");
|
||||
this.loginCredentials = checkNotNull(loginCredentials, "loginCredentials for %", hostAndPort);
|
||||
this.connectTimeout = connectTimeout;
|
||||
this.sessionTimeout = sessionTimeout;
|
||||
this.agentConnector = checkNotNull(agentConnector, "agentConnector for %", hostAndPort);
|
||||
}
|
||||
|
||||
@Resource
|
||||
|
@ -136,10 +159,13 @@ public class SSHClientConnection implements Connection<SSHClient> {
|
|||
ssh.connect(hostAndPort.getHostText(), hostAndPort.getPortOrDefault(22));
|
||||
if (loginCredentials.getPassword() != null) {
|
||||
ssh.authPassword(loginCredentials.getUser(), loginCredentials.getPassword());
|
||||
} else {
|
||||
} else if (loginCredentials.hasUnencryptedPrivateKey()) {
|
||||
OpenSSHKeyFile key = new OpenSSHKeyFile();
|
||||
key.init(loginCredentials.getPrivateKey(), null);
|
||||
ssh.authPublickey(loginCredentials.getUser(), key);
|
||||
} else if (agentConnector.isPresent()) {
|
||||
AgentProxy proxy = new AgentProxy(agentConnector.get());
|
||||
ssh.auth(loginCredentials.getUser(), getAuthMethods(proxy));
|
||||
}
|
||||
return ssh;
|
||||
}
|
||||
|
@ -175,6 +201,14 @@ public class SSHClientConnection implements Connection<SSHClient> {
|
|||
return sessionTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Ssh agent connector
|
||||
*/
|
||||
public Optional<Connector> getAgentConnector() {
|
||||
return agentConnector;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the current ssh or {@code null} if not connected
|
||||
|
@ -206,4 +240,12 @@ public class SSHClientConnection implements Connection<SSHClient> {
|
|||
"sessionTimeout", sessionTimeout).toString();
|
||||
}
|
||||
|
||||
private static List<AuthMethod> getAuthMethods(AgentProxy agent) throws BufferException {
|
||||
ImmutableList.Builder<AuthMethod> identities = ImmutableList.builder();
|
||||
for (Identity identity : agent.getIdentities()) {
|
||||
identities.add(new AuthAgent(agent, identity));
|
||||
}
|
||||
return identities.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ import org.jclouds.util.Closeables2;
|
|||
import org.jclouds.util.Throwables2;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Splitter;
|
||||
|
@ -76,6 +77,7 @@ import com.google.common.base.Throwables;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.google.inject.Inject;
|
||||
import com.jcraft.jsch.agentproxy.Connector;
|
||||
|
||||
/**
|
||||
* This class needs refactoring. It is not thread safe.
|
||||
|
@ -141,25 +143,28 @@ public class SshjSshClient implements SshClient {
|
|||
private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
|
||||
|
||||
public SshjSshClient(BackoffLimitedRetryHandler backoffLimitedRetryHandler, HostAndPort socket,
|
||||
LoginCredentials loginCredentials, int timeout) {
|
||||
LoginCredentials loginCredentials, int timeout, Optional<Connector> agentConnector) {
|
||||
this.user = checkNotNull(loginCredentials, "loginCredentials").getUser();
|
||||
this.host = checkNotNull(socket, "socket").getHostText();
|
||||
checkArgument(socket.getPort() > 0, "ssh port must be greater then zero" + socket.getPort());
|
||||
checkArgument(loginCredentials.getPassword() != null || loginCredentials.getPrivateKey() != null,
|
||||
"you must specify a password or a key");
|
||||
checkArgument(loginCredentials.getPassword() != null || loginCredentials.hasUnencryptedPrivateKey() || agentConnector.isPresent(),
|
||||
"you must specify a password, a key or an SSH agent needs to be available");
|
||||
this.backoffLimitedRetryHandler = checkNotNull(backoffLimitedRetryHandler, "backoffLimitedRetryHandler");
|
||||
if (loginCredentials.getPrivateKey() == null) {
|
||||
if (loginCredentials.getPassword() != null) {
|
||||
this.toString = String.format("%s:pw[%s]@%s:%d", loginCredentials.getUser(),
|
||||
base16().lowerCase().encode(md5().hashString(loginCredentials.getPassword(), UTF_8).asBytes()), host,
|
||||
socket.getPort());
|
||||
} else {
|
||||
} else if (loginCredentials.hasUnencryptedPrivateKey()) {
|
||||
String fingerPrint = fingerprintPrivateKey(loginCredentials.getPrivateKey());
|
||||
String sha1 = sha1PrivateKey(loginCredentials.getPrivateKey());
|
||||
this.toString = String.format("%s:rsa[fingerprint(%s),sha1(%s)]@%s:%d", loginCredentials.getUser(),
|
||||
fingerPrint, sha1, host, socket.getPort());
|
||||
} else {
|
||||
this.toString = String.format("%s:rsa[ssh-agent]@%s:%d", loginCredentials.getUser(),
|
||||
host, socket.getPort());
|
||||
}
|
||||
sshClientConnection = SSHClientConnection.builder().hostAndPort(HostAndPort.fromParts(host, socket.getPort()))
|
||||
.loginCredentials(loginCredentials).connectTimeout(timeout).sessionTimeout(timeout).build();
|
||||
.loginCredentials(loginCredentials).connectTimeout(timeout).sessionTimeout(timeout).agentConnector(agentConnector).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -25,11 +25,15 @@ import org.jclouds.ssh.SshClient;
|
|||
import org.jclouds.ssh.config.ConfiguresSshClient;
|
||||
import org.jclouds.sshj.SshjSshClient;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Scopes;
|
||||
import com.jcraft.jsch.agentproxy.AgentProxyException;
|
||||
import com.jcraft.jsch.agentproxy.Connector;
|
||||
import com.jcraft.jsch.agentproxy.ConnectorFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -42,11 +46,22 @@ public class SshjSshClientModule extends AbstractModule {
|
|||
bind(SshClient.Factory.class).to(Factory.class).in(Scopes.SINGLETON);
|
||||
}
|
||||
|
||||
|
||||
private static class Factory implements SshClient.Factory {
|
||||
@Named(Constants.PROPERTY_CONNECTION_TIMEOUT)
|
||||
@Inject(optional = true)
|
||||
int timeout = 60000;
|
||||
|
||||
Optional<Connector> agentConnector = getAgentConnector();
|
||||
|
||||
Optional<Connector> getAgentConnector() {
|
||||
try {
|
||||
return Optional.of(ConnectorFactory.getDefault().createConnector());
|
||||
} catch (final AgentProxyException e) {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
private final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
|
||||
private final Injector injector;
|
||||
|
||||
|
@ -58,9 +73,15 @@ public class SshjSshClientModule extends AbstractModule {
|
|||
|
||||
@Override
|
||||
public SshClient create(HostAndPort socket, LoginCredentials credentials) {
|
||||
SshClient client = new SshjSshClient(backoffLimitedRetryHandler, socket, credentials, timeout);
|
||||
SshClient client = new SshjSshClient(backoffLimitedRetryHandler, socket, credentials, timeout, getAgentConnector());
|
||||
injector.injectMembers(client);// add logger
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAgentAvailable() {
|
||||
return agentConnector.isPresent();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -469,6 +469,23 @@
|
|||
<package>com.google</package>
|
||||
</packages>
|
||||
</exception>
|
||||
<exception>
|
||||
<conflictingDependencies>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch.agentproxy.core</artifactId>
|
||||
<version>0.0.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch.agentproxy.connector-factory</artifactId>
|
||||
<version>0.0.7</version>
|
||||
</dependency>
|
||||
</conflictingDependencies>
|
||||
<packages>
|
||||
<package>com.jcraft.jsch.agentproxy</package>
|
||||
</packages>
|
||||
</exception>
|
||||
</exceptions>
|
||||
<ignoredResources>
|
||||
<!-- For all the jetty packages -->
|
||||
|
|
Loading…
Reference in New Issue