fecb42fc2c7311f4a5772fccf6dd75fc6affddb4
[ccsdk/sli.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
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
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
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.
22  *
23  * ============LICENSE_END=========================================================
24  */
25
26 package org.onap.ccsdk.sli.adaptors.ssh.sshd;
27
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;
51
52 import static org.junit.Assert.assertTrue;
53
54 @Ignore
55 public class SshAdaptorTest {
56
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";
63
64     private int sshPort = SSH_PORT;
65     private SshServer sshd;
66     private final SshAdaptor sshAdaptor = new SshAdaptorSshd();
67
68     @Rule
69     public ExpectedException thrown = ExpectedException.none();
70
71     @Test
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;
76         try {
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);
82         } finally {
83             disconnect(sshConnection);
84         }
85     }
86
87     @Test
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;
92         try {
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);
97         } finally {
98             disconnect(sshConnection);
99         }
100     }
101
102     @Test
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;
107         try {
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);
112         } finally {
113             disconnect(sshConnection);
114         }
115     }
116
117     @Test
118     public void testWrongUsername() {
119         thrown.expect(SshException.class);
120         thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
121         disconnect(invalidConnect("WrongUsername", SSH_PASSWORD));
122     }
123
124     @Test
125     public void testWrongPassword() {
126         thrown.expect(SshException.class);
127         thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
128         disconnect(invalidConnect(SSH_USERNAME, "WrongPassword"));
129     }
130
131
132
133     @Test
134     public void testInstantiateWithKeyFile() {
135         SshConnection connection = sshAdaptor.getConnection(null, 0, null);
136         assertTrue(connection instanceof SshConnection);
137     }
138
139     /*
140     @Test
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();
147     }
148
149     @Test
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());
154         String s = null;
155         Whitebox.setInternalState(connection, "username", s);
156         assertEquals(SSH_HOST, connection.toString());
157     }
158     */
159
160     @Before
161     public void beforeTest() throws IOException {
162         if (START_SERVER) {
163             startServer();
164         }
165     }
166
167     @After
168     public void afterTest() {
169         stopServer();
170     }
171
172     private SshConnection connect() {
173         SshConnection sshConnection = sshAdaptor.getConnection(SSH_HOST, sshPort, SshAdaptorTest.SSH_USERNAME, SshAdaptorTest.SSH_PASSWORD);
174         try {
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) + "]");
182         }
183         return sshConnection;
184     }
185
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;
191     }
192
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) + "]");
197         }
198 }
199
200     private int execCmd(SshConnection sshConnection, String cmd, OutputStream stdout, OutputStream stderr, boolean usePty) {
201         System.out.println("=> Running command [" + cmd + "] over SSH");
202         int status;
203         if (usePty) {
204             status = sshConnection.execCommandWithPty(cmd, stdout);
205         } else {
206             status = sshConnection.execCommand(cmd, stdout, stderr);
207         }
208         System.out.println("=> Command [" + cmd + "] status is [" + status + "], stdout is [" + stdout + "], stderr is [" + stderr + "]");
209         return status;
210     }
211
212    private void startServer() throws IOException {
213         sshd = SshServer.setUpDefaultServer();
214         sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
215         sshd.setCommandFactory(new ScpCommandFactory());
216
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");
222         startServer0();
223         try {
224             Thread.sleep(1000);
225         } catch (InterruptedException e) {
226             // ignore
227         }
228     }
229
230     private void startServer0() throws IOException {
231         boolean serverStarted = false;
232         IOException exception = null;
233         while (!serverStarted && (sshPort < Integer.MAX_VALUE)) {
234             try {
235                 System.out.println("Starting SSH server on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
236                 sshd.setPort(sshPort);
237                 sshd.start();
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
243                     exception = e;
244                 }
245                 sshPort++;
246             }
247         }
248         if (!serverStarted && exception != null) {
249             throw exception;
250         }
251         System.out.println("SSH server started on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
252     }
253
254     private void stopServer() {
255         try {
256             if (sshd != null) {
257                 sshd.stop();
258                 System.out.println("SSH server stopped on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
259             }
260         } catch (IOException e) {
261             System.err.println("=> IO Error stopping SSH server.");
262             e.printStackTrace();
263         } finally {
264             sshd = null;
265         }
266     }
267 }