summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2010-11-05 18:30:07 -0700
committerShawn O. Pearce <sop@google.com>2010-11-05 18:30:07 -0700
commitcd67a8403f4040b55cf100c4f4474f54f7cfd8a2 (patch)
tree4111ded61e2e6f35d3cc9e209ae9661a629d6dc8
parent8a0bf3671171b3ba69dbfb6ac2e37fa3754daaee (diff)
Improve the no-interactive-shell error message over SSH
Present users with a more useful message that explains they have logged in, but aren't able to run commands directly through SSH. Change-Id: I9763ae6f28c2dd2aa7a3f3e41a9b13ef997a1f45 Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java157
-rw-r--r--gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java4
2 files changed, 134 insertions, 27 deletions
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
index 95c3416df1..431b4209bd 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/NoShell.java
@@ -14,15 +14,28 @@
package com.google.gerrit.sshd;
+import com.google.gerrit.reviewdb.Account;
+import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.ssh.SshInfo;
+import com.google.gerrit.sshd.SshScope.Context;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
import org.apache.sshd.common.Factory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
+import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.session.ServerSession;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.util.SystemReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
/**
* Dummy shell which prints a message and terminates.
@@ -32,41 +45,135 @@ import java.io.OutputStream;
* cannot continue further.
*/
class NoShell implements Factory<Command> {
+ private final Provider<SendMessage> shell;
+
+ @Inject
+ NoShell(Provider<SendMessage> shell) {
+ this.shell = shell;
+ }
+
public Command create() {
- return new Command() {
- private InputStream in;
- private OutputStream out;
- private OutputStream err;
- private ExitCallback exit;
-
- public void setInputStream(final InputStream in) {
- this.in = in;
- }
+ return shell.get();
+ }
- public void setOutputStream(final OutputStream out) {
- this.out = out;
- }
+ static class SendMessage implements Command, SessionAware {
+ private final Provider<MessageFactory> messageFactory;
+
+ private InputStream in;
+ private OutputStream out;
+ private OutputStream err;
+ private ExitCallback exit;
+ private Context context;
+
+ @Inject
+ SendMessage(Provider<MessageFactory> messageFactory) {
+ this.messageFactory = messageFactory;
+ }
+
+ public void setInputStream(final InputStream in) {
+ this.in = in;
+ }
+
+ public void setOutputStream(final OutputStream out) {
+ this.out = out;
+ }
+
+ public void setErrorStream(final OutputStream err) {
+ this.err = err;
+ }
- public void setErrorStream(final OutputStream err) {
- this.err = err;
+ public void setExitCallback(final ExitCallback callback) {
+ this.exit = callback;
+ }
+
+ public void setSession(final ServerSession session) {
+ this.context = new Context(session.getAttribute(SshSession.KEY), "");
+ }
+
+ public void start(final Environment env) throws IOException {
+ Context old = SshScope.set(context);
+ String message;
+ try {
+ message = messageFactory.get().getMessage();
+ } finally {
+ SshScope.set(old);
}
+ err.write(Constants.encodeASCII(message.toString()));
+ err.flush();
+
+ in.close();
+ out.close();
+ err.close();
+ exit.onExit(127);
+ }
+
+ public void destroy() {
+ }
+ }
+
+ static class MessageFactory {
+ private final IdentifiedUser user;
+ private final SshInfo sshInfo;
+ private final Provider<String> urlProvider;
- public void setExitCallback(final ExitCallback callback) {
- this.exit = callback;
+ @Inject
+ MessageFactory(IdentifiedUser user, SshInfo sshInfo,
+ @CanonicalWebUrl Provider<String> urlProvider) {
+ this.user = user;
+ this.sshInfo = sshInfo;
+ this.urlProvider = urlProvider;
+ }
+
+ String getMessage() {
+ StringBuilder msg = new StringBuilder();
+
+ msg.append("\r\n");
+ msg.append(" **** Welcome to Gerrit Code Review ****\r\n");
+ msg.append("\r\n");
+
+ Account account = user.getAccount();
+ String name = account.getFullName();
+ if (name == null || name.isEmpty()) {
+ name = user.getUserName();
}
+ msg.append(" Hi ");
+ msg.append(name);
+ msg.append(", you have successfully connected over SSH.");
+ msg.append("\r\n");
+ msg.append("\r\n");
- public void start(final Environment env) throws IOException {
- err.write(Constants.encodeASCII("gerrit: no shell available\r\n"));
- err.flush();
+ msg.append(" Unfortunately, interactive shells are disabled.\r\n");
+ msg.append(" To clone a hosted Git repository, use:\r\n");
+ msg.append("\r\n");
- in.close();
- out.close();
- err.close();
- exit.onExit(127);
+ if (!sshInfo.getHostKeys().isEmpty()) {
+ String host = sshInfo.getHostKeys().get(0).getHost();
+ if (host.startsWith("*:")) {
+ host = getGerritHost() + host.substring(1);
+ }
+
+ msg.append(" git clone ssh://");
+ msg.append(user.getUserName());
+ msg.append("@");
+ msg.append(host);
+ msg.append("/");
+ msg.append("REPOSITORY_NAME.git");
+ msg.append("\r\n");
}
- public void destroy() {
+ msg.append("\r\n");
+ return msg.toString();
+ }
+
+ private String getGerritHost() {
+ String url = urlProvider.get();
+ if (url != null) {
+ try {
+ return new URL(url).getHost();
+ } catch (MalformedURLException e) {
+ }
}
- };
+ return SystemReader.getInstance().getHostname();
+ }
}
}
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 ae7b65daa2..dee55a5922 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
@@ -124,7 +124,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
private volatile IoAcceptor acceptor;
@Inject
- SshDaemon(final CommandFactory commandFactory,
+ SshDaemon(final CommandFactory commandFactory, final NoShell noShell,
final PublickeyAuthenticator userAuth,
final KeyPairProvider hostKeyProvider, final IdGenerator idGenerator,
@GerritServerConfig final Config cfg, final SshLog sshLog) {
@@ -169,7 +169,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener {
initUserAuth(userAuth);
setKeyPairProvider(hostKeyProvider);
setCommandFactory(commandFactory);
- setShellFactory(new NoShell());
+ setShellFactory(noShell);
setSessionFactory(new SessionFactory() {
@Override
protected ServerSession createSession(final IoSession io)