diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/BasicConnectionAuthorizationHandler.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/BasicConnectionAuthorizationHandler.java new file mode 100644 index 000000000..8a259d0c8 --- /dev/null +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/BasicConnectionAuthorizationHandler.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2019- UT-Battelle, LLC. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Initial API and implementation and/or initial documentation - + * Jay Jay Billings, Joe Osborn + *******************************************************************************/ +package org.eclipse.ice.commands; + +/** + * This class is intended to offer the possibility to establish a connection via + * a basic authorization process, wherein one just obtains the username, + * hostname, and password from the user. It is intended to be a concrete + * implementation of ConnectionAuthorizationHandler in its most basic form. It + * is recommended to use alternative authorization handlers to establish a + * connection, as this is the only one where the password is stored in memory + * for some time period. See comments in + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#password} and + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#setPassword(char[])} + * + * @author Joe Osborn + * + */ +public class BasicConnectionAuthorizationHandler extends ConnectionAuthorizationHandler { + + /** + * Default constructor + */ + public BasicConnectionAuthorizationHandler() { + } + + /** + * See {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#getPassword()} + * and the above comments on use of this class + */ + @Override + protected char[] getPassword() { + return password; + } + + /** + * No options required for console authorization + * See {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#setOption(String)} + */ + @Override + public void setOption(String option) { + return; + } + + + +} diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/Command.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/Command.java index 919be83e9..ad14ce6a5 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/Command.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/Command.java @@ -63,6 +63,13 @@ public abstract class Command { */ protected int exitValue = -1; + /** + * Have a connection manager for commands that defaults to the static object + * from the factory method. Users can override this if they want to through a + * specific constructor which sets the manager. + */ + protected ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); + /** * Default constructor */ diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/Connection.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/Connection.java index 34a0df052..3153352db 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/Connection.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/Connection.java @@ -34,7 +34,7 @@ public class Connection { * An AtomicReference to the ConnectionConfiguration from which connection * information can be gathered */ - private AtomicReference configuration; + private AtomicReference configuration = new AtomicReference(null);; /** * The secure channel provided by com.jcraft.jsch @@ -70,7 +70,6 @@ public class Connection { * Default constructor */ public Connection() { - configuration = new AtomicReference(new ConnectionConfiguration()); } /** @@ -92,6 +91,9 @@ public ConnectionConfiguration getConfiguration() { return configuration.get(); } + public void setConfiguration(ConnectionConfiguration configuration) { + this.configuration.set(configuration); + } /** * Set the JShell session {@link org.eclipse.ice.commands.Connection#jShell} * diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionAuthorizationHandler.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionAuthorizationHandler.java index de9de62c6..d2f0de421 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionAuthorizationHandler.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionAuthorizationHandler.java @@ -42,6 +42,20 @@ public abstract class ConnectionAuthorizationHandler { */ String hostname = null; + /** + * A char array which can hold a password should the user desire. It is not + * recommended to use this since this stores the password in memory for some + * time. Rather, it is recommended to use either the + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#getPassword()} + * function, which retrieves the password from the user in some way, or use + * the private key functionality for establishing a connection as in + * {@link org.eclipse.ice.commands.ConnectionManagerTest#testOpenConnectionKeyPath}. + * Note that in all implementations of getPassword, the password is not actually + * stored in this char[] and is rather obtained where it is needed to establish + * a connection and then immediately destroyed. + */ + char[] password = null; + /** * This function gets a password for the command authentication. The password is * returned in a char array since Strings are immutable, so it is generally ill @@ -51,6 +65,17 @@ public abstract class ConnectionAuthorizationHandler { */ protected abstract char[] getPassword(); + /** + * This function is intended to be a "jack of all trades" function where an option + * can be passed that may be specific to a particular subclass. For example, for + * text file authorization, a path to the text file can be passed as specified + * by the subclass. The purpose of this function is for ease of setting things + * in the factory method. + * + * @param option + */ + public abstract void setOption(String option); + /** * Getter for authorization hostname * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#hostname} @@ -91,4 +116,23 @@ public void setUsername(String username) { this.username = username; } + /** + * Setter for {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#password} + * Please see the associated comment to this member variable before using this function. + * It is highly recommended that after a connection is established, this function is + * called again to remove the password information from memory. For example: + * ```java + * ConnectionAuthorizationHandler handler = new BasicConnectionAuthorizationHandler(); + * handler.setPassword("password".toCharArray()); + * // Now establish some connection with the ConnectionManager + * (insert code to establish connection) + * // Now erase the password from memory + * handler.setPassword("".toCharArray()); + * ``` + * @param password + */ + public void setPassword(char[] password) { + this.password = password; + } + } diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionAuthorizationHandlerFactory.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionAuthorizationHandlerFactory.java index 7ceff25bd..1994aef35 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionAuthorizationHandlerFactory.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionAuthorizationHandlerFactory.java @@ -48,7 +48,12 @@ public ConnectionAuthorizationHandlerFactory() { // A text file containing all credentials. Authorization will automatically grab // credentials handlerList.put("text", new TxtFileConnectionAuthorizationHandler()); - + // Use a path to a key pair that was already generated to establish the + // connection + handlerList.put("keypath", new KeyPathConnectionAuthorizationHandler()); + // Use a basic authorization by just explicitly setting the username, + // hostname, and password + handlerList.put("basic", new BasicConnectionAuthorizationHandler()); } /** @@ -70,7 +75,7 @@ public ConnectionAuthorizationHandler getConnectionAuthorizationHandler(String t * @param type - type of authorization handler desired * @return - authorization handler */ - public ConnectionAuthorizationHandler getConnectionAuthorizationHandler(String type, String path) { + public ConnectionAuthorizationHandler getConnectionAuthorizationHandler(String type, String option) { ConnectionAuthorizationHandler auth = null; // Iterate over the default authorization types @@ -78,16 +83,11 @@ public ConnectionAuthorizationHandler getConnectionAuthorizationHandler(String t // Check if the type matches, and set the auth variable if (type.equals(entry.getKey())) { auth = entry.getValue(); + // Set the option for the authorization, if necessary + auth.setOption(option); } } - // Have a separate set for a text file authorization since it needs to take the - // path as a constructor argument - // TODO - think about if there is a better way to do this - don't want to have - // to add an additional if statement for each non-default constructor - if (type.equals("text")) - auth = new TxtFileConnectionAuthorizationHandler(path); - if (auth == null) logger.error("Unknown authorization type! Will return null."); diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionManager.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionManager.java index e0e37160b..79ade0d5a 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionManager.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionManager.java @@ -23,8 +23,8 @@ import com.jcraft.jsch.JSchException; /** - * This factory class manages remote connections, and as such interfaces with - * all classes that are associated with remote connections. + * This class manages remote connections, and as such interfaces with all + * classes that are associated with remote connections. * * @author Joe Osborn * @@ -73,7 +73,6 @@ public ConnectionManager() { * @return Connection - returns connection if successful, null otherwise */ public Connection openConnection(ConnectionConfiguration config) throws JSchException { - // The new connection to be opened Connection newConnection = new Connection(config); @@ -88,11 +87,6 @@ public Connection openConnection(ConnectionConfiguration config) throws JSchExce // Get the information necessary to open the connection if (newConnection.getConfiguration() != null) { ConnectionAuthorizationHandler auth = newConnection.getConfiguration().getAuthorization(); - - // Get the password first. If authorization is a text file, then - // username and hostname will be set. Otherwise user must set them - char[] pwd = auth.getPassword(); - String username = auth.getUsername(); String hostname = auth.getHostname(); @@ -104,31 +98,25 @@ public Connection openConnection(ConnectionConfiguration config) throws JSchExce throw new JSchException(); } - // Pass it to the session - newConnection.getSession().setPassword(String.valueOf(pwd)); - - // Erase contents of pwd and fill with null - Arrays.fill(pwd, Character.MIN_VALUE); + // Authorize the JSch session with a ConnectionAuthorizationHandler + authorizeSession(newConnection); // JSch default requests ssh-rsa host checking, but some keys // request ecdsa-sha2-nistp256. So loop through the available // host keys that were grabbed from known_hosts and check what // type the user-given hostname needs HostKeyRepository hkr = jsch.getHostKeyRepository(); - + String type = null; for (HostKey hk : hkr.getHostKey()) { // If this hostkey contains the hostname that was supplied by // the user if (hk.getHost().contains(hostname)) { - String type = hk.getType(); + type = hk.getType(); // Set the session configuration key type to that hosts type newConnection.getSession().setConfig("server_host_key", type); } } - // Set the authentication requirements - newConnection.getSession().setConfig("PreferredAuthentications", "publickey,password"); - // If the user wants to disable StrictHostKeyChecking, add it to the // session configuration if (!requireStrictHostKeyChecking) @@ -138,9 +126,8 @@ public Connection openConnection(ConnectionConfiguration config) throws JSchExce try { newConnection.getSession().connect(); } catch (JSchException e) { - // Add something here that if this is a first time connect, and thus - // the fingerprint doesn't exist, to try to manually override? - logger.error("Couldn't connect to session with given username and/or password. Exiting.", e); + logger.error("Couldn't connect to session with given username and/or password/key. Exiting.", e); + throw new JSchException(); } @@ -158,6 +145,42 @@ public Connection openConnection(ConnectionConfiguration config) throws JSchExce return null; } + /** + * This function deals with the new connection authentication. It takes a + * connection that is being opened, and decides what kind of authentication to + * provide JSch depending on whether or not a password exists in the + * ConnectionAuthorizationHandler. + * + * @param connection + * @throws JSchException + */ + private void authorizeSession(Connection connection) throws JSchException { + // Get the authorization information + ConnectionAuthorizationHandler auth = connection.getConfiguration().getAuthorization(); + + // If a password was set, then try to authenticate with the password + if (auth.getPassword() != null) { + logger.info("Trying to authenticate with a password"); + // Get the password first. If authorization is a text file, then + // username and hostname will be set. Otherwise user must set them + char[] pwd = auth.getPassword(); + + // Pass it to the session + connection.getSession().setPassword(String.valueOf(pwd)); + + // Erase contents of pwd and fill with null + Arrays.fill(pwd, Character.MIN_VALUE); + // Set the authentication requirements + connection.getSession().setConfig("PreferredAuthentications", "publickey,password"); + } else { + logger.info("Trying to authenticate with a key"); + // Otherwise try a key authentication + String keyPath = ((KeyPathConnectionAuthorizationHandler) auth).getKeyPath(); + connection.getJShellSession().addIdentity(keyPath); + } + return; + } + /** * This function finds the particular connection requested by name in the list * of all connections and returns it. @@ -250,6 +273,17 @@ public void closeAllConnections() { } + /** + * This function allows adding a user defined connection to the connection + * manager rather than opening a default connection through the function + * {@link ConnectionManager#openConnection(ConnectionConfiguration)}. + * + * @param connection + */ + public void addConnection(Connection connection) { + connectionList.put(connection.getConfiguration().getName(), connection); + } + /** * This function lists all the connections (and their statuses, i.e. if open or * not) to the logger, if so desired. Useful for checking the connections and diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionManagerFactory.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionManagerFactory.java index eeade5daf..fd85cd6de 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionManagerFactory.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConnectionManagerFactory.java @@ -24,7 +24,7 @@ */ public class ConnectionManagerFactory { - static ConnectionManager manager = new ConnectionManager(); + static private ConnectionManager manager = new ConnectionManager(); /** * Default constructor diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConsoleConnectionAuthorizationHandler.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConsoleConnectionAuthorizationHandler.java index 628655daf..9accfa387 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConsoleConnectionAuthorizationHandler.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/ConsoleConnectionAuthorizationHandler.java @@ -66,4 +66,13 @@ protected char[] getPassword() { return password.toCharArray(); } + /** + * No options required for console authorization + * See {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#setOption(String)} + */ + @Override + public void setOption(String option) { + return; + } + } diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/FileHandler.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/FileHandler.java index 0adab94d7..0a071f6d2 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/FileHandler.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/FileHandler.java @@ -64,6 +64,16 @@ public abstract class FileHandler implements IFileHandler { */ protected HandleType HANDLE_TYPE = null; + + /** + * Have a connection manager for commands that defaults to the static object from + * the factory method. Users can override this if they want to through a specific + * constructor which sets the manager. + */ + protected ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); + + + /** * Default constructor */ diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/KeyPathConnectionAuthorizationHandler.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/KeyPathConnectionAuthorizationHandler.java new file mode 100644 index 000000000..48262bb73 --- /dev/null +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/KeyPathConnectionAuthorizationHandler.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2019- UT-Battelle, LLC. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Initial API and implementation and/or initial documentation - + * Jay Jay Billings, Joe Osborn + *******************************************************************************/ +package org.eclipse.ice.commands; + +/** + * This class handles authentication via a path for a key which contains an ssh + * fingerprint that can establish the connection. + * + * @author Joe Osborn + * + */ +public class KeyPathConnectionAuthorizationHandler extends ConnectionAuthorizationHandler { + + private String keyPath = null; + + /** + * Default constructor + */ + public KeyPathConnectionAuthorizationHandler() { + } + + public KeyPathConnectionAuthorizationHandler(String keyPath) { + this.keyPath = keyPath; + } + + /** + * Setter for + * {@link org.eclipse.ice.commands.KeyPathConnectionAuthorizationHandler#keyPath} + * + * @param keyPath + */ + @Override + public void setOption(String option) { + this.keyPath = option; + } + + /** + * Getter for + * {@link org.eclipse.ice.commands.KeyPathConnectionAuthorizationHandler#keyPath} + * + * @return + */ + public String getKeyPath() { + return keyPath; + } + /** + * See + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#getPassword()} + * No need for implementation here since the password should not be necessary if + * a key has already been generated + */ + @Override + protected char[] getPassword() { + return null; + } + +} diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/LocalConnectionAuthorizationHandler.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/LocalConnectionAuthorizationHandler.java index a1cd26c21..0186e06ff 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/LocalConnectionAuthorizationHandler.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/LocalConnectionAuthorizationHandler.java @@ -30,6 +30,7 @@ public class LocalConnectionAuthorizationHandler extends ConnectionAuthorization public LocalConnectionAuthorizationHandler() { // By default local authorization has local host as the hostname, so set it hostname = getLocalHostname(); + username = System.getProperty("user.name"); } /** @@ -61,4 +62,12 @@ protected static String getLocalHostname() { return hostname; } + /** + * No options required for console authorization See + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#setOption(String)} + */ + @Override + public void setOption(String option) { + return; + } } diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/RemoteCommand.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/RemoteCommand.java index 249925024..97b1eca80 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/RemoteCommand.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/RemoteCommand.java @@ -47,7 +47,7 @@ public class RemoteCommand extends Command { * that machine to connect to a second machine. TODO - Implement multi-hop * connections with secondConnection */ - private Connection secondConnection = new Connection(); + private AtomicReference secondConnection = new AtomicReference(new Connection()); /** * A file output stream for error messages to be remotely logged to @@ -78,21 +78,30 @@ public RemoteCommand() { * additional connection, if the command is meant to multi-hop where * one remote host is used to execute a job on another remote host */ - public RemoteCommand(CommandConfiguration _commandConfig, ConnectionConfiguration connectConfig, + public RemoteCommand(CommandConfiguration commandConfig, ConnectionConfiguration connectConfig, ConnectionConfiguration extraConnection) { // Set the command and connection configurations - commandConfig = _commandConfig; - connectionConfig = connectConfig; + this.commandConfig = commandConfig; + this.connectionConfig = connectConfig; + this.secondConnection.get().setConfiguration(extraConnection); + openAndSetConnection(); - // Get the connection manager to open a new connection - ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); + status = CommandStatus.PROCESSING; + } + /** + * Opens and sets a connection based on what was passed in the constructor. This + * function first checks if a connection with the same name is already available + * in the connection manager, and if so, grabs it. Otherwise, it opens a new + * connection with the provided information. + */ + private void openAndSetConnection() { // Open and set the connection(s) try { - if (manager.getConnection(connectConfig.getName()) == null) { - connection.set(manager.openConnection(connectConfig)); + if (manager.getConnection(connectionConfig.getName()) == null) { + connection.set(manager.openConnection(connectionConfig)); } else { - connection.set(manager.getConnection(connectConfig.getName())); + connection.set(manager.getConnection(connectionConfig.getName())); // Make sure the connections are starting fresh from scratch if (connection.get().getExecChannel() != null) connection.get().getExecChannel().disconnect(); @@ -102,16 +111,17 @@ public RemoteCommand(CommandConfiguration _commandConfig, ConnectionConfiguratio // Set the commandConfig hostname to that of the connectionConfig - only used // for output logging info - commandConfig.setHostname(connectConfig.getAuthorization().getHostname()); + commandConfig.setHostname(connectionConfig.getAuthorization().getHostname()); // If there is an extra connection so that we are multi-hopping, then open it // too // TODO - the multi-hop API isn't implemented yet - need to work on it - if (extraConnection != null) { - secondConnection = manager.openConnection(extraConnection); + ConnectionConfiguration secondConfig = secondConnection.get().getConfiguration(); + if (secondConfig != null) { + secondConnection.set(manager.openConnection(secondConfig)); // Set the commandConfig hostname to be the extra connection, since this is // really where the job will run - commandConfig.setHostname(extraConnection.getAuthorization().getHostname()); + commandConfig.setHostname(secondConnection.get().getConfiguration().getAuthorization().getHostname()); } } catch (JSchException e) { // If the connection(s) can't be opened, we can't be expected to execute a job @@ -122,7 +132,6 @@ public RemoteCommand(CommandConfiguration _commandConfig, ConnectionConfiguratio return; } - status = CommandStatus.PROCESSING; } /** diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/RemoteFileHandler.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/RemoteFileHandler.java index a2b0f6922..4c359f75d 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/RemoteFileHandler.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/RemoteFileHandler.java @@ -12,9 +12,6 @@ package org.eclipse.ice.commands; import java.io.IOException; -import java.util.HashMap; -import java.util.ArrayList; - import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSchException; @@ -59,8 +56,6 @@ public void setConnectionConfiguration(ConnectionConfiguration config) { // Get the connection manager and open the connection in constructor so that it // is only performed once, thus the connection isn't constantly re-requiring // password authentication - ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); - // First check if there is already an existing connection open with these // details if (manager.getConnection(config.getName()) == null) { diff --git a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/TxtFileConnectionAuthorizationHandler.java b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/TxtFileConnectionAuthorizationHandler.java index 652a3554f..0a271e404 100644 --- a/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/TxtFileConnectionAuthorizationHandler.java +++ b/org.eclipse.ice.commands/src/main/java/org/eclipse/ice/commands/TxtFileConnectionAuthorizationHandler.java @@ -42,15 +42,14 @@ public TxtFileConnectionAuthorizationHandler() { } /** - * Constructor where a particular pathname to the text file is given - * - * @param path + * No options required for console authorization + * See {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#setOption(String)} */ - public TxtFileConnectionAuthorizationHandler(String path) { - this.path = path; + @Override + public void setOption(String option) { + this.path = option; setUsernameHostname(); } - /** * See * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandler#getPassword()} diff --git a/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionAuthorizationHandlerFactoryTest.java b/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionAuthorizationHandlerFactoryTest.java new file mode 100644 index 000000000..8871c5df9 --- /dev/null +++ b/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionAuthorizationHandlerFactoryTest.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2019- UT-Battelle, LLC. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Initial API and implementation and/or initial documentation - + * Jay Jay Billings, Joe Osborn + *******************************************************************************/ +package org.eclipse.ice.tests.commands; + +import static org.junit.Assert.*; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import org.eclipse.ice.commands.ConnectionAuthorizationHandler; +import org.eclipse.ice.commands.ConnectionAuthorizationHandlerFactory; +import org.eclipse.ice.commands.ConnectionConfiguration; +import org.eclipse.ice.commands.ConnectionManagerFactory; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.jcraft.jsch.JSchException; + +/** + * This class tests + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandlerFactory} + * + * @author Joe Osborn + * + */ +public class ConnectionAuthorizationHandlerFactoryTest { + + private ConnectionAuthorizationHandlerFactory factory = new ConnectionAuthorizationHandlerFactory(); + + /** + * Tests local authorization of + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandlerFactory#getConnectionAuthorizationHandler(String)} + */ + @Test + public void testLocalAuthorization() { + // Get a local authorization; + ConnectionAuthorizationHandler local = factory.getConnectionAuthorizationHandler("local"); + // Get the hostname for your local computer + InetAddress addr = null; + try { + addr = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + // Assert that the username and hostname are that of the local computer + assert (local.getHostname() == addr.getHostName()); + assert (local.getUsername() == System.getProperty("user.name")); + + } + + /** + * Tests text file authorization of + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandlerFactory#getConnectionAuthorizationHandler(String)} + * + * @throws JSchException + */ + @Test + public void testTextAuthorization() throws JSchException { + String credFile = "/tmp/ice-remote-creds.txt"; + if (System.getProperty("os.name").toLowerCase().contains("win")) + credFile = "C:\\Users\\Administrator\\ice-remote-creds.txt"; + + // Get a text file authorization handler + ConnectionAuthorizationHandler text = factory.getConnectionAuthorizationHandler("text", credFile); + + // Assert that the hostname and username are the dummy test host + assert (text.getHostname().equals("osbornjd-ice-host.ornl.gov")); + assert (text.getUsername().equals("dummy")); + + // Create a connection configuration to actually try and open the connection + ConnectionConfiguration config = new ConnectionConfiguration(); + config.setName("Text"); + config.setAuthorization(text); + + // Try to open the connection + ConnectionManagerFactory.getConnectionManager().openConnection(config); + // Assert that it was correctly opened + assert (ConnectionManagerFactory.getConnectionManager().isConnectionOpen("Text")); + // Close it since we are done with it + ConnectionManagerFactory.getConnectionManager().removeAllConnections(); + } + + /** + * Tests key path authorization of + * {@link org.eclipse.ice.commands.ConnectionAuthorizationHandlerFactory#getConnectionAuthorizationHandler(String)} + * + * @throws JSchException + */ + @Test + public void testKeyPathAuthorization() throws JSchException { + // Filepath to the dummy host key + String keyPath = "~/.ssh/dummyhostkey"; + // Create a connection authorization handler for a keypath + ConnectionAuthorizationHandler auth = factory.getConnectionAuthorizationHandler("keypath", keyPath); + auth.setHostname("osbornjd-ice-host.ornl.gov"); + auth.setUsername("dummy"); + // Make a connection configuration with the key information + ConnectionConfiguration config = new ConnectionConfiguration(); + config.setName("keyPath"); + config.setAuthorization(auth); + + // Try to open the connection + ConnectionManagerFactory.getConnectionManager().openConnection(config); + // Assert that it was correctly opened + assert (ConnectionManagerFactory.getConnectionManager().isConnectionOpen("keyPath")); + // Close it since we are done with it + ConnectionManagerFactory.getConnectionManager().removeAllConnections(); + + } + +} diff --git a/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionManagerTest.java b/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionManagerTest.java index 1c0a9108a..8392a69a9 100644 --- a/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionManagerTest.java +++ b/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionManagerTest.java @@ -16,12 +16,15 @@ import java.util.HashMap; import java.util.Scanner; +import org.eclipse.ice.commands.BasicConnectionAuthorizationHandler; import org.eclipse.ice.commands.Connection; import org.eclipse.ice.commands.ConnectionAuthorizationHandler; import org.eclipse.ice.commands.ConnectionAuthorizationHandlerFactory; import org.eclipse.ice.commands.ConnectionConfiguration; import org.eclipse.ice.commands.ConnectionManager; import org.eclipse.ice.commands.ConnectionManagerFactory; +import org.eclipse.ice.commands.KeyPathConnectionAuthorizationHandler; +import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -54,11 +57,6 @@ public class ConnectionManagerTest { */ static ConnectionConfiguration configuration = new ConnectionConfiguration(); - /** - * A connection manager to deal with the dummy test connections - */ - ConnectionManager manager = new ConnectionManager(); - /** * This function makes a test connection with which to play with * @@ -85,6 +83,22 @@ public static void setUpBeforeClass() throws Exception { } + /** + * Clear out the connections formed after each test so that each test starts fresh + * with a clean slated connection manager + * @throws Exception + */ + @After + public void tearDown() throws Exception { + // Clear out the connection manager so we start fresh with each test + ConnectionManagerFactory.getConnectionManager().removeAllConnections(); + // Reset the known hosts directory, for after the test with the + // expected JSch exception due to nonexistent known_hosts + ConnectionManagerFactory.getConnectionManager() + .setKnownHosts(System.getProperty("user.home") + "/.ssh/known_hosts"); + + + } /** * This function deletes all of the connections in the connection manager once * the tests have run and completed. @@ -94,7 +108,6 @@ public static void setUpBeforeClass() throws Exception { @AfterClass public static void tearDownAfterClass() throws Exception { ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); - // Test removing all connections from the list in ConnectionManager manager.removeAllConnections(); @@ -102,15 +115,47 @@ public static void tearDownAfterClass() throws Exception { assert (manager.getConnectionList().size() == 0); // Make sure the known hosts are reset to the default directory + manager.setKnownHosts(System.getProperty("user.home") + "/.ssh/known_hosts"); + + } + + + /** + * This function tests opening a connection with an already generated key path + * @throws JSchException + */ + @Test + public void testOpenConnectionKeyPath() throws JSchException { + ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); + System.out.println("Testing keypath open connection"); + + // Make a connection configuration for using a key path + ConnectionConfiguration keyConfiguration = new ConnectionConfiguration(); + keyConfiguration.setName("keypath"); + KeyPathConnectionAuthorizationHandler auth = new KeyPathConnectionAuthorizationHandler(); + // Set the authorization information that is needed + auth.setHostname("osbornjd-ice-host.ornl.gov"); + auth.setUsername("dummy"); + auth.setOption("dummyhostkey"); + keyConfiguration.setAuthorization(auth); + // Open the connection + manager.openConnection(keyConfiguration); + + // assert that it was properly opened + assert(manager.isConnectionOpen("keypath")); + ConnectionManagerFactory.getConnectionManager() .setKnownHosts(System.getProperty("user.home") + "/.ssh/known_hosts"); + } + /** * Test method for - * {@link org.eclipse.ice.commands.ConnectionManager#OpenConnection(String)} + * {@link org.eclipse.ice.commands.ConnectionManager#OpenConnection(ConnectionConfiguration)} */ public void testOpenConnection() { + ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); // Set the name of the configuration, in case it was overwritten by other test configuration.setName(connectionName); // Try to open a connection @@ -130,6 +175,7 @@ public void testOpenConnection() { * {@link org.eclipse.ice.commands.ConnectionManager#GetConnection(String)} */ public void testGetConnection() { + ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); Connection testConnection = null; testConnection = manager.getConnection(connectionName); assert (testConnection != null); @@ -144,6 +190,7 @@ public void testGetConnection() { * {@link org.eclipse.ice.commands.ConnectionManager#CloseConnection(String)} */ public void testCloseConnection() { + ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); // disconnect the session manager.closeConnection(connectionName); @@ -162,31 +209,14 @@ public void testCloseConnection() { */ @Test public void testMultipleConnections() { - ConnectionManagerFactory.getConnectionManager() - .setKnownHosts(System.getProperty("user.home") + "/.ssh/known_hosts"); + ConnectionManager manager = ConnectionManagerFactory.getConnectionManager(); + // Read in a dummy configuration file that contains credentials - File file = null; String credFile = "/tmp/ice-remote-creds.txt"; if (System.getProperty("os.name").toLowerCase().contains("win")) credFile = "C:\\Users\\Administrator\\ice-remote-creds.txt"; - file = new File(credFile); - Scanner scanner = null; - try { - scanner = new Scanner(file); - } catch (FileNotFoundException e1) { - e1.printStackTrace(); - } - - // Scan line by line - scanner.useDelimiter("\n"); - - // Get the credentials for the dummy remote account - String username = scanner.next(); - String password = scanner.next(); - String hostname = scanner.next(); - // Set the credentials since they were deleted after closing the previous // connection // Get a factory which determines the type of authorization @@ -220,6 +250,7 @@ public void testMultipleConnections() { // Expect only two connections since one of the connections is not good (i.e. // conn3 has a bad password, therefore it isn't added to the list) + assert (connections.size() == 2); // List all available connections to the console screen @@ -249,9 +280,7 @@ public void testMultipleConnections() { @Test public void testValidConnection() { System.out.println("Testing valid connection"); - ConnectionManagerFactory.getConnectionManager() - .setKnownHosts(System.getProperty("user.home") + "/.ssh/known_hosts"); - + testOpenConnection(); testGetConnection(); @@ -269,7 +298,7 @@ public void testValidConnection() { public void testNoKnownHost() throws JSchException { // Set the known hosts to something random, where we know the ssh fingerprint // doesn't exist - System.out.println("Testing no known host"); + System.out.println("Testing with no known host file, exception expected"); ConnectionManagerFactory.getConnectionManager().setKnownHosts("/tmp/knownhosts"); // Try to open a connection // Should throw a JSchException since the host fingerprint won't match @@ -277,4 +306,7 @@ public void testNoKnownHost() throws JSchException { } + + + } diff --git a/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionTest.java b/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionTest.java index a6b559807..8aa57d0fe 100644 --- a/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionTest.java +++ b/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/ConnectionTest.java @@ -31,7 +31,7 @@ public void testConnection() { Connection connection = new Connection(); // Check that the default connection leaves the configuration empty - assert (connection.getConfiguration().getName().equals("")); + assert (connection.getConfiguration() == null); assert (connection.getSession() == null); } diff --git a/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/RemoteFileBrowserTest.java b/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/RemoteFileBrowserTest.java index 04a3e165d..ba0db78f2 100644 --- a/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/RemoteFileBrowserTest.java +++ b/org.eclipse.ice.commands/src/test/java/org/eclipse/ice/tests/commands/RemoteFileBrowserTest.java @@ -75,6 +75,31 @@ public static void setUpBeforeClass() throws Exception { } /** +<<<<<<< HEAD + * @throws java.lang.Exception + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + ConnectionManagerFactory.getConnectionManager().removeAllConnections(); + } + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + } + + /** +======= +>>>>>>> 354a0ec8cad995c7e88a1f5ace79c97b811f1381 * Function to execute the remote file browsing and remote directory browsing * test. We call one main function so that a file structure can be created at * the beginning of the test, accessed by both "subtests", and then deleted at