Repository: mina-sshd Updated Branches: refs/heads/master 8ba704888 -> 5a66fdf3b
[SSHD-700] SSHD does not suppot agent forwarding for XShell and XAgent Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/5a66fdf3 Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/5a66fdf3 Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/5a66fdf3 Branch: refs/heads/master Commit: 5a66fdf3b069ce128c1e459eb3ccf4b6ca8a10fd Parents: 8ba7048 Author: Li Fangning <lifangn...@hotmail.com> Authored: Sat Jul 15 17:48:51 2017 +0300 Committer: Goldstein Lyor <l...@c-b4.com> Committed: Sun Jul 16 11:00:51 2017 +0300 ---------------------------------------------------------------------- .../apache/sshd/agent/SshAgentConstants.java | 8 +++ .../org/apache/sshd/agent/SshAgentFactory.java | 3 + .../sshd/agent/common/AbstractAgentProxy.java | 59 ++++++++++++++++---- .../sshd/agent/local/AgentForwardedChannel.java | 6 +- .../sshd/agent/local/ProxyAgentFactory.java | 23 +++++++- .../org/apache/sshd/common/FactoryManager.java | 16 ++++++ .../sshd/server/channel/ChannelSession.java | 1 + 7 files changed, 102 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5a66fdf3/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentConstants.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentConstants.java b/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentConstants.java index 3c86197..83443ff 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentConstants.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentConstants.java @@ -69,6 +69,14 @@ public final class SshAgentConstants { public static final byte SSH_AGENT_CONSTRAIN_LIFETIME = 1; public static final byte SSH_AGENT_CONSTRAIN_CONFIRM = 2; + // Packet types defined by IETF (https://tools.ietf.org/html/draft-ietf-secsh-agent-02) + // Messages sent by the client + public static final int SSH_AGENT_LIST_KEYS = 204; + public static final int SSH_AGENT_PRIVATE_KEY_OP = 205; + // Messages sent by the agent + public static final byte SSH_AGENT_KEY_LIST = 104; + public static final byte SSH_AGENT_OPERATION_COMPLETE = 105; + private SshAgentConstants() { } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5a66fdf3/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java b/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java index 551d14d..9b44d27 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/SshAgentFactory.java @@ -39,6 +39,9 @@ public interface SshAgentFactory { // see also https://tools.ietf.org/html/draft-ietf-secsh-agent-02 String DEFAULT_PROXY_AUTH_CHANNEL_TYPE = "auth-agent-...@openssh.com"; + // See ProxyAgentFactory#getChannelForwardingFactories + String PREFER_UNIX_AGENT = "ssh-prefer-unix-agent"; + /** * The channels are requested by the ssh server when forwarding a client request. * The channel will receive agent requests and need to forward them to the agent, http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5a66fdf3/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java index c038e7f..21bd92c 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java @@ -28,6 +28,7 @@ import java.util.concurrent.ExecutorService; import org.apache.sshd.agent.SshAgent; import org.apache.sshd.agent.SshAgentConstants; +import org.apache.sshd.common.FactoryManager; import org.apache.sshd.common.SshException; import org.apache.sshd.common.config.keys.KeyUtils; import org.apache.sshd.common.util.GenericUtils; @@ -42,13 +43,23 @@ import org.apache.sshd.common.util.threads.ExecutorServiceConfigurer; * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> */ public abstract class AbstractAgentProxy extends AbstractLoggingBean implements SshAgent, ExecutorServiceConfigurer { + private ExecutorService executor; private boolean shutdownExecutor; + private String channelType = FactoryManager.AGENT_FORWARDING_TYPE_OPENSSH; protected AbstractAgentProxy() { super(); } + public String getChannelType() { + return channelType; + } + + public void setChannelType(String channelType) { + this.channelType = channelType; + } + @Override public ExecutorService getExecutorService() { return executor; @@ -71,10 +82,17 @@ public abstract class AbstractAgentProxy extends AbstractLoggingBean implements @Override public List<Pair<PublicKey, String>> getIdentities() throws IOException { - Buffer buffer = createBuffer(SshAgentConstants.SSH2_AGENTC_REQUEST_IDENTITIES, 1); + int cmd = SshAgentConstants.SSH2_AGENTC_REQUEST_IDENTITIES; + int okcmd = SshAgentConstants.SSH2_AGENT_IDENTITIES_ANSWER; + if (FactoryManager.AGENT_FORWARDING_TYPE_IETF.equals(channelType)) { + cmd = SshAgentConstants.SSH_AGENT_LIST_KEYS; + okcmd = SshAgentConstants.SSH_AGENT_KEY_LIST; + } + + Buffer buffer = createBuffer((byte) cmd, 1); buffer = request(prepare(buffer)); int type = buffer.getUByte(); - if (type != SshAgentConstants.SSH2_AGENT_IDENTITIES_ANSWER) { + if (type != okcmd) { throw new SshException("Bad agent identities answer: " + SshAgentConstants.getCommandMessageName(type)); } @@ -99,24 +117,43 @@ public abstract class AbstractAgentProxy extends AbstractLoggingBean implements @Override public byte[] sign(PublicKey key, byte[] data) throws IOException { - Buffer buffer = createBuffer(SshAgentConstants.SSH2_AGENTC_SIGN_REQUEST); + int cmd = SshAgentConstants.SSH2_AGENTC_SIGN_REQUEST; + int okcmd = SshAgentConstants.SSH2_AGENT_SIGN_RESPONSE; + if (FactoryManager.AGENT_FORWARDING_TYPE_IETF.equals(channelType)) { + cmd = SshAgentConstants.SSH_AGENT_PRIVATE_KEY_OP; + okcmd = SshAgentConstants.SSH_AGENT_OPERATION_COMPLETE; + } + + Buffer buffer = createBuffer((byte) cmd); + if (FactoryManager.AGENT_FORWARDING_TYPE_IETF.equals(channelType)) { + buffer.putString("sign"); + } buffer.putPublicKey(key); buffer.putBytes(data); buffer.putInt(0); buffer = request(prepare(buffer)); int responseType = buffer.getUByte(); - if (responseType != SshAgentConstants.SSH2_AGENT_SIGN_RESPONSE) { + if (responseType != okcmd) { throw new SshException("Bad signing response type: " + SshAgentConstants.getCommandMessageName(responseType)); } - Buffer buf = new ByteArrayBuffer(buffer.getBytes()); - String algorithm = buf.getString(); - byte[] signature = buf.getBytes(); - if (log.isDebugEnabled()) { - log.debug("sign({})[{}] {}: {}", - KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key), - algorithm, BufferUtils.toHex(':', signature)); + byte[] signature = buffer.getBytes(); + if (FactoryManager.AGENT_FORWARDING_TYPE_IETF.equals(channelType)) { + if (log.isDebugEnabled()) { + log.debug("sign({})[{}] : {}", + KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key), + BufferUtils.toHex(':', signature)); + } + } else { + Buffer buf = new ByteArrayBuffer(signature); + String algorithm = buf.getString(); + signature = buf.getBytes(); + if (log.isDebugEnabled()) { + log.debug("sign({})[{}] {}: {}", + KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key), + algorithm, BufferUtils.toHex(':', signature)); + } } return signature; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5a66fdf3/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java index 355856a..9306bc8 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentForwardedChannel.java @@ -28,6 +28,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.sshd.agent.SshAgent; import org.apache.sshd.agent.common.AbstractAgentProxy; import org.apache.sshd.client.channel.AbstractClientChannel; +import org.apache.sshd.common.FactoryManager; +import org.apache.sshd.common.PropertyResolverUtils; import org.apache.sshd.common.SshConstants; import org.apache.sshd.common.channel.ChannelOutputStream; import org.apache.sshd.common.channel.Window; @@ -44,7 +46,7 @@ public class AgentForwardedChannel extends AbstractClientChannel { } public SshAgent getAgent() { - return new AbstractAgentProxy() { + AbstractAgentProxy rtn = new AbstractAgentProxy() { private final AtomicBoolean open = new AtomicBoolean(true); @Override @@ -65,6 +67,8 @@ public class AgentForwardedChannel extends AbstractClientChannel { } } }; + rtn.setChannelType(PropertyResolverUtils.getString(getSession(), FactoryManager.AGENT_FORWARDING_TYPE)); + return rtn; } protected Buffer request(Buffer buffer) throws IOException { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5a66fdf3/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java index 4c7a5d3..ab19539 100644 --- a/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java +++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/ProxyAgentFactory.java @@ -27,13 +27,17 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.apache.sshd.agent.SshAgent; import org.apache.sshd.agent.SshAgentFactory; import org.apache.sshd.agent.SshAgentServer; +import org.apache.sshd.agent.unix.AprLibrary; import org.apache.sshd.agent.unix.UnixAgentFactory; import org.apache.sshd.common.FactoryManager; import org.apache.sshd.common.NamedFactory; +import org.apache.sshd.common.PropertyResolver; +import org.apache.sshd.common.PropertyResolverUtils; import org.apache.sshd.common.channel.Channel; import org.apache.sshd.common.session.ConnectionService; import org.apache.sshd.common.session.Session; import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.OsUtils; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.server.session.ServerSession; @@ -49,7 +53,9 @@ public class ProxyAgentFactory implements SshAgentFactory { @Override public List<NamedFactory<Channel>> getChannelForwardingFactories(FactoryManager manager) { - return UnixAgentFactory.DEFAULT_FORWARDING_CHANNELS; + return isPreferredUnixAgent(manager) + ? UnixAgentFactory.DEFAULT_FORWARDING_CHANNELS + : LocalAgentFactory.DEFAULT_FORWARDING_CHANNELS; } @Override @@ -73,7 +79,7 @@ public class ProxyAgentFactory implements SshAgentFactory { ValidateUtils.checkInstanceOf(session, ServerSession.class, "The session used to create an agent server proxy must be a server session: %s", session); - final AgentServerProxy proxy = new AgentServerProxy(service); + AgentServerProxy proxy = new AgentServerProxy(service); proxies.put(proxy.getId(), proxy); return new SshAgentServer() { private final AtomicBoolean open = new AtomicBoolean(true); @@ -99,4 +105,17 @@ public class ProxyAgentFactory implements SshAgentFactory { }; } + public static boolean isPreferredUnixAgent(PropertyResolver resolver) { + if (PropertyResolverUtils.getBooleanProperty(resolver, PREFER_UNIX_AGENT, OsUtils.isUNIX())) { + try { + if (AprLibrary.getInstance() != null) { + return true; + } + } catch (Exception ignore) { + // ignored + } + } + + return false; + } } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5a66fdf3/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java index 0717323..8652cd8 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/FactoryManager.java @@ -349,6 +349,22 @@ public interface FactoryManager String IGNORE_MESSAGE_SIZE = "ignore-message-size"; /** + * The request type of agent forwarding. The value may be {@value #AGENT_FORWARDING_TYPE_IETF} or + * {@value #AGENT_FORWARDING_TYPE_OPENSSH}. + */ + String AGENT_FORWARDING_TYPE = "agent-fw-auth-type"; + + /** + * The agent forwarding type defined by IETF (https://tools.ietf.org/html/draft-ietf-secsh-agent-02). + */ + String AGENT_FORWARDING_TYPE_IETF = "auth-agent-req"; + + /** + * The agent forwarding type defined by OpenSSH. + */ + String AGENT_FORWARDING_TYPE_OPENSSH = "auth-agent-...@openssh.com"; + + /** * Value of {@value #IGNORE_MESSAGE_SIZE} if none configured */ int DEFAULT_IGNORE_MESSAGE_SIZE = 16; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/5a66fdf3/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java index fcdc6bd..053d2bc 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java @@ -698,6 +698,7 @@ public class ChannelSession extends AbstractServerChannel { protected RequestHandler.Result handleAgentForwarding(String requestType, Buffer buffer, boolean wantReply) throws IOException { ServerSession session = getServerSession(); + PropertyResolverUtils.updateProperty(session, FactoryManager.AGENT_FORWARDING_TYPE, requestType); FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No session factory manager"); ForwardingFilter filter = manager.getTcpipForwardingFilter(); SshAgentFactory factory = manager.getAgentFactory();