/* * Copyright 2012 aquenos GmbH. * All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html. */ package com.aquenos.scm.ssh.server; import java.io.IOException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import org.apache.shiro.subject.Subject; import org.apache.sshd.SshServer; import org.apache.sshd.common.Factory; import org.apache.sshd.common.Session.AttributeKey; import org.apache.sshd.server.Command; import org.apache.sshd.server.CommandFactory; import org.apache.sshd.server.PasswordAuthenticator; import org.apache.sshd.server.PublickeyAuthenticator; import org.apache.sshd.server.session.ServerSession; import com.google.inject.Inject; import com.google.inject.Singleton; /** * SSH server for SCM. * * @author Sebastian Marsching */ @Singleton public class ScmSshServer { /** * Key used for storing a {@link Subject} in a {@link ServerSession}. */ public final static AttributeKey<Subject> SUBJECT_SESSION_ATTRIBUTE_KEY = new AttributeKey<Subject>(); private SshServer sshServer; /** * Constructor. Meant to be called by Guice. * * @param passwordAuthenticator * authenticator used for password authentication. * @param publickeyAuthenticator * authenticator used for public-key authentication. * @param commandFactory * factory used to create SSH commands. * @param configStore * store the the SSH server configuration. * @param keyPairProvider * provider for SSH host keys. */ @Inject public ScmSshServer(PasswordAuthenticator passwordAuthenticator, PublickeyAuthenticator publickeyAuthenticator, CommandFactory commandFactory, ScmSshServerConfigurationStore configStore, ScmKeyPairProvider keyPairProvider) { ScmSshServerConfiguration config = configStore.load(); if (config == null) { config = new ScmSshServerConfiguration(); } sshServer = SshServer.setUpDefaultServer(); String listenAddress = config.getListenAddress(); if (listenAddress != null && !listenAddress.trim().isEmpty()) { sshServer.setHost(config.getListenAddress()); } sshServer.setPort(config.getListenPort()); sshServer.setKeyPairProvider(keyPairProvider); sshServer.setPasswordAuthenticator(passwordAuthenticator); sshServer.setPublickeyAuthenticator(publickeyAuthenticator); sshServer.setCommandFactory(commandFactory); sshServer.setShellFactory(new NoShellCommandFactory()); } /** * Starts the SSH server in a thread of its own. */ public void start() { try { sshServer.start(); } catch (IOException e) { throw new RuntimeException( "Error while trying to start SSH server: " + e.getMessage(), e); } } /** * Stops the SSH server. This method will block until the SSH server has * been stopped. */ public void stop() { try { sshServer.stop(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } /** * Simple command factory that creates a command which signals the client * that no shell is available. */ private class NoShellCommandFactory implements Factory<Command> { @Override public Command create() { return new AbstractCommand() { @Override protected int run() { try { PrintStream printStream = null; if (getErrorStream() != null) { printStream = new PrintStream(getErrorStream(), true, "UTF-8"); } else if (getOutputStream() != null) { printStream = new PrintStream(getOutputStream(), true, "UTF-8"); } if (printStream != null) { printStream.println("This is not a shell."); } } catch (UnsupportedEncodingException e) { // Ignore an unsupported-encoding exception. We just do // not write anything. } return 1; } }; } } }