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
This commit is contained in:
Shawn Pearce
2013-11-08 20:48:02 -08:00
8 changed files with 151 additions and 75 deletions

View File

@@ -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);
}
}

View File

@@ -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.google.inject.Singleton;
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.BlowfishCBC;
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.mac.HMACSHA196;
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 org.slf4j.LoggerFactory;
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 @@ import java.util.List;
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 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
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 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
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 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
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 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
initMacs(cfg);
initSignatures();
initChannels();
initForwardingFilter();
initForwarding();
initFileSystemFactory();
initSubsystems();
initCompression();
@@ -202,24 +212,28 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
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 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
});
return s;
}
@Override
protected AbstractSession doCreateSession(IoSession ioSession)
throws Exception {
return new GerritServerSession(server, ioSession);
}
});
hostKeys = computeHostKeys();
@@ -245,13 +265,11 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
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 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
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 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
private void initChannels() {
setChannelFactories(Arrays.<NamedFactory<Channel>> asList(
new ChannelSession.Factory(), //
new ChannelDirectTcpip.Factory() //
new TcpipServerChannel.DirectTcpipFactory() //
));
}
@@ -514,28 +533,29 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
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() {

View File

@@ -21,8 +21,8 @@ import com.google.gerrit.server.IdentifiedUser;
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 @@ public class SshUtil {
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 {

View File

@@ -30,8 +30,9 @@ import com.google.gerrit.sshd.SshDaemon;
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 @@ final class ShowCaches extends CacheCommand {
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(

View File

@@ -25,8 +25,10 @@ import com.google.gerrit.sshd.SshDaemon;
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 @@ final class ShowConnections extends SshCommand {
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 @@ final class ShowConnections extends SshCommand {
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), //