2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
 
   6  * ================================================================================
 
   7  * Copyright (C) 2017 Amdocs
 
   8  * =============================================================================
 
   9  * Licensed under the Apache License, Version 2.0 (the "License");
 
  10  * you may not use this file except in compliance with the License.
 
  11  * You may obtain a copy of the License at
 
  13  *      http://www.apache.org/licenses/LICENSE-2.0
 
  15  * Unless required by applicable law or agreed to in writing, software
 
  16  * distributed under the License is distributed on an "AS IS" BASIS,
 
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  18  * See the License for the specific language governing permissions and
 
  19  * limitations under the License.
 
  21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
 
  22  * ============LICENSE_END=========================================================
 
  25 package org.onap.appc.adapter.ssh.sshd;
 
  27 import org.apache.sshd.SshServer;
 
  28 import org.apache.sshd.common.NamedFactory;
 
  29 import org.apache.sshd.common.util.OsUtils;
 
  30 import org.apache.sshd.server.Command;
 
  31 import org.apache.sshd.server.CommandFactory;
 
  32 import org.apache.sshd.server.PasswordAuthenticator;
 
  33 import org.apache.sshd.server.PublickeyAuthenticator;
 
  34 import org.apache.sshd.server.command.ScpCommandFactory;
 
  35 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 
  36 import org.apache.sshd.server.session.ServerSession;
 
  37 import org.apache.sshd.server.sftp.SftpSubsystem;
 
  38 import org.apache.sshd.server.shell.ProcessShellFactory;
 
  39 import org.hamcrest.CoreMatchers;
 
  41 import org.junit.rules.ExpectedException;
 
  42 import org.onap.appc.adapter.ssh.SshAdapter;
 
  43 import org.onap.appc.adapter.ssh.SshConnection;
 
  44 import org.onap.appc.adapter.ssh.SshException;
 
  45 import org.onap.appc.adapter.ssh.sshd.SshAdapterSshd;
 
  47 import java.io.ByteArrayOutputStream;
 
  48 import java.io.IOException;
 
  49 import java.io.OutputStream;
 
  50 import java.net.BindException;
 
  51 import java.security.PublicKey;
 
  52 import java.util.Collections;
 
  53 import java.util.EnumSet;
 
  55 public class SshAdapterTest {
 
  57     private static final boolean START_SERVER = true;
 
  58     private static final String SSH_HOST = "localhost";
 
  59     private static final int SSH_PORT = 2222;
 
  60     private static final String SSH_USERNAME = "test";
 
  61     private static final String SSH_PASSWORD = "test";
 
  62     private static final String F_TEST_CMD = "ping -%c 4 %s";
 
  64     private int sshPort = SSH_PORT;
 
  65     private SshServer sshd;
 
  66     private SshAdapter sshAdapter = new SshAdapterSshd();
 
  69     public ExpectedException thrown = ExpectedException.none();
 
  72     public void testExecute() {
 
  73         String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
 
  74         SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
 
  76             System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
 
  77             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
 
  78             ByteArrayOutputStream stderr = new ByteArrayOutputStream();
 
  79             int status = execCmd(sshConnection, cmd, stdout, stderr, false);
 
  80             Assert.assertEquals(stdout.toString() + ". " + stderr.toString(), 0, status);
 
  82             disconnect(sshConnection);
 
  87     public void testExecuteWithPty() {
 
  88         String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
 
  89         SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
 
  91             System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
 
  92             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
 
  93             int status = execCmd(sshConnection, cmd, stdout, null, true);
 
  94             Assert.assertEquals(stdout.toString() + ". " + stdout.toString(), 0, status);
 
  96             disconnect(sshConnection);
 
 101     public void testExecuteInvalidCommand() {
 
 102         String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "nosuchhost");
 
 103         SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
 
 105             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
 
 106             ByteArrayOutputStream stderr = new ByteArrayOutputStream();
 
 107             int status = execCmd(sshConnection, cmd, stdout, stderr, false);
 
 108             Assert.assertNotEquals(stdout.toString() + ". " + stderr.toString(), 0, status);
 
 110             disconnect(sshConnection);
 
 115     public void testWrongUsername() {
 
 116         thrown.expect(SshException.class);
 
 117         thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
 
 118         disconnect(connect("WrongUsername", SSH_PASSWORD));
 
 122     public void testWrongPassword() {
 
 123         thrown.expect(SshException.class);
 
 124         thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
 
 125         disconnect(connect(SSH_USERNAME, "WrongPassword"));
 
 129     public void beforeTest() throws IOException {
 
 136     public void afterTest() throws InterruptedException {
 
 140     private SshConnection connect(String username, String password) {
 
 141         SshConnection sshConnection = sshAdapter.getConnection(SSH_HOST, sshPort, username, password);
 
 142         sshConnection.connect();
 
 143         System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
 
 144         return sshConnection;
 
 147     private void disconnect(SshConnection sshConnection) {
 
 148         sshConnection.disconnect();
 
 149         System.out.println("SSH client disconnected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
 
 152     private int execCmd(SshConnection sshConnection, String cmd, OutputStream stdout, OutputStream stderr, boolean usePty) {
 
 153         System.out.println("=> Running command [" + cmd + "] over SSH");
 
 156             status = sshConnection.execCommandWithPty(cmd, stdout);
 
 158             status = sshConnection.execCommand(cmd, stdout, stderr);
 
 160         System.out.println("=> Command [" + cmd + "] status is [" + status + "], stdout is [" + String.valueOf(stdout) + "], stderr is [" + String.valueOf(stderr) + "]");
 
 164     private void startServer() throws IOException {
 
 165         sshd = SshServer.setUpDefaultServer();
 
 166         sshd.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(new SftpSubsystem.Factory()));
 
 167         sshd.setCommandFactory(new ScpCommandFactory(new CommandFactory() {
 
 169             public Command createCommand(String command) {
 
 170                 EnumSet<ProcessShellFactory.TtyOptions> ttyOptions;
 
 171                 if (OsUtils.isUNIX()) {
 
 172                     ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr);
 
 174                     ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr);
 
 176                 return new ProcessShellFactory(command.split(" "), ttyOptions).create();
 
 179         if (OsUtils.isUNIX()) {
 
 180             sshd.setShellFactory(new ProcessShellFactory(new String[]{"/bin/sh", "-i", "-l"},
 
 181                     EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr)));
 
 183             sshd.setShellFactory(new ProcessShellFactory(new String[]{"cmd.exe "},
 
 184                     EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr)));
 
 186 //              if(SecurityUtils.isBouncyCastleRegistered()) {
 
 187 //                      sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider(System.getProperty("java.io.tmpdir") + "/key.pem"));
 
 189         sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(System.getProperty("java.io.tmpdir") + "/key.ser"));
 
 191         sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
 
 194             public boolean authenticate(String username, String password, ServerSession session) {
 
 195                 return (SSH_USERNAME.equals(username) && SSH_PASSWORD.equals(password));
 
 198         sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {
 
 200             public boolean authenticate(String username, PublicKey key, ServerSession session) {
 
 204         sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD\n");
 
 208         } catch (InterruptedException e) {
 
 213     private void startServer0() throws IOException {
 
 214         boolean serverStarted = false;
 
 215         IOException exception = null;
 
 216         while (!serverStarted && (sshPort < Integer.MAX_VALUE)) {
 
 218                 System.out.println("Starting SSH server on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
 
 219                 sshd.setPort(sshPort);
 
 221                 serverStarted = true;
 
 222             } catch (BindException e) {
 
 223                 System.err.println("Cannot start SSH server on port [" + sshPort + "]. " + e.getMessage());
 
 224                 if (exception == null) {
 
 225                     // store first thrown exception - will be thrown if cannot start the server
 
 231         if (!serverStarted) {
 
 234         System.out.println("SSH server started on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
 
 237     private void stopServer() {
 
 241                 System.out.println("SSH server stopped on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
 
 243         } catch (InterruptedException e) {
 
 244             System.err.println("=> Error stopping SSH server.");