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.keyprovider.SimpleGeneratorHostKeyProvider;
37 import org.apache.sshd.server.scp.ScpCommandFactory;
38 import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
39 import org.hamcrest.CoreMatchers;
40 import org.junit.After;
41 import org.junit.Assert;
42 import org.junit.Before;
43 import org.junit.Ignore;
44 import org.junit.Rule;
45 import org.junit.Test;
46 import org.junit.rules.ExpectedException;
47 import org.onap.ccsdk.sli.adaptors.ssh.SshAdaptor;
48 import org.onap.ccsdk.sli.adaptors.ssh.SshConnection;
49 import org.onap.ccsdk.sli.adaptors.ssh.SshException;
51 import static org.junit.Assert.assertTrue;
54 public class SshAdaptorTest {
56 private static final boolean START_SERVER = true;
57 private static final String SSH_HOST = "localhost";
58 private static final int SSH_PORT = 2222;
59 private static final String SSH_USERNAME = "test";
60 private static final String SSH_PASSWORD = "test";
61 private static final String F_TEST_CMD = "ping -%c 4 %s";
63 private int sshPort = SSH_PORT;
64 private SshServer sshd;
65 private final SshAdaptor sshAdaptor = new SshAdaptorSshd();
68 public ExpectedException thrown = ExpectedException.none();
71 public void testExecute() {
72 String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
73 SshConnection sshConnection = connect();
74 if (sshConnection == null) return;
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 + ". " + stderr, 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();
90 if (sshConnection == null) return;
92 System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
93 ByteArrayOutputStream stdout = new ByteArrayOutputStream();
94 int status = execCmd(sshConnection, cmd, stdout, null, true);
95 Assert.assertEquals(stdout + ". " + stdout, 0, status);
97 disconnect(sshConnection);
102 public void testExecuteInvalidCommand() {
103 String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "nosuchhost");
104 SshConnection sshConnection = connect();
105 if (sshConnection == null) return;
107 ByteArrayOutputStream stdout = new ByteArrayOutputStream();
108 ByteArrayOutputStream stderr = new ByteArrayOutputStream();
109 int status = execCmd(sshConnection, cmd, stdout, stderr, false);
110 Assert.assertNotEquals(stdout + ". " + stderr, 0, status);
112 disconnect(sshConnection);
117 public void testWrongUsername() {
118 thrown.expect(SshException.class);
119 thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
120 disconnect(invalidConnect("WrongUsername", SSH_PASSWORD));
124 public void testWrongPassword() {
125 thrown.expect(SshException.class);
126 thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
127 disconnect(invalidConnect(SSH_USERNAME, "WrongPassword"));
133 public void testInstantiateWithKeyFile() {
134 SshConnection connection = sshAdaptor.getConnection(null, 0, null);
135 assertTrue(connection instanceof SshConnection);
140 public void testConnectWithRetry() {
141 SshConnection connection = Mockito.spy(sshAdaptor.getConnection(
142 SSH_HOST, SSH_PORT, SSH_USERNAME, SSH_PASSWORD));
143 connection.setExecTimeout(1);
144 connection.connectWithRetry();
145 Mockito.verify(connection).connect();
149 public void testToString() {
150 SshConnection connection = Mockito.spy(sshAdaptor.getConnection(
151 SSH_HOST, SSH_PORT, SSH_USERNAME, SSH_PASSWORD));
152 assertEquals(SSH_USERNAME + "@" + SSH_HOST, connection.toString());
154 Whitebox.setInternalState(connection, "username", s);
155 assertEquals(SSH_HOST, connection.toString());
160 public void beforeTest() throws IOException {
167 public void afterTest() {
171 private SshConnection connect() {
172 SshConnection sshConnection = sshAdaptor.getConnection(SSH_HOST, sshPort, SshAdaptorTest.SSH_USERNAME, SshAdaptorTest.SSH_PASSWORD);
174 /* move connect to inside try block, in case ssh connection to localhost is
175 * blocked by localhost ssh policy */
176 sshConnection.connect();
177 System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
178 } catch (Exception e) {
179 sshConnection = null;
180 System.out.println("SSH client connect failed. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
182 return sshConnection;
185 private SshConnection invalidConnect(String username, String password) {
186 SshConnection sshConnection = sshAdaptor.getConnection(SSH_HOST, sshPort, username, password);
187 sshConnection.connect();
188 System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
189 return sshConnection;
192 private void disconnect(SshConnection sshConnection) {
193 if (sshConnection != null) {
194 sshConnection.disconnect();
195 System.out.println("SSH client disconnected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
199 private int execCmd(SshConnection sshConnection, String cmd, OutputStream stdout, OutputStream stderr, boolean usePty) {
200 System.out.println("=> Running command [" + cmd + "] over SSH");
203 status = sshConnection.execCommandWithPty(cmd, stdout);
205 status = sshConnection.execCommand(cmd, stdout, stderr);
207 System.out.println("=> Command [" + cmd + "] status is [" + status + "], stdout is [" + stdout + "], stderr is [" + stderr + "]");
211 private void startServer() throws IOException {
212 sshd = SshServer.setUpDefaultServer();
213 sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
214 sshd.setCommandFactory(new ScpCommandFactory());
216 sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(Paths.get(System.getProperty("java.io.tmpdir") + "/key.ser")));
217 sshd.setPasswordAuthenticator((username, password, session) -> (SSH_USERNAME.equals(username) && SSH_PASSWORD.equals(password)));
218 sshd.setPublickeyAuthenticator((username, key, session) -> false);
219 sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD\n");
223 } catch (InterruptedException e) {
228 private void startServer0() throws IOException {
229 boolean serverStarted = false;
230 IOException exception = null;
231 while (!serverStarted && (sshPort < Integer.MAX_VALUE)) {
233 System.out.println("Starting SSH server on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
234 sshd.setPort(sshPort);
236 serverStarted = true;
237 } catch (BindException e) {
238 System.err.println("Cannot start SSH server on port [" + sshPort + "]. " + e.getMessage());
239 if (exception == null) {
240 // store first thrown exception - will be thrown if cannot start the server
246 if (!serverStarted && exception != null) {
249 System.out.println("SSH server started on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
252 private void stopServer() {
256 System.out.println("SSH server stopped on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
258 } catch (IOException e) {
259 System.err.println("=> IO Error stopping SSH server.");