2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Copyright (C) 2017 Amdocs
8 * ================================================================================
9 * Modifications Copyright (C) 2019 Ericsson
10 * =============================================================================
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
23 * ============LICENSE_END=========================================================
26 package org.onap.ccsdk.sli.adaptors.ssh.sshd;
28 import java.io.ByteArrayOutputStream;
29 import java.io.IOException;
30 import java.io.OutputStream;
31 import java.net.BindException;
32 import java.nio.file.Paths;
33 import java.util.Collections;
34 import org.apache.sshd.common.util.OsUtils;
35 import org.apache.sshd.server.SshServer;
36 import org.apache.sshd.server.ServerFactoryManager;
37 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
38 import org.apache.sshd.server.scp.ScpCommandFactory;
39 import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
40 import org.hamcrest.CoreMatchers;
41 import org.junit.After;
42 import org.junit.Assert;
43 import org.junit.Before;
44 import org.junit.Ignore;
45 import org.junit.Rule;
46 import org.junit.Test;
47 import org.junit.rules.ExpectedException;
48 import org.onap.ccsdk.sli.adaptors.ssh.SshAdaptor;
49 import org.onap.ccsdk.sli.adaptors.ssh.SshConnection;
50 import org.onap.ccsdk.sli.adaptors.ssh.SshException;
52 import static org.junit.Assert.assertTrue;
55 public class SshAdaptorTest {
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 final SshAdaptor sshAdaptor = new SshAdaptorSshd();
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();
75 if (sshConnection == null) return;
77 System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
78 ByteArrayOutputStream stdout = new ByteArrayOutputStream();
79 ByteArrayOutputStream stderr = new ByteArrayOutputStream();
80 int status = execCmd(sshConnection, cmd, stdout, stderr, false);
81 Assert.assertEquals(stdout + ". " + stderr, 0, status);
83 disconnect(sshConnection);
88 public void testExecuteWithPty() {
89 String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
90 SshConnection sshConnection = connect();
91 if (sshConnection == null) return;
93 System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
94 ByteArrayOutputStream stdout = new ByteArrayOutputStream();
95 int status = execCmd(sshConnection, cmd, stdout, null, true);
96 Assert.assertEquals(stdout + ". " + stdout, 0, status);
98 disconnect(sshConnection);
103 public void testExecuteInvalidCommand() {
104 String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "nosuchhost");
105 SshConnection sshConnection = connect();
106 if (sshConnection == null) return;
108 ByteArrayOutputStream stdout = new ByteArrayOutputStream();
109 ByteArrayOutputStream stderr = new ByteArrayOutputStream();
110 int status = execCmd(sshConnection, cmd, stdout, stderr, false);
111 Assert.assertNotEquals(stdout + ". " + stderr, 0, status);
113 disconnect(sshConnection);
118 public void testWrongUsername() {
119 thrown.expect(SshException.class);
120 thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
121 disconnect(invalidConnect("WrongUsername", SSH_PASSWORD));
125 public void testWrongPassword() {
126 thrown.expect(SshException.class);
127 thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
128 disconnect(invalidConnect(SSH_USERNAME, "WrongPassword"));
134 public void testInstantiateWithKeyFile() {
135 SshConnection connection = sshAdaptor.getConnection(null, 0, null);
136 assertTrue(connection instanceof SshConnection);
141 public void testConnectWithRetry() {
142 SshConnection connection = Mockito.spy(sshAdaptor.getConnection(
143 SSH_HOST, SSH_PORT, SSH_USERNAME, SSH_PASSWORD));
144 connection.setExecTimeout(1);
145 connection.connectWithRetry();
146 Mockito.verify(connection).connect();
150 public void testToString() {
151 SshConnection connection = Mockito.spy(sshAdaptor.getConnection(
152 SSH_HOST, SSH_PORT, SSH_USERNAME, SSH_PASSWORD));
153 assertEquals(SSH_USERNAME + "@" + SSH_HOST, connection.toString());
155 Whitebox.setInternalState(connection, "username", s);
156 assertEquals(SSH_HOST, connection.toString());
161 public void beforeTest() throws IOException {
168 public void afterTest() {
172 private SshConnection connect() {
173 SshConnection sshConnection = sshAdaptor.getConnection(SSH_HOST, sshPort, SshAdaptorTest.SSH_USERNAME, SshAdaptorTest.SSH_PASSWORD);
175 /* move connect to inside try block, in case ssh connection to localhost is
176 * blocked by localhost ssh policy */
177 sshConnection.connect();
178 System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
179 } catch (Exception e) {
180 sshConnection = null;
181 System.out.println("SSH client connect failed. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
183 return sshConnection;
186 private SshConnection invalidConnect(String username, String password) {
187 SshConnection sshConnection = sshAdaptor.getConnection(SSH_HOST, sshPort, username, password);
188 sshConnection.connect();
189 System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
190 return sshConnection;
193 private void disconnect(SshConnection sshConnection) {
194 if (sshConnection != null) {
195 sshConnection.disconnect();
196 System.out.println("SSH client disconnected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
200 private int execCmd(SshConnection sshConnection, String cmd, OutputStream stdout, OutputStream stderr, boolean usePty) {
201 System.out.println("=> Running command [" + cmd + "] over SSH");
204 status = sshConnection.execCommandWithPty(cmd, stdout);
206 status = sshConnection.execCommand(cmd, stdout, stderr);
208 System.out.println("=> Command [" + cmd + "] status is [" + status + "], stdout is [" + stdout + "], stderr is [" + stderr + "]");
212 private void startServer() throws IOException {
213 sshd = SshServer.setUpDefaultServer();
214 sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
215 sshd.setCommandFactory(new ScpCommandFactory());
217 sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Paths.get(System.getProperty("java.io.tmpdir") + "/key.ser")));
218 sshd.setPasswordAuthenticator((username, password, session) -> (SSH_USERNAME.equals(username) && SSH_PASSWORD.equals(password)));
219 sshd.setPublickeyAuthenticator((username, key, session) -> false);
220 // SshServer.WELCOME_BANNER no longer exists in apache sshd 2.7.0
221 // sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD\n");
225 } catch (InterruptedException e) {
230 private void startServer0() throws IOException {
231 boolean serverStarted = false;
232 IOException exception = null;
233 while (!serverStarted && (sshPort < Integer.MAX_VALUE)) {
235 System.out.println("Starting SSH server on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
236 sshd.setPort(sshPort);
238 serverStarted = true;
239 } catch (BindException e) {
240 System.err.println("Cannot start SSH server on port [" + sshPort + "]. " + e.getMessage());
241 if (exception == null) {
242 // store first thrown exception - will be thrown if cannot start the server
248 if (!serverStarted && exception != null) {
251 System.out.println("SSH server started on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
254 private void stopServer() {
258 System.out.println("SSH server stopped on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
260 } catch (IOException e) {
261 System.err.println("=> IO Error stopping SSH server.");