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();

Reply via email to