summaryrefslogtreecommitdiffstats
path: root/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd
diff options
context:
space:
mode:
Diffstat (limited to 'appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd')
-rw-r--r--appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/.settings/org.eclipse.wst.common.project.facet.core.xml4
-rw-r--r--appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/pom.xml62
-rw-r--r--appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterSshd.java33
-rw-r--r--appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshConnectionSshd.java172
-rw-r--r--appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshdDataAccessService.java106
-rw-r--r--appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/resources/OSGI-INF/blueprint/blueprint.xml38
-rw-r--r--appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/test/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterSample.java56
-rw-r--r--appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/test/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterTest.java247
8 files changed, 718 insertions, 0 deletions
diff --git a/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/.settings/org.eclipse.wst.common.project.facet.core.xml b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 000000000..f4ef8aa0a
--- /dev/null
+++ b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <installed facet="java" version="1.8"/>
+</faceted-project>
diff --git a/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/pom.xml b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/pom.xml
new file mode 100644
index 000000000..54b7ea428
--- /dev/null
+++ b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.openecomp.appc</groupId>
+ <artifactId>appc-ssh-adapter</artifactId>
+ <version>1.0.0</version>
+ </parent>
+
+ <artifactId>appc-ssh-adapter-sshd</artifactId>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.openecomp.appc</groupId>
+ <artifactId>appc-ssh-adapter-api</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sshd</groupId>
+ <artifactId>sshd-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.att.eelf</groupId>
+ <artifactId>eelf-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.openecomp.appc</groupId>
+ <artifactId>appc-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.openecomp.sdnc.core</groupId>
+ <artifactId>dblib-provider</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Service>org.openecomp.appc.adapter.ssh.SshAdapter</Export-Service>
+ <Private-Package>org.openecomp.appc.adapter.ssh.impl.*</Private-Package>
+ <Import-Package>!org.apache.log,!org.apache.commons.logging,!groovy.lang,!javax.jms,!org.codehaus.commons.compiler,!org.codehaus.groovy.*,!org.codehaus.janino,!com.ibm.icu.*,!com.sun.faces.*,!org.jasypt.*,*</Import-Package>
+ <Embed-Dependency>!dblib-provider,appc-common,jasypt,eelf-core,logback-core,logback-classic;scope=compile|runtime;inline=false</Embed-Dependency>
+ <Embed-Transitive>true</Embed-Transitive>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterSshd.java b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterSshd.java
new file mode 100644
index 000000000..44a6fb4ce
--- /dev/null
+++ b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterSshd.java
@@ -0,0 +1,33 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.adapter.ssh.sshd;
+
+import org.openecomp.appc.adapter.ssh.SshAdapter;
+import org.openecomp.appc.adapter.ssh.SshConnection;
+
+public class SshAdapterSshd implements SshAdapter {
+
+ @Override
+ public SshConnection getConnection(String host, int port, String username, String password) {
+ return new SshConnectionSshd(host, port, username, password);
+ }
+}
diff --git a/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshConnectionSshd.java b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshConnectionSshd.java
new file mode 100644
index 000000000..4d8b83b6f
--- /dev/null
+++ b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshConnectionSshd.java
@@ -0,0 +1,172 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.adapter.ssh.sshd;
+
+import org.apache.sshd.ClientChannel;
+import org.apache.sshd.ClientSession;
+import org.apache.sshd.SshClient;
+import org.apache.sshd.client.channel.ChannelExec;
+import org.apache.sshd.client.future.AuthFuture;
+import org.apache.sshd.client.future.OpenFuture;
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
+import org.openecomp.appc.adapter.ssh.SshConnection;
+import org.openecomp.appc.adapter.ssh.SshException;
+import org.openecomp.appc.encryption.EncryptionTool;
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+
+import java.io.OutputStream;
+import java.security.KeyPair;
+
+/**
+ * Implementation of SshConnection interface based on Apache MINA SSHD library.
+ */
+class SshConnectionSshd implements SshConnection {
+
+ private static final EELFLogger logger = EELFManager.getInstance().getApplicationLogger();
+
+ private static final long AUTH_TIMEOUT = 60000;
+ private static final long EXEC_TIMEOUT = 120000;
+
+ private String host;
+ private int port;
+ private String username;
+ private String password;
+ private long timeout = EXEC_TIMEOUT;
+ private String keyFile;
+ private SshClient sshClient;
+ private ClientSession clientSession;
+
+ public SshConnectionSshd(String host, int port, String username, String password, String keyFile) {
+ this.host = host;
+ this.port = port;
+ this.username = username;
+ this.password = password;
+ this.keyFile = keyFile;
+ }
+
+ public SshConnectionSshd(String host, int port, String username, String password) {
+ this(host, port, username, password, null);
+ }
+
+ public SshConnectionSshd(String host, int port, String keyFile) {
+ this(host, port, null, null, keyFile);
+ }
+
+ @Override
+ public void connect() {
+ sshClient = SshClient.setUpDefaultClient();
+ sshClient.start();
+ try {
+ clientSession = sshClient.connect(EncryptionTool.getInstance().decrypt(username), host, port).await().getSession();
+ if(password != null) {
+ clientSession.addPasswordIdentity(EncryptionTool.getInstance().decrypt(password));
+ }
+ if(keyFile != null) {
+ KeyPairProvider keyPairProvider = new FileKeyPairProvider(new String[]{keyFile});
+ KeyPair keyPair = keyPairProvider.loadKeys().iterator().next();
+ clientSession.addPublicKeyIdentity(keyPair);
+ }
+ AuthFuture authFuture = clientSession.auth();
+ authFuture.await(AUTH_TIMEOUT);
+ if(!authFuture.isSuccess()) {
+ throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + "]. Authentication failed.");
+ }
+ } catch(RuntimeException e) {
+ throw e;
+ } catch(Exception e) {
+ throw new SshException("Error establishing ssh connection to [" + username + "@" + host + ":" + port + "].", e);
+ }
+ if(logger.isDebugEnabled()) {
+ logger.debug("SSH: connected to [" + toString() + "]");
+ }
+ }
+
+ @Override
+ public void disconnect() {
+ try {
+ if(logger.isDebugEnabled()) {
+ logger.debug("SSH: disconnecting from [" + toString() + "]");
+ }
+ clientSession.close(false);
+ } finally {
+ if(sshClient != null) {
+ sshClient.stop();
+ }
+ }
+ }
+
+ @Override
+ public void setExecTimeout(long timeout) {
+ this.timeout = timeout;
+ }
+
+ @Override
+ public int execCommand(String cmd, OutputStream out, OutputStream err) {
+ return execCommand(cmd, out, err, false);
+ }
+
+ @Override
+ public int execCommandWithPty(String cmd, OutputStream out) {
+ return execCommand(cmd, out, out, true);
+ }
+
+ private int execCommand(String cmd, OutputStream out, OutputStream err, boolean usePty) {
+ try {
+ if(logger.isDebugEnabled()) {
+ logger.debug("SSH: executing command");
+ }
+ ChannelExec client = clientSession.createExecChannel(cmd);
+ client.setUsePty(usePty); // use pseudo-tty?
+ client.setOut(out);
+ client.setErr(err);
+ OpenFuture openFuture = client.open();
+ int exitStatus = 0;
+ try {
+ client.waitFor(ClientChannel.CLOSED, timeout);
+ openFuture.verify();
+ Integer exitStatusI = client.getExitStatus();
+ if(exitStatusI == null) {
+ throw new SshException("Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + port + "]. Operation timed out.");
+ }
+ exitStatus = exitStatusI;
+ } finally {
+ client.close(false);
+ }
+ return exitStatus;
+ } catch(RuntimeException e) {
+ throw e;
+ } catch(Exception t) {
+ throw new SshException("Error executing command [" + cmd + "] over SSH [" + username + "@" + host + ":" + port + "]", t);
+ }
+ }
+
+ @Override
+ public String toString() {
+ String address = host;
+ if(username != null) {
+ address = username + '@' +address;
+ }
+ return address;
+ }
+}
diff --git a/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshdDataAccessService.java b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshdDataAccessService.java
new file mode 100644
index 000000000..a12e2be93
--- /dev/null
+++ b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/java/org/openecomp/appc/adapter/ssh/sshd/SshdDataAccessService.java
@@ -0,0 +1,106 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.adapter.ssh.sshd;
+
+import javax.sql.rowset.CachedRowSet;
+
+import org.openecomp.appc.adapter.ssh.Constants;
+import org.openecomp.appc.adapter.ssh.SshConnectionDetails;
+import org.openecomp.appc.adapter.ssh.SshDataAccessException;
+import org.openecomp.appc.adapter.ssh.SshDataAccessService;
+import org.openecomp.appc.exceptions.APPCException;
+import org.openecomp.sdnc.sli.resource.dblib.DbLibService;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+
+
+
+public class SshdDataAccessService implements SshDataAccessService {
+
+ private String schema = Constants.NETCONF_SCHEMA;
+ private DbLibService dbLibService;
+
+ @Override
+ public void setSchema(String schema) {
+ this.schema = schema;
+ }
+
+ @Override
+ public void setDbLibService(DbLibService dbLibService) {
+ this.dbLibService = dbLibService;
+ }
+
+ @Override
+ public boolean retrieveConnectionDetails(String vnfType, SshConnectionDetails connectionDetails) throws SshDataAccessException {
+
+ boolean recordFound = false;
+
+ String queryString = "select " + Constants.USER_NAME_TABLE_FIELD_NAME + "," + Constants.PASSWORD_TABLE_FIELD_NAME + "," + Constants.PORT_NUMBER_TABLE_FIELD_NAME + " " +
+ "from " + Constants.DEVICE_AUTHENTICATION_TABLE_NAME + " " +
+ "where " + Constants.VNF_TYPE_TABLE_FIELD_NAME + " = ?";
+
+ ArrayList<String> argList = new ArrayList<>();
+ argList.add(vnfType);
+
+ try {
+
+ final CachedRowSet data = dbLibService.getData(queryString, argList, schema);
+ if (data.first()) {
+ recordFound = true;
+ connectionDetails.setUsername(data.getString(Constants.USER_NAME_TABLE_FIELD_NAME));
+ connectionDetails.setPassword(data.getString(Constants.PASSWORD_TABLE_FIELD_NAME));
+ connectionDetails.setPort(data.getInt(Constants.PORT_NUMBER_TABLE_FIELD_NAME));
+ }
+
+ } catch (SQLException e) {
+ throw new SshDataAccessException(e);
+ }
+
+ return recordFound;
+ }
+
+ @Override
+ public String retrieveConfigFileName(String xmlID) throws SshDataAccessException {
+ String fileContent;
+
+ String queryString = "select " + Constants.FILE_CONTENT_TABLE_FIELD_NAME + " " +
+ "from " + Constants.CONFIGFILES_TABLE_NAME + " " +
+ "where " + Constants.FILE_NAME_TABLE_FIELD_NAME + " = ?";
+
+ ArrayList<String> argList = new ArrayList<>();
+ argList.add(xmlID);
+
+ try {
+
+ final CachedRowSet data = dbLibService.getData(queryString, argList, schema);
+ fileContent = data.getString(Constants.FILE_CONTENT_TABLE_FIELD_NAME);
+
+ } catch (SQLException e) {
+ throw new SshDataAccessException(e);
+ }
+
+ return fileContent;
+ }
+
+
+}
diff --git a/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/resources/OSGI-INF/blueprint/blueprint.xml
new file mode 100644
index 000000000..f9d10868a
--- /dev/null
+++ b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ============LICENSE_START=======================================================
+ openECOMP : APP-C
+ ================================================================================
+ Copyright (C) 2017 AT&T Intellectual Property. All rights
+ reserved.
+ ================================================================================
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ============LICENSE_END=========================================================
+ -->
+
+
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd">
+
+ <bean id="sshdBean" class="org.openecomp.appc.adapter.ssh.sshd.SshAdapterSshd" scope="singleton"/>
+ <service id="sshAdapter" interface="org.openecomp.appc.adapter.ssh.SshAdapter" ref="sshdBean"/>
+
+ <reference id="dbLibServiceRef" availability="mandatory" activation="eager" interface="org.openecomp.sdnc.sli.resource.dblib.DbLibService" />
+ <bean id="sshdDAServiceBean" class="org.openecomp.appc.adapter.ssh.sshd.SshdDataAccessService" scope="singleton">
+ <property name="dbLibService" ref="dbLibServiceRef" />
+ </bean>
+
+ <service id="sshDAService" interface="org.openecomp.appc.adapter.ssh.SshDataAccessService" ref="sshdDAServiceBean"/>
+
+</blueprint>
diff --git a/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/test/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterSample.java b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/test/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterSample.java
new file mode 100644
index 000000000..197915de8
--- /dev/null
+++ b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/test/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterSample.java
@@ -0,0 +1,56 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.adapter.ssh.sshd;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+import org.openecomp.appc.adapter.ssh.SshAdapter;
+import org.openecomp.appc.adapter.ssh.SshConnection;
+import org.openecomp.appc.adapter.ssh.sshd.SshAdapterSshd;
+
+public class SshAdapterSample {
+
+ public static void main(String[] args) {
+ String host = "hostname";
+ int port = 22;
+ String username = "user";
+ String password = "secret";
+ String command = "ls";
+
+ SshAdapter sshAdapter = new SshAdapterSshd();
+ SshConnection sshConnection = sshAdapter.getConnection(host, port, username, password);
+ sshConnection.connect();
+ try {
+ OutputStream stdout = new ByteArrayOutputStream();
+ OutputStream stderr = new ByteArrayOutputStream();
+ int status = sshConnection.execCommand(command, stdout, stderr);
+ if(status == 0) {
+ System.out.println("Command executed successfully. Output:\n" + stdout.toString());
+ } else {
+ System.err.println("Command returned status " + status + ". Error:\n" + stderr.toString());
+ }
+ } finally {
+ sshConnection.disconnect();
+ }
+ }
+}
diff --git a/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/test/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterTest.java b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/test/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterTest.java
new file mode 100644
index 000000000..1d7d06df2
--- /dev/null
+++ b/appc-adapters/appc-ssh-adapter/appc-ssh-adapter-sshd/src/test/java/org/openecomp/appc/adapter/ssh/sshd/SshAdapterTest.java
@@ -0,0 +1,247 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * openECOMP : APP-C
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.appc.adapter.ssh.sshd;
+
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.CommandFactory;
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.PublickeyAuthenticator;
+import org.apache.sshd.server.command.ScpCommandFactory;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.server.sftp.SftpSubsystem;
+import org.apache.sshd.server.shell.ProcessShellFactory;
+import org.hamcrest.CoreMatchers;
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+import org.openecomp.appc.adapter.ssh.SshAdapter;
+import org.openecomp.appc.adapter.ssh.SshConnection;
+import org.openecomp.appc.adapter.ssh.SshException;
+import org.openecomp.appc.adapter.ssh.sshd.SshAdapterSshd;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.BindException;
+import java.security.PublicKey;
+import java.util.Collections;
+import java.util.EnumSet;
+
+public class SshAdapterTest {
+
+ private static final boolean START_SERVER = true;
+ private static final String SSH_HOST = "localhost";
+ private static final int SSH_PORT = 2222;
+ private static final String SSH_USERNAME = "test";
+ private static final String SSH_PASSWORD = "test";
+ private static final String F_TEST_CMD = "ping -%c 4 %s";
+
+ private int sshPort = SSH_PORT;
+ private SshServer sshd;
+ private SshAdapter sshAdapter = new SshAdapterSshd();
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testExecute() {
+ String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
+ SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
+ try {
+ System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+ int status = execCmd(sshConnection, cmd, stdout, stderr, false);
+ Assert.assertEquals(stdout.toString() + ". " + stderr.toString(), 0, status);
+ } finally {
+ disconnect(sshConnection);
+ }
+ }
+
+ @Test
+ public void testExecuteWithPty() {
+ String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "localhost");
+ SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
+ try {
+ System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ int status = execCmd(sshConnection, cmd, stdout, null, true);
+ Assert.assertEquals(stdout.toString() + ". " + stdout.toString(), 0, status);
+ } finally {
+ disconnect(sshConnection);
+ }
+ }
+
+ @Test
+ public void testExecuteInvalidCommand() {
+ String cmd = String.format(F_TEST_CMD, OsUtils.isUNIX() ? 'c' : 'n', "nosuchhost");
+ SshConnection sshConnection = connect(SSH_USERNAME, SSH_PASSWORD);
+ try {
+ ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+ ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+ int status = execCmd(sshConnection, cmd, stdout, stderr, false);
+ Assert.assertNotEquals(stdout.toString() + ". " + stderr.toString(), 0, status);
+ } finally {
+ disconnect(sshConnection);
+ }
+ }
+
+ @Test
+ public void testWrongUsername() {
+ thrown.expect(SshException.class);
+ thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
+ disconnect(connect("WrongUsername", SSH_PASSWORD));
+ }
+
+ @Test
+ public void testWrongPassword() {
+ thrown.expect(SshException.class);
+ thrown.expectMessage(CoreMatchers.containsString("Authentication failed"));
+ disconnect(connect(SSH_USERNAME, "WrongPassword"));
+ }
+
+ @Before
+ public void beforeTest() throws IOException {
+ if (START_SERVER) {
+ startServer();
+ }
+ }
+
+ @After
+ public void afterTest() throws InterruptedException {
+ stopServer();
+ }
+
+ private SshConnection connect(String username, String password) {
+ SshConnection sshConnection = sshAdapter.getConnection(SSH_HOST, sshPort, username, password);
+ sshConnection.connect();
+ System.out.println("SSH client connected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
+ return sshConnection;
+ }
+
+ private void disconnect(SshConnection sshConnection) {
+ sshConnection.disconnect();
+ System.out.println("SSH client disconnected. Server port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
+ }
+
+ private int execCmd(SshConnection sshConnection, String cmd, OutputStream stdout, OutputStream stderr, boolean usePty) {
+ System.out.println("=> Running command [" + cmd + "] over SSH");
+ int status;
+ if (usePty) {
+ status = sshConnection.execCommandWithPty(cmd, stdout);
+ } else {
+ status = sshConnection.execCommand(cmd, stdout, stderr);
+ }
+ System.out.println("=> Command [" + cmd + "] status is [" + status + "], stdout is [" + String.valueOf(stdout) + "], stderr is [" + String.valueOf(stderr) + "]");
+ return status;
+ }
+
+ private void startServer() throws IOException {
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setSubsystemFactories(Collections.<NamedFactory<Command>>singletonList(new SftpSubsystem.Factory()));
+ sshd.setCommandFactory(new ScpCommandFactory(new CommandFactory() {
+
+ public Command createCommand(String command) {
+ EnumSet<ProcessShellFactory.TtyOptions> ttyOptions;
+ if (OsUtils.isUNIX()) {
+ ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr);
+ } else {
+ ttyOptions = EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr);
+ }
+ return new ProcessShellFactory(command.split(" "), ttyOptions).create();
+ }
+ }));
+ if (OsUtils.isUNIX()) {
+ sshd.setShellFactory(new ProcessShellFactory(new String[]{"/bin/sh", "-i", "-l"},
+ EnumSet.of(ProcessShellFactory.TtyOptions.ONlCr)));
+ } else {
+ sshd.setShellFactory(new ProcessShellFactory(new String[]{"cmd.exe "},
+ EnumSet.of(ProcessShellFactory.TtyOptions.Echo, ProcessShellFactory.TtyOptions.ICrNl, ProcessShellFactory.TtyOptions.ONlCr)));
+ }
+// if(SecurityUtils.isBouncyCastleRegistered()) {
+// sshd.setKeyPairProvider(new PEMGeneratorHostKeyProvider(System.getProperty("java.io.tmpdir") + "/key.pem"));
+// } else {
+ sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(System.getProperty("java.io.tmpdir") + "/key.ser"));
+// }
+ sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
+
+ @Override
+ public boolean authenticate(String username, String password, ServerSession session) {
+ return (SSH_USERNAME.equals(username) && SSH_PASSWORD.equals(password));
+ }
+ });
+ sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {
+
+ public boolean authenticate(String username, PublicKey key, ServerSession session) {
+ return true;
+ }
+ });
+ sshd.getProperties().put(SshServer.WELCOME_BANNER, "Welcome to SSHD\n");
+ startServer0();
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ private void startServer0() throws IOException {
+ boolean serverStarted = false;
+ IOException exception = null;
+ while (!serverStarted && (sshPort < Integer.MAX_VALUE)) {
+ try {
+ System.out.println("Starting SSH server on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
+ sshd.setPort(sshPort);
+ sshd.start();
+ serverStarted = true;
+ } catch (BindException e) {
+ System.err.println("Cannot start SSH server on port [" + sshPort + "]. " + e.getMessage());
+ if (exception == null) {
+ // store first thrown exception - will be thrown if cannot start the server
+ exception = e;
+ }
+ sshPort++;
+ }
+ }
+ if (!serverStarted) {
+ throw exception;
+ }
+ System.out.println("SSH server started on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
+ }
+
+ private void stopServer() {
+ try {
+ if (sshd != null) {
+ sshd.stop(true);
+ System.out.println("SSH server stopped on port [" + sshPort + "]. [" + getClass().getName() + "#" + System.identityHashCode(this) + "]");
+ }
+ } catch (InterruptedException e) {
+ System.err.println("=> Error stopping SSH server.");
+ e.printStackTrace();
+ } finally {
+ sshd = null;
+ }
+ }
+}