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