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