Merge branch 'stable-2.6' into stable-2.7

* stable-2.6:
  Bump SSHD version to 0.9.0.201311081

Conflicts:
	gerrit-sshd/src/main/java/com/google/gerrit/sshd/DatabasePubKeyAuth.java
	gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java

Change-Id: Iacee71305c167687c8f70836bff802b1dfec2082
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index daafcf1..93492ba 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2299,6 +2299,14 @@
 [[sshd]] Section sshd
 ~~~~~~~~~~~~~~~~~~~~~
 
+[[sshd.backend]]sshd.backend::
++
+Starting from version 0.9.0 Apache SSHD project added support for NIO2
+IoSession. To use the new NIO2 session the `backend` option must be set
+to `NIO2`.
++
+By default, `MINA`.
+
 [[sshd.listenAddress]]sshd.listenAddress::
 +
 Specifies the local addresses the internal SSHD should listen
@@ -2337,20 +2345,13 @@
 +
 By default, sshd.listenAddress.
 
-[[sshd.reuseAddress]]sshd.reuseAddress::
-+
-If true, permits the daemon to bind to the port even if the port
-is already in use.  If false, the daemon ensures the port is not
-in use before starting.  Busy sites may need to set this to true
-to permit fast restarts.
-+
-By default, true.
-
 [[sshd.tcpKeepAlive]]sshd.tcpKeepAlive::
 +
 If true, enables TCP keepalive messages to the other side, so
 the daemon can terminate connections if the peer disappears.
 +
+Only effective when `sshd.backend` is set to `MINA`.
++
 By default, true.
 
 [[sshd.threads]]sshd.threads::
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java
new file mode 100644
index 0000000..b7f7c22
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/GerritServerSession.java
@@ -0,0 +1,34 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.sshd;
+
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.server.ServerFactoryManager;
+import org.apache.sshd.server.session.ServerSession;
+
+/* Expose addition of close session listeners */
+class GerritServerSession extends ServerSession {
+
+  GerritServerSession(ServerFactoryManager server,
+      IoSession ioSession) throws Exception {
+    super(server, ioSession);
+  }
+
+  void addCloseSessionListener(SshFutureListener<CloseFuture> l) {
+    closeFuture.addListener(l);
+  }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
index 8519e94..bafc388 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java
@@ -15,7 +15,6 @@
 package com.google.gerrit.sshd;
 
 import static com.google.gerrit.server.ssh.SshAddressesModule.IANA_SSH_PORT;
-
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 
@@ -35,20 +34,18 @@
 import com.jcraft.jsch.HostKey;
 import com.jcraft.jsch.JSchException;
 
-import org.apache.mina.core.future.IoFuture;
-import org.apache.mina.core.future.IoFutureListener;
-import org.apache.mina.core.service.IoAcceptor;
-import org.apache.mina.core.session.IoSession;
 import org.apache.mina.transport.socket.SocketSessionConfig;
 import org.apache.sshd.SshServer;
 import org.apache.sshd.common.Channel;
 import org.apache.sshd.common.Cipher;
 import org.apache.sshd.common.Compression;
+import org.apache.sshd.common.ForwardingFilter;
 import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.Session;
 import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.common.cipher.AES128CBC;
 import org.apache.sshd.common.cipher.AES192CBC;
 import org.apache.sshd.common.cipher.AES256CBC;
@@ -56,6 +53,19 @@
 import org.apache.sshd.common.cipher.CipherNone;
 import org.apache.sshd.common.cipher.TripleDESCBC;
 import org.apache.sshd.common.compression.CompressionNone;
+import org.apache.sshd.common.file.FileSystemFactory;
+import org.apache.sshd.common.file.FileSystemView;
+import org.apache.sshd.common.file.SshFile;
+import org.apache.sshd.common.forward.DefaultTcpipForwarderFactory;
+import org.apache.sshd.common.forward.TcpipServerChannel;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.io.IoAcceptor;
+import org.apache.sshd.common.io.IoServiceFactory;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.mina.MinaServiceFactory;
+import org.apache.sshd.common.io.mina.MinaSession;
+import org.apache.sshd.common.io.nio2.Nio2ServiceFactory;
 import org.apache.sshd.common.mac.HMACMD5;
 import org.apache.sshd.common.mac.HMACMD596;
 import org.apache.sshd.common.mac.HMACSHA1;
@@ -63,26 +73,21 @@
 import org.apache.sshd.common.random.BouncyCastleRandom;
 import org.apache.sshd.common.random.JceRandom;
 import org.apache.sshd.common.random.SingletonRandomFactory;
+import org.apache.sshd.common.session.AbstractSession;
 import org.apache.sshd.common.signature.SignatureDSA;
 import org.apache.sshd.common.signature.SignatureRSA;
 import org.apache.sshd.common.util.Buffer;
 import org.apache.sshd.common.util.SecurityUtils;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.CommandFactory;
-import org.apache.sshd.server.FileSystemFactory;
-import org.apache.sshd.server.FileSystemView;
-import org.apache.sshd.server.ForwardingFilter;
 import org.apache.sshd.server.PublickeyAuthenticator;
-import org.apache.sshd.server.SshFile;
 import org.apache.sshd.server.UserAuth;
 import org.apache.sshd.server.auth.UserAuthPublicKey;
 import org.apache.sshd.server.auth.gss.GSSAuthenticator;
 import org.apache.sshd.server.auth.gss.UserAuthGSS;
-import org.apache.sshd.server.channel.ChannelDirectTcpip;
 import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.kex.DHG1;
 import org.apache.sshd.server.kex.DHG14;
-import org.apache.sshd.server.session.ServerSession;
 import org.apache.sshd.server.session.SessionFactory;
 import org.eclipse.jgit.lib.Config;
 import org.slf4j.Logger;
@@ -91,7 +96,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
-import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.net.UnknownHostException;
 import java.security.InvalidKeyException;
@@ -126,6 +130,11 @@
 public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
   private static final Logger log = LoggerFactory.getLogger(SshDaemon.class);
 
+  public static enum SshSessionBackend {
+    MINA,
+    NIO2
+  }
+
   private final List<SocketAddress> listen;
   private final List<String> advertised;
   private final boolean keepAlive;
@@ -144,7 +153,6 @@
 
     this.listen = listen;
     this.advertised = advertised;
-    reuseAddress = cfg.getBoolean("sshd", "reuseaddress", true);
     keepAlive = cfg.getBoolean("sshd", "tcpkeepalive", true);
 
     getProperties().put(SERVER_IDENTIFICATION,
@@ -161,12 +169,6 @@
 
     long idleTimeoutSeconds = ConfigUtil.getTimeUnit(cfg, "sshd", null,
         "idleTimeout", 0, SECONDS);
-    if (idleTimeoutSeconds == 0) {
-      // Since Apache SSHD does not allow to turn off closing idle connections,
-      // we fake it by using the highest timeout allowed by Apache SSHD, which
-      // amounts to ~24 days.
-      idleTimeoutSeconds = MILLISECONDS.toSeconds(Integer.MAX_VALUE);
-    }
     getProperties().put(
         IDLE_TIMEOUT,
         String.valueOf(SECONDS.toMillis(idleTimeoutSeconds)));
@@ -183,6 +185,14 @@
     final String kerberosPrincipal = cfg.getString(
         "sshd", null, "kerberosPrincipal");
 
+    SshSessionBackend backend = cfg.getEnum(
+        "sshd", null, "backend", SshSessionBackend.MINA);
+
+    System.setProperty(IoServiceFactory.class.getName(),
+        backend == SshSessionBackend.MINA
+            ? MinaServiceFactory.class.getName()
+            : Nio2ServiceFactory.class.getName());
+
     if (SecurityUtils.isBouncyCastleRegistered()) {
       initProviderBouncyCastle();
     } else {
@@ -192,7 +202,7 @@
     initMacs(cfg);
     initSignatures();
     initChannels();
-    initForwardingFilter();
+    initForwarding();
     initFileSystemFactory();
     initSubsystems();
     initCompression();
@@ -202,24 +212,28 @@
     setShellFactory(noShell);
     setSessionFactory(new SessionFactory() {
       @Override
-      protected ServerSession createSession(final IoSession io)
+      protected AbstractSession createSession(final IoSession io)
           throws Exception {
-        if (io.getConfig() instanceof SocketSessionConfig) {
-          final SocketSessionConfig c = (SocketSessionConfig) io.getConfig();
-          c.setKeepAlive(keepAlive);
+        if (io instanceof MinaSession) {
+          if (((MinaSession) io).getSession()
+              .getConfig() instanceof SocketSessionConfig) {
+            ((SocketSessionConfig) ((MinaSession) io).getSession()
+                .getConfig())
+                .setKeepAlive(keepAlive);
+          }
         }
 
-        final ServerSession s = (ServerSession) super.createSession(io);
-        final int id = idGenerator.next();
-        final SocketAddress peer = io.getRemoteAddress();
+        GerritServerSession s = (GerritServerSession)super.createSession(io);
+        int id = idGenerator.next();
+        SocketAddress peer = io.getRemoteAddress();
         final SshSession sd = new SshSession(id, peer);
         s.setAttribute(SshSession.KEY, sd);
 
         // Log a session close without authentication as a failure.
         //
-        io.getCloseFuture().addListener(new IoFutureListener<IoFuture>() {
+        s.addCloseSessionListener(new SshFutureListener<CloseFuture>() {
           @Override
-          public void operationComplete(IoFuture future) {
+          public void operationComplete(CloseFuture future) {
             if (sd.isAuthenticationError()) {
               sshLog.onAuthFail(sd);
             }
@@ -227,6 +241,12 @@
         });
         return s;
       }
+
+      @Override
+      protected AbstractSession doCreateSession(IoSession ioSession)
+          throws Exception {
+        return new GerritServerSession(server, ioSession);
+      }
     });
 
     hostKeys = computeHostKeys();
@@ -245,13 +265,11 @@
   public synchronized void start() {
     if (acceptor == null && !listen.isEmpty()) {
       checkConfig();
-
+      if (sessionFactory == null) {
+        sessionFactory = createSessionFactory();
+      }
+      sessionFactory.setServer(this);
       acceptor = createAcceptor();
-      configure(acceptor);
-
-      final SessionFactory handler = getSessionFactory();
-      handler.setServer(this);
-      acceptor.setHandler(handler);
 
       try {
         acceptor.bind(listen);
@@ -259,7 +277,8 @@
         throw new IllegalStateException("Cannot bind to " + addressList(), e);
       }
 
-      log.info("Started Gerrit SSHD on " + addressList());
+      log.info(String.format("Started Gerrit %s on %s",
+          version, addressList()));
     }
   }
 
@@ -473,7 +492,7 @@
   private void initChannels() {
     setChannelFactories(Arrays.<NamedFactory<Channel>> asList(
         new ChannelSession.Factory(), //
-        new ChannelDirectTcpip.Factory() //
+        new TcpipServerChannel.DirectTcpipFactory() //
         ));
   }
 
@@ -514,28 +533,29 @@
     setPublickeyAuthenticator(pubkey);
   }
 
-  private void initForwardingFilter() {
-    setForwardingFilter(new ForwardingFilter() {
+  private void initForwarding() {
+    setTcpipForwardingFilter(new ForwardingFilter() {
       @Override
-      public boolean canForwardAgent(ServerSession session) {
-        return false;
+      public boolean canForwardAgent(Session session) {
+          return false;
       }
 
       @Override
-      public boolean canForwardX11(ServerSession session) {
-        return false;
+      public boolean canForwardX11(Session session) {
+          return false;
       }
 
       @Override
-      public boolean canConnect(InetSocketAddress address, ServerSession session) {
-        return false;
+      public boolean canListen(SshdSocketAddress address, Session session) {
+          return false;
       }
 
       @Override
-      public boolean canListen(InetSocketAddress address, ServerSession session) {
-        return false;
+      public boolean canConnect(SshdSocketAddress address, Session session) {
+          return false;
       }
     });
+    setTcpipForwarderFactory(new DefaultTcpipForwarderFactory());
   }
 
   private void initFileSystemFactory() {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
index 6a4d995..74e6d1b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshUtil.java
@@ -21,8 +21,8 @@
 import com.google.gerrit.sshd.SshScope.Context;
 
 import org.apache.commons.codec.binary.Base64;
-import org.apache.mina.core.future.IoFuture;
-import org.apache.mina.core.future.IoFutureListener;
+import org.apache.sshd.common.future.CloseFuture;
+import org.apache.sshd.common.future.SshFutureListener;
 import org.apache.sshd.common.KeyPairProvider;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.util.Buffer;
@@ -138,10 +138,11 @@
         sshScope.set(old);
       }
 
-      session.getIoSession().getCloseFuture().addListener(
-          new IoFutureListener<IoFuture>() {
+      GerritServerSession s = (GerritServerSession) session;
+      s.addCloseSessionListener(
+          new SshFutureListener<CloseFuture>() {
             @Override
-            public void operationComplete(IoFuture future) {
+            public void operationComplete(CloseFuture future) {
               final Context ctx = sshScope.newContext(null, sd, null);
               final Context old = sshScope.set(ctx);
               try {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
index 3366841..fbc0e75 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowCaches.java
@@ -30,8 +30,9 @@
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
-import org.apache.mina.core.service.IoAcceptor;
-import org.apache.mina.core.session.IoSession;
+import org.apache.sshd.common.io.IoAcceptor;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.mina.MinaSession;
 import org.apache.sshd.server.Environment;
 import org.eclipse.jgit.internal.storage.file.WindowCacheStatAccessor;
 import org.kohsuke.args4j.Option;
@@ -275,8 +276,12 @@
     long now = System.currentTimeMillis();
     Collection<IoSession> list = acceptor.getManagedSessions().values();
     long oldest = now;
+
     for (IoSession s : list) {
-      oldest = Math.min(oldest, s.getCreationTime());
+      if (s instanceof MinaSession) {
+        MinaSession minaSession = (MinaSession)s;
+        oldest = Math.min(oldest, minaSession.getSession().getCreationTime());
+      }
     }
 
     stdout.format(
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
index 1c3d828..47ec5e4 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ShowConnections.java
@@ -25,8 +25,10 @@
 import com.google.gerrit.sshd.SshSession;
 import com.google.inject.Inject;
 
-import org.apache.mina.core.service.IoAcceptor;
-import org.apache.mina.core.session.IoSession;
+import org.apache.sshd.common.io.IoAcceptor;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.io.mina.MinaSession;
+import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.session.ServerSession;
 import org.kohsuke.args4j.Option;
 
@@ -62,10 +64,16 @@
     Collections.sort(list, new Comparator<IoSession>() {
       @Override
       public int compare(IoSession arg0, IoSession arg1) {
-        if (arg0.getCreationTime() < arg1.getCreationTime()) {
-          return -1;
-        } else if (arg0.getCreationTime() > arg1.getCreationTime()) {
-          return 1;
+        if (arg0 instanceof MinaSession) {
+          MinaSession mArg0 = (MinaSession) arg0;
+          MinaSession mArg1 = (MinaSession) arg1;
+          if (mArg0.getSession().getCreationTime() < mArg1.getSession()
+              .getCreationTime()) {
+            return -1;
+          } else if (mArg0.getSession().getCreationTime() > mArg1.getSession()
+              .getCreationTime()) {
+            return 1;
+          }
         }
         return (int) (arg0.getId() - arg1.getId());
       }
@@ -80,8 +88,15 @@
       SshSession sd = s != null ? s.getAttribute(SshSession.KEY) : null;
 
       final SocketAddress remoteAddress = io.getRemoteAddress();
-      final long start = io.getCreationTime();
-      final long idle = now - io.getLastIoTime();
+      MinaSession minaSession = io instanceof MinaSession
+          ? (MinaSession) io
+          : null;
+      final long start = minaSession == null
+          ? 0
+          : minaSession.getSession().getCreationTime();
+      final long idle = minaSession == null
+          ? now
+          : now - minaSession.getSession().getLastIoTime();
 
       stdout.print(String.format("%8s %8s %8s  %-15.15s %.30s\n", //
           id(sd), //
diff --git a/gerrit-war/src/main/resources/log4j.properties b/gerrit-war/src/main/resources/log4j.properties
index 1fcca6d..cb14916 100644
--- a/gerrit-war/src/main/resources/log4j.properties
+++ b/gerrit-war/src/main/resources/log4j.properties
@@ -26,7 +26,7 @@
 log4j.logger.org.apache.sshd.common=WARN
 log4j.logger.org.apache.sshd.server=WARN
 log4j.logger.org.apache.sshd.common.keyprovider.FileKeyPairProvider=INFO
-log4j.logger.com.google.gerrit.server.ssh.GerritServerSession=WARN
+log4j.logger.com.google.gerrit.sshd.GerritServerSession=WARN
 
 # Silence non-critical messages from Jetty.
 #
diff --git a/pom.xml b/pom.xml
index a206560..7f6cc87 100644
--- a/pom.xml
+++ b/pom.xml
@@ -570,13 +570,13 @@
       <dependency>
         <groupId>org.apache.mina</groupId>
         <artifactId>mina-core</artifactId>
-        <version>2.0.5</version>
+        <version>2.0.7</version>
       </dependency>
 
       <dependency>
         <groupId>org.apache.sshd</groupId>
         <artifactId>sshd-core</artifactId>
-        <version>0.6.0</version>
+        <version>0.9.0.201311081</version>
       </dependency>
 
       <dependency>