Changed to unmaintained
[appc.git] / appc-adapters / appc-ssh-adapter / appc-ssh-adapter-sshd / src / test / java / org / onap / appc / adapter / ssh / sshd / SshAdapterTest.java
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.appc.adapter.ssh.sshd;
27
28 import org.apache.sshd.server.SshServer;
29 import org.apache.sshd.common.NamedFactory;
30 import org.apache.sshd.common.util.OsUtils;
31 import org.apache.sshd.server.command.Command;
32 import org.apache.sshd.server.auth.password.PasswordAuthenticator;
33 import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
34 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
35 import org.apache.sshd.server.scp.ScpCommandFactory;
36 import org.apache.sshd.server.session.ServerSession;
37 import org.apache.sshd.server.shell.ProcessShellFactory;
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.Rule;
44 import org.junit.Test;
45 import org.junit.rules.ExpectedException;
46 import org.mockito.Mockito;
47 import org.onap.appc.adapter.ssh.SshAdapter;
48 import org.onap.appc.adapter.ssh.SshConnection;
49 import org.onap.appc.adapter.ssh.SshException;
50 import org.powermock.reflect.Whitebox;
51 import static org.junit.Assert.assertEquals;
52 import static org.junit.Assert.assertTrue;
53 import java.io.ByteArrayOutputStream;
54 import java.io.File;
55 import java.io.IOException;
56 import java.io.OutputStream;
57 import java.net.BindException;
58 import java.security.PublicKey;
59 import java.util.Collections;
60
61 //@Ignore
62 public class SshAdapterTest {
63
64     private static final boolean START_SERVER = true;
65     private static final String SSH_HOST = "localhost";
66     private static final int SSH_PORT = 2222;
67     private static final String SSH_USERNAME = "test";
68     private static final String SSH_PASSWORD = "test";
69     private static final String F_TEST_CMD = "ping -%c 4 %s";
70
71     private int sshPort = SSH_PORT;
72     private SshServer sshd;
73     private SshAdapter sshAdapter = new SshAdapterSshd();
74
75     @Rule
76     public ExpectedException thrown = ExpectedException.none();
77
78     @Test
79     public void testExecute() {
80         String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
81         SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
82         try {
83             System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
84             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
85             ByteArrayOutputStream stderr = new ByteArrayOutputStream();
86             int status = execCmd(sshConnection, cmd, stdout, stderr, false);
87             Assert.assertEquals(stdout.toString() + ". " + stderr.toString(), 0, status);
88         } finally {
89             disconnect(sshConnection);
90         }
91     }
92
93     @Test
94     public void testExecuteWithPty() {
95         String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
96         SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
97         try {
98             System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
99             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
100             int status = execCmd(sshConnection, cmd, stdout, null, true);
101             Assert.assertEquals(stdout.toString() + ". " + stdout.toString(), 0, status);
102         } finally {
103             disconnect(sshConnection);
104         }
105     }
106
107     @Test
108     public void testExecuteInvalidCommand() {
109         String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "nosuchhost");
110         SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
111         try {
112             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
113             ByteArrayOutputStream stderr = new ByteArrayOutputStream();
114             int status = execCmd(sshConnection, cmd, stdout, stderr, false);
115             Assert.assertNotEquals(stdout.toString() + ". " + stderr.toString(), 0, status);
116         } finally {
117             disconnect(sshConnection);
118         }
119     }
120
121     @Test
122     public void testWrongUsername() {
123         thrown.expect(SshException.class);
124         thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
125         disconnect(connect("WrongUsername", SSH_PASSWORD));
126     }
127
128     @Test
129     public void testWrongPassword() {
130         thrown.expect(SshException.class);
131         thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
132         disconnect(connect(SSH_USERNAME, "WrongPassword"));
133     }
134
135     @Test
136     public void testInstantiateWithKeyFile() {
137         SshConnection connection = sshAdapter.getConnection(null, 0, null);
138         assertTrue(connection instanceof SshConnection);
139     }
140
141     @Test
142     public void testConnectWithRetry() {
143         SshConnection connection = Mockito.spy(sshAdapter.getConnection(
144                 SSH_HOST, SSH_PORT, SSH_USERNAME, SSH_PASSWORD));
145         connection.setExecTimeout(1);
146         connection.connectWithRetry();
147         Mockito.verify(connection).connect();
148     }
149
150     @Test
151     public void testToString() {
152         SshConnection connection = Mockito.spy(sshAdapter.getConnection(
153                 SSH_HOST, SSH_PORT, SSH_USERNAME, SSH_PASSWORD));
154         assertEquals(SSH_USERNAME + "@" + SSH_HOST, connection.toString());
155         String s = null;
156         Whitebox.setInternalState(connection, "username", s);
157         assertEquals(SSH_HOST, connection.toString());
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() throws InterruptedException {
169         stopServer();
170     }
171
172     private SshConnection connect(String username, String password) {
173         SshConnection sshConnection = sshAdapter.getConnection(SSH_HOST, sshPort, username, password);
174         sshConnection.connect();
175         System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
176         return sshConnection;
177     }
178
179     private void disconnect(SshConnection sshConnection) {
180         sshConnection.disconnect();
181         System.out.println("SSH client disconnected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
182     }
183
184     private int execCmd(SshConnection sshConnection, String cmd, OutputStream stdout, OutputStream stderr, boolean usePty) {
185         System.out.println("=> Running command [" + cmd + "] over SSH");
186         int status;
187         if (usePty) {
188             status = sshConnection.execCommandWithPty(cmd, stdout);
189         } else {
190             status = sshConnection.execCommand(cmd, stdout, stderr);
191         }
192         System.out.println("=> Command [" + cmd + "] status is [" + status + "], stdout is [" + String.valueOf(stdout) + "], stderr is [" + String.valueOf(stderr) + "]");
193         return status;
194     }
195
196     private void startServer() throws IOException {
197         sshd = SshServer.setUpDefaultServer();
198         sshd.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(new SftpSubsystemFactory()));
199         sshd.setCommandFactory(new ScpCommandFactory() {
200
201             public Command createCommand(String command) {
202                 //EnumSet<ProcessShellFactory.TtyOptions> ttyOptions;
203                 //if (OsUtils.isUNIX()) {
204                 //    ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr);
205                 //} else {
206                 //    ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr);
207                 //}
208                 //return new ProcessShellFactory(command.split(" "), ttyOptions).create();
209                 
210                 return new ProcessShellFactory(command.split(" ")).create();
211             }
212         });
213         if (OsUtils.isUNIX()) {
214             sshd.setShellFactory(new ProcessShellFactory(new String[]{"/bin/sh", "-i", "-l"}/*,
215                     EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr)*/));
216         } else {
217             sshd.setShellFactory(new ProcessShellFactory(new String[]{"cmd.exe "}/*,
218                     EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr)*/));
219         }
220 //              if(SecurityUtils.isBouncyCastleRegistered()) {
221 //                      sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider(System.getProperty("java.io.tmpdir") + "/key.pem"));
222 //              } else {
223         sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(new File(System.getProperty("java.io.tmpdir") + "/key.ser")));
224 //              }
225         sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
226             @Override
227             public boolean authenticate(String username, String password, ServerSession session) {
228                 return (SSH_USERNAME.equals(username) && SSH_PASSWORD.equals(password));
229             }
230         });
231         sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {
232             // We're testing access using passwords, so do not authorize authentitication using public keys
233             public boolean authenticate(String username, PublicKey key, ServerSession session) {
234                 return false;
235             }
236         });
237         sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD\n");
238         startServer0();
239         try {
240             Thread.sleep(1000);
241         } catch (InterruptedException e) {
242             // ignore
243         }
244     }
245
246     private void startServer0() throws IOException {
247         boolean serverStarted = false;
248         IOException exception = null;
249         while (!serverStarted && (sshPort < Integer.MAX_VALUE)) {
250             try {
251                 System.out.println("Starting SSH server on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
252                 sshd.setPort(sshPort);
253                 sshd.start();
254                 serverStarted = true;
255             } catch (BindException e) {
256                 System.err.println("Cannot start SSH server on port [" + sshPort + "]. " + e.getMessage());
257                 if (exception == null) {
258                     // store first thrown exception - will be thrown if cannot start the server
259                     exception = e;
260                 }
261                 sshPort++;
262             }
263         }
264         if (!serverStarted) {
265             throw exception;
266         }
267         System.out.println("SSH server started on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
268     }
269
270     private void stopServer() {
271         try {
272             if (sshd != null) {
273                 sshd.stop();
274                 System.out.println("SSH server stopped on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
275             }
276         } catch (IOException e) {
277             System.err.println("=> IO Error stopping SSH server.");
278             e.printStackTrace();
279         } finally {
280             sshd = null;
281         }
282     }
283 }