Update license header in REST and SSH adapter file
[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  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * 
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.appc.adapter.ssh.sshd;
25
26 import org.apache.sshd.SshServer;
27 import org.apache.sshd.common.NamedFactory;
28 import org.apache.sshd.common.util.OsUtils;
29 import org.apache.sshd.server.Command;
30 import org.apache.sshd.server.CommandFactory;
31 import org.apache.sshd.server.PasswordAuthenticator;
32 import org.apache.sshd.server.PublickeyAuthenticator;
33 import org.apache.sshd.server.command.ScpCommandFactory;
34 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
35 import org.apache.sshd.server.session.ServerSession;
36 import org.apache.sshd.server.sftp.SftpSubsystem;
37 import org.apache.sshd.server.shell.ProcessShellFactory;
38 import org.hamcrest.CoreMatchers;
39 import org.junit.*;
40 import org.junit.rules.ExpectedException;
41 import org.onap.appc.adapter.ssh.SshAdapter;
42 import org.onap.appc.adapter.ssh.SshConnection;
43 import org.onap.appc.adapter.ssh.SshException;
44 import org.onap.appc.adapter.ssh.sshd.SshAdapterSshd;
45
46 import java.io.ByteArrayOutputStream;
47 import java.io.IOException;
48 import java.io.OutputStream;
49 import java.net.BindException;
50 import java.security.PublicKey;
51 import java.util.Collections;
52 import java.util.EnumSet;
53
54 public class SshAdapterTest {
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 SshAdapter sshAdapter = new SshAdapterSshd();
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(SSH_USERNAME, SSH_PASSWORD);
74         try {
75             System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
76             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
77             ByteArrayOutputStream stderr = new ByteArrayOutputStream();
78             int status = execCmd(sshConnection, cmd, stdout, stderr, false);
79             Assert.assertEquals(stdout.toString() + ". " + stderr.toString(), 0, status);
80         } finally {
81             disconnect(sshConnection);
82         }
83     }
84
85     @Test
86     public void testExecuteWithPty() {
87         String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
88         SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
89         try {
90             System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
91             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
92             int status = execCmd(sshConnection, cmd, stdout, null, true);
93             Assert.assertEquals(stdout.toString() + ". " + stdout.toString(), 0, status);
94         } finally {
95             disconnect(sshConnection);
96         }
97     }
98
99     @Test
100     public void testExecuteInvalidCommand() {
101         String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "nosuchhost");
102         SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
103         try {
104             ByteArrayOutputStream stdout = new ByteArrayOutputStream();
105             ByteArrayOutputStream stderr = new ByteArrayOutputStream();
106             int status = execCmd(sshConnection, cmd, stdout, stderr, false);
107             Assert.assertNotEquals(stdout.toString() + ". " + stderr.toString(), 0, status);
108         } finally {
109             disconnect(sshConnection);
110         }
111     }
112
113     @Test
114     public void testWrongUsername() {
115         thrown.expect(SshException.class);
116         thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
117         disconnect(connect("WrongUsername", SSH_PASSWORD));
118     }
119
120     @Test
121     public void testWrongPassword() {
122         thrown.expect(SshException.class);
123         thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
124         disconnect(connect(SSH_USERNAME, "WrongPassword"));
125     }
126
127     @Before
128     public void beforeTest() throws IOException {
129         if (START_SERVER) {
130             startServer();
131         }
132     }
133
134     @After
135     public void afterTest() throws InterruptedException {
136         stopServer();
137     }
138
139     private SshConnection connect(String username, String password) {
140         SshConnection sshConnection = sshAdapter.getConnection(SSH_HOST, sshPort, username, password);
141         sshConnection.connect();
142         System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
143         return sshConnection;
144     }
145
146     private void disconnect(SshConnection sshConnection) {
147         sshConnection.disconnect();
148         System.out.println("SSH client disconnected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
149     }
150
151     private int execCmd(SshConnection sshConnection, String cmd, OutputStream stdout, OutputStream stderr, boolean usePty) {
152         System.out.println("=> Running command [" + cmd + "] over SSH");
153         int status;
154         if (usePty) {
155             status = sshConnection.execCommandWithPty(cmd, stdout);
156         } else {
157             status = sshConnection.execCommand(cmd, stdout, stderr);
158         }
159         System.out.println("=> Command [" + cmd + "] status is [" + status + "], stdout is [" + String.valueOf(stdout) + "], stderr is [" + String.valueOf(stderr) + "]");
160         return status;
161     }
162
163     private void startServer() throws IOException {
164         sshd = SshServer.setUpDefaultServer();
165         sshd.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(new SftpSubsystem.Factory()));
166         sshd.setCommandFactory(new ScpCommandFactory(new CommandFactory() {
167
168             public Command createCommand(String command) {
169                 EnumSet<ProcessShellFactory.TtyOptions> ttyOptions;
170                 if (OsUtils.isUNIX()) {
171                     ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr);
172                 } else {
173                     ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr);
174                 }
175                 return new ProcessShellFactory(command.split(" "), ttyOptions).create();
176             }
177         }));
178         if (OsUtils.isUNIX()) {
179             sshd.setShellFactory(new ProcessShellFactory(new String[]{"/bin/sh", "-i", "-l"},
180                     EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr)));
181         } else {
182             sshd.setShellFactory(new ProcessShellFactory(new String[]{"cmd.exe "},
183                     EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr)));
184         }
185 //              if(SecurityUtils.isBouncyCastleRegistered()) {
186 //                      sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider(System.getProperty("java.io.tmpdir") + "/key.pem"));
187 //              } else {
188         sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(System.getProperty("java.io.tmpdir") + "/key.ser"));
189 //              }
190         sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
191
192             @Override
193             public boolean authenticate(String username, String password, ServerSession session) {
194                 return (SSH_USERNAME.equals(username) && SSH_PASSWORD.equals(password));
195             }
196         });
197         sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {
198
199             public boolean authenticate(String username, PublicKey key, ServerSession session) {
200                 return true;
201             }
202         });
203         sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD\n");
204         startServer0();
205         try {
206             Thread.sleep(1000);
207         } catch (InterruptedException e) {
208             // ignore
209         }
210     }
211
212     private void startServer0() throws IOException {
213         boolean serverStarted = false;
214         IOException exception = null;
215         while (!serverStarted && (sshPort < Integer.MAX_VALUE)) {
216             try {
217                 System.out.println("Starting SSH server on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
218                 sshd.setPort(sshPort);
219                 sshd.start();
220                 serverStarted = true;
221             } catch (BindException e) {
222                 System.err.println("Cannot start SSH server on port [" + sshPort + "]. " + e.getMessage());
223                 if (exception == null) {
224                     // store first thrown exception - will be thrown if cannot start the server
225                     exception = e;
226                 }
227                 sshPort++;
228             }
229         }
230         if (!serverStarted) {
231             throw exception;
232         }
233         System.out.println("SSH server started on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
234     }
235
236     private void stopServer() {
237         try {
238             if (sshd != null) {
239                 sshd.stop(true);
240                 System.out.println("SSH server stopped on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
241             }
242         } catch (InterruptedException e) {
243             System.err.println("=> Error stopping SSH server.");
244             e.printStackTrace();
245         } finally {
246             sshd = null;
247         }
248     }
249 }