You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2018/04/17 12:33:08 UTC
[4/6] mina-sshd git commit: [SSHD-816] Moved all 'main' code for
client commands to sshd-cli module
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/536effdc/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
index 0874b93..1d034c1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SshClient.java
@@ -18,44 +18,24 @@
*/
package org.apache.sshd.client;
-import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.PrintWriter;
import java.io.StreamCorruptedException;
-import java.io.StringWriter;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
import java.nio.file.LinkOption;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.Date;
-import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
-import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.logging.ConsoleHandler;
-import java.util.logging.Formatter;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
import org.apache.sshd.agent.SshAgentFactory;
import org.apache.sshd.client.auth.AuthenticationIdentitiesProvider;
@@ -65,18 +45,12 @@ import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
import org.apache.sshd.client.auth.password.UserAuthPasswordFactory;
import org.apache.sshd.client.auth.pubkey.UserAuthPublicKeyFactory;
-import org.apache.sshd.client.channel.ChannelShell;
-import org.apache.sshd.client.channel.ClientChannel;
-import org.apache.sshd.client.channel.ClientChannelEvent;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.client.config.hosts.HostConfigEntryResolver;
-import org.apache.sshd.client.config.keys.ClientIdentity;
import org.apache.sshd.client.config.keys.ClientIdentityLoader;
import org.apache.sshd.client.config.keys.DefaultClientIdentitiesWatcher;
import org.apache.sshd.client.future.ConnectFuture;
import org.apache.sshd.client.future.DefaultConnectFuture;
-import org.apache.sshd.client.keyverifier.DefaultKnownHostsServerKeyVerifier;
-import org.apache.sshd.client.keyverifier.KnownHostsServerKeyVerifier;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
import org.apache.sshd.client.session.AbstractClientSession;
import org.apache.sshd.client.session.ClientConnectionServiceFactory;
@@ -89,40 +63,22 @@ import org.apache.sshd.client.simple.AbstractSimpleClientSessionCreator;
import org.apache.sshd.client.simple.SimpleClient;
import org.apache.sshd.common.Closeable;
import org.apache.sshd.common.Factory;
-import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.PropertyResolver;
-import org.apache.sshd.common.PropertyResolverUtils;
import org.apache.sshd.common.ServiceFactory;
import org.apache.sshd.common.channel.Channel;
-import org.apache.sshd.common.cipher.BuiltinCiphers;
-import org.apache.sshd.common.cipher.Cipher;
-import org.apache.sshd.common.compression.BuiltinCompressions;
-import org.apache.sshd.common.compression.Compression;
-import org.apache.sshd.common.config.CompressionConfigValue;
-import org.apache.sshd.common.config.SshConfigFileReader;
-import org.apache.sshd.common.config.keys.BuiltinIdentities;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.config.keys.PublicKeyEntry;
import org.apache.sshd.common.future.SshFutureListener;
import org.apache.sshd.common.helpers.AbstractFactoryManager;
import org.apache.sshd.common.io.IoConnectFuture;
import org.apache.sshd.common.io.IoConnector;
import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
-import org.apache.sshd.common.mac.BuiltinMacs;
-import org.apache.sshd.common.mac.Mac;
import org.apache.sshd.common.scp.ScpFileOpener;
import org.apache.sshd.common.session.helpers.AbstractSession;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.common.util.io.NoCloseInputStream;
-import org.apache.sshd.common.util.io.NoCloseOutputStream;
import org.apache.sshd.common.util.net.SshdSocketAddress;
/**
@@ -180,11 +136,6 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
public static final Factory<SshClient> DEFAULT_SSH_CLIENT_FACTORY = SshClient::new;
/**
- * Command line option used to indicate non-default target port
- */
- public static final String SSH_CLIENT_PORT_OPTION = "-p";
-
- /**
* Default user authentication preferences if not set
* @see <A HREF="http://linux.die.net/man/5/ssh_config">ssh_config(5) - PreferredAuthentications</A>
*/
@@ -821,695 +772,4 @@ public class SshClient extends AbstractFactoryManager implements ClientFactoryMa
public static SshClient setUpDefaultClient() {
return ClientBuilder.builder().build();
}
-
- /*=================================
- Main class implementation
- *=================================*/
-
- public static boolean showError(PrintStream stderr, String message) {
- stderr.println(message);
- return true;
- }
-
- public static boolean isArgumentedOption(String portOption, String argName) {
- return portOption.equals(argName)
- || "-i".equals(argName)
- || "-o".equals(argName)
- || "-l".equals(argName)
- || "-w".equals(argName)
- || "-c".equals(argName)
- || "-m".equals(argName)
- || "-E".equals(argName);
- }
-
- // NOTE: ClientSession#getFactoryManager is the SshClient
- public static ClientSession setupClientSession(
- String portOption, BufferedReader stdin, PrintStream stdout, PrintStream stderr, String... args)
- throws Exception {
-
- int port = -1;
- String host = null;
- String login = null;
- String password = null;
- boolean error = false;
- List<Path> identities = new ArrayList<>();
- Map<String, Object> options = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- List<NamedFactory<Cipher>> ciphers = null;
- List<NamedFactory<Mac>> macs = null;
- List<NamedFactory<Compression>> compressions = null;
- int numArgs = GenericUtils.length(args);
- for (int i = 0; (!error) && (i < numArgs); i++) {
- String argName = args[i];
- String argVal = null;
- if (isArgumentedOption(portOption, argName)) {
- if ((i + 1) >= numArgs) {
- error = showError(stderr, "option requires an argument: " + argName);
- break;
- }
-
- argVal = args[++i];
- }
-
- if (portOption.equals(argName)) {
- if (port > 0) {
- error = showError(stderr, argName + " option value re-specified: " + port);
- break;
- }
-
- port = Integer.parseInt(argVal);
- if (port <= 0) {
- error = showError(stderr, "Bad option value for " + argName + ": " + port);
- break;
- }
- } else if ("-w".equals(argName)) {
- if (GenericUtils.length(password) > 0) {
- error = showError(stderr, argName + " option value re-specified: " + password);
- break;
- }
- password = argVal;
- } else if ("-c".equals(argName)) {
- ciphers = setupCiphers(argName, argVal, ciphers, stderr);
- if (GenericUtils.isEmpty(ciphers)) {
- error = true;
- break;
- }
- } else if ("-m".equals(argName)) {
- macs = setupMacs(argName, argVal, macs, stderr);
- if (GenericUtils.isEmpty(macs)) {
- error = true;
- break;
- }
- } else if ("-i".equals(argName)) {
- identities.add(resolveIdentityFile(argVal));
- } else if ("-C".equals(argName)) {
- compressions = setupCompressions(argName,
- GenericUtils.join(
- Arrays.asList(
- BuiltinCompressions.Constants.ZLIB, BuiltinCompressions.Constants.DELAYED_ZLIB), ','),
- compressions, stderr);
- if (GenericUtils.isEmpty(compressions)) {
- error = true;
- break;
- }
- } else if ("-o".equals(argName)) {
- String opt = argVal;
- int idx = opt.indexOf('=');
- if (idx <= 0) {
- error = showError(stderr, "bad syntax for option: " + opt);
- break;
- }
-
- String optName = opt.substring(0, idx);
- String optValue = opt.substring(idx + 1);
- if (HostConfigEntry.IDENTITY_FILE_CONFIG_PROP.equals(optName)) {
- identities.add(resolveIdentityFile(optValue));
- } else {
- options.put(optName, optValue);
- }
- } else if ("-l".equals(argName)) {
- if (login != null) {
- error = showError(stderr, argName + " option value re-specified: " + port);
- break;
- }
-
- login = argVal;
- } else if (argName.charAt(0) != '-') {
- if (host != null) { // assume part of a command following it
- break;
- }
-
- host = argName;
- int pos = host.indexOf('@'); // check if user@host
- if (pos > 0) {
- if (login == null) {
- login = host.substring(0, pos);
- host = host.substring(pos + 1);
- } else {
- error = showError(stderr, "Login already specified using -l option (" + login + "): " + host);
- break;
- }
- }
- }
- }
-
- if ((!error) && GenericUtils.isEmpty(host)) {
- error = showError(stderr, "Hostname not specified");
- }
-
- if (error) {
- return null;
- }
-
- SshClient client = setupClient(options, ciphers, macs, compressions, identities, stdin, stdout, stderr);
- if (client == null) {
- return null;
- }
-
- try {
- client.start();
-
- if (login == null) {
- login = OsUtils.getCurrentUser();
- }
-
- if (port <= 0) {
- port = SshConfigFileReader.DEFAULT_PORT;
- }
-
- // TODO use a configurable wait time
- ClientSession session = client.connect(login, host, port).verify().getSession();
- try {
- if (GenericUtils.length(password) > 0) {
- session.addPasswordIdentity(password);
- }
- session.auth().verify(FactoryManager.DEFAULT_AUTH_TIMEOUT); // TODO use a configurable wait time
- return session;
- } catch (Exception e) {
- session.close(true);
- throw e;
- }
- } catch (Exception e) {
- client.close();
- throw e;
- }
- }
-
- public static Path resolveIdentityFile(String id) throws IOException {
- BuiltinIdentities identity = BuiltinIdentities.fromName(id);
- if (identity != null) {
- String fileName = ClientIdentity.getIdentityFileName(identity.getName());
- Path keysFolder = PublicKeyEntry.getDefaultKeysFolderPath();
- return keysFolder.resolve(fileName);
- } else {
- return Paths.get(id);
- }
- }
-
- // returns null if error encountered
- public static SshClient setupClient(
- Map<String, Object> options,
- List<NamedFactory<Cipher>> ciphers,
- List<NamedFactory<Mac>> macs,
- List<NamedFactory<Compression>> compressions,
- Collection<? extends Path> identities,
- BufferedReader stdin, PrintStream stdout, PrintStream stderr) throws Exception {
- PropertyResolver resolver = PropertyResolverUtils.toPropertyResolver(options);
- if (GenericUtils.isEmpty(ciphers)) {
- ciphers = setupCiphers(resolver, stderr);
- if (ciphers == null) {
- return null;
- }
- }
-
- if (GenericUtils.isEmpty(macs)) {
- macs = setupMacs(resolver, stderr);
- if (macs == null) {
- return null;
- }
- }
-
- if (GenericUtils.isEmpty(compressions)) {
- compressions = setupCompressions(resolver, stderr);
- if (compressions == null) {
- return null;
- }
- }
-
- SshClient client = SshClient.setUpDefaultClient();
- try {
- if (GenericUtils.size(ciphers) > 0) {
- client.setCipherFactories(ciphers);
- }
-
- if (GenericUtils.size(macs) > 0) {
- client.setMacFactories(macs);
- }
-
- if (GenericUtils.size(compressions) > 0) {
- client.setCompressionFactories(compressions);
- }
-
- try {
- setupSessionIdentities(client, identities, stdin, stdout, stderr);
- } catch (Throwable t) { // show but do not fail the setup - maybe a password can be used
- showError(stderr, t.getClass().getSimpleName() + " while loading user keys: " + t.getMessage());
- }
-
- setupServerKeyVerifier(client, options, stdin, stdout, stderr);
- setupSessionUserInteraction(client, stdin, stdout, stderr);
-
- Map<String, Object> props = client.getProperties();
- props.putAll(options);
- return client;
- } catch (Throwable t) {
- showError(stderr, "Failed (" + t.getClass().getSimpleName() + ") to setup client: " + t.getMessage());
- client.close();
- return null;
- }
- }
-
- public static FileKeyPairProvider setupSessionIdentities(ClientFactoryManager client, Collection<? extends Path> identities,
- BufferedReader stdin, PrintStream stdout, PrintStream stderr)
- throws Throwable {
- client.setFilePasswordProvider(file -> {
- stdout.print("Enter password for private key file=" + file + ": ");
- return stdin.readLine();
- });
-
- if (GenericUtils.isEmpty(identities)) {
- return null;
- }
-
- FileKeyPairProvider provider = new FileKeyPairProvider() {
- @Override
- public String toString() {
- return FileKeyPairProvider.class.getSimpleName() + "[clientIdentitiesProvider]";
- }
- };
- provider.setPaths(identities);
- client.setKeyPairProvider(provider);
- return provider;
- }
-
- public static UserInteraction setupSessionUserInteraction(
- ClientAuthenticationManager client, BufferedReader stdin, PrintStream stdout, PrintStream stderr) {
- UserInteraction ui = new UserInteraction() {
- @Override
- public boolean isInteractionAllowed(ClientSession session) {
- return true;
- }
-
- @Override
- public void serverVersionInfo(ClientSession session, List<String> lines) {
- for (String l : lines) {
- stdout.append('\t').println(l);
- }
- }
-
- @Override
- public void welcome(ClientSession clientSession, String banner, String lang) {
- stdout.println(banner);
- }
-
- @Override
- public String[] interactive(ClientSession clientSession, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
- int numPropmts = GenericUtils.length(prompt);
- String[] answers = new String[numPropmts];
- try {
- for (int i = 0; i < numPropmts; i++) {
- stdout.append(prompt[i]).print(" ");
- answers[i] = stdin.readLine();
- }
- } catch (IOException e) {
- stderr.append(e.getClass().getSimpleName()).append(" while read prompts: ").println(e.getMessage());
- }
- return answers;
- }
-
- @Override
- public String getUpdatedPassword(ClientSession clientSession, String prompt, String lang) {
- stdout.append(prompt).print(" ");
- try {
- return stdin.readLine();
- } catch (IOException e) {
- stderr.append(e.getClass().getSimpleName()).append(" while read password: ").println(e.getMessage());
- return null;
- }
- }
- };
- client.setUserInteraction(ui);
- return ui;
- }
-
- public static ServerKeyVerifier setupServerKeyVerifier(
- ClientAuthenticationManager manager, Map<String, ?> options, BufferedReader stdin, PrintStream stdout, PrintStream stderr) {
- ServerKeyVerifier current = manager.getServerKeyVerifier();
- if (current == null) {
- current = ClientBuilder.DEFAULT_SERVER_KEY_VERIFIER;
- manager.setServerKeyVerifier(current);
- }
-
- String strictValue = Objects.toString(options.remove(KnownHostsServerKeyVerifier.STRICT_CHECKING_OPTION), "true");
- if (!SshConfigFileReader.parseBooleanValue(strictValue)) {
- return current;
- }
-
- String filePath = Objects.toString(options.remove(KnownHostsServerKeyVerifier.KNOWN_HOSTS_FILE_OPTION), null);
- if (GenericUtils.isEmpty(filePath)) {
- current = new DefaultKnownHostsServerKeyVerifier(current);
- } else { // if user specifies a different location than default be lenient
- current = new DefaultKnownHostsServerKeyVerifier(current, false, Paths.get(filePath));
- }
-
- ((KnownHostsServerKeyVerifier) current).setModifiedServerKeyAcceptor((clientSession, remoteAddress, entry, expected, actual) -> {
- stderr.append("Mismatched keys presented by ").append(Objects.toString(remoteAddress))
- .append(" for entry=").println(entry);
- stderr.append('\t').append("Expected=").append(KeyUtils.getKeyType(expected))
- .append('-').println(KeyUtils.getFingerPrint(expected));
- stderr.append('\t').append("Actual=").append(KeyUtils.getKeyType(actual))
- .append('-').println(KeyUtils.getFingerPrint(actual));
- stderr.flush(); // just making sure
-
- stdout.append("Accept key and update known hosts: y/[N]");
- stdout.flush(); // just making sure
-
- String ans = GenericUtils.trimToEmpty(stdin.readLine());
- return (GenericUtils.length(ans) > 0) && (Character.toLowerCase(ans.charAt(0)) == 'y');
- });
-
- manager.setServerKeyVerifier(current);
- return current;
- }
-
- public static Level resolveLoggingVerbosity(String... args) {
- return resolveLoggingVerbosity(args, GenericUtils.length(args));
- }
-
- public static Level resolveLoggingVerbosity(String[] args, int maxIndex) {
- for (int index = 0; index < maxIndex; index++) {
- String argName = args[index];
- if ("-v".equals(argName)) {
- return Level.INFO;
- } else if ("-vv".equals(argName)) {
- return Level.FINE;
- } else if ("-vvv".equals(argName)) {
- return Level.FINEST;
- }
- }
-
- return Level.WARNING;
- }
-
- public static OutputStream resolveLoggingTargetStream(PrintStream stdout, PrintStream stderr, String... args) {
- return resolveLoggingTargetStream(stdout, stderr, args, GenericUtils.length(args));
- }
-
- public static OutputStream resolveLoggingTargetStream(PrintStream stdout, PrintStream stderr, String[] args, int maxIndex) {
- for (int index = 0; index < maxIndex; index++) {
- String argName = args[index];
- if ("-E".equals(argName)) {
- if ((index + 1) >= maxIndex) {
- showError(stderr, "Missing " + argName + " option argument");
- return null;
- }
-
- String argVal = args[index + 1];
- if ("--".equals(argVal)) {
- return stdout;
- }
-
- try {
- Path path = Paths.get(argVal).normalize().toAbsolutePath();
- return Files.newOutputStream(path);
- } catch (IOException e) {
- showError(stderr, "Failed (" + e.getClass().getSimpleName() + ") to open " + argVal + ": " + e.getMessage());
- return null;
- }
- }
- }
-
- return stderr;
- }
-
- public static List<NamedFactory<Compression>> setupCompressions(PropertyResolver options, PrintStream stderr) {
- String argVal = PropertyResolverUtils.getString(options, SshConfigFileReader.COMPRESSION_PROP);
- if (GenericUtils.isEmpty(argVal)) {
- return Collections.emptyList();
- }
-
- NamedFactory<Compression> value = CompressionConfigValue.fromName(argVal);
- if (value == null) {
- showError(stderr, "Unknown compression configuration value: " + argVal);
- return null;
- }
-
- return Collections.singletonList(value);
- }
-
- public static List<NamedFactory<Compression>> setupCompressions(
- String argName, String argVal, List<NamedFactory<Compression>> current, PrintStream stderr) {
- if (GenericUtils.size(current) > 0) {
- showError(stderr, argName + " option value re-specified: " + NamedResource.getNames(current));
- return null;
- }
-
- BuiltinCompressions.ParseResult result = BuiltinCompressions.parseCompressionsList(argVal);
- Collection<? extends NamedFactory<Compression>> available = result.getParsedFactories();
- if (GenericUtils.isEmpty(available)) {
- showError(stderr, "No known compressions in " + argVal);
- return null;
- }
-
- Collection<String> unsupported = result.getUnsupportedFactories();
- if (GenericUtils.size(unsupported) > 0) {
- stderr.append("Ignored unsupported compressions: ").println(GenericUtils.join(unsupported, ','));
- }
-
- return new ArrayList<>(available);
- }
-
- public static List<NamedFactory<Mac>> setupMacs(PropertyResolver options, PrintStream stderr) {
- String argVal = PropertyResolverUtils.getString(options, SshConfigFileReader.MACS_CONFIG_PROP);
- return GenericUtils.isEmpty(argVal)
- ? Collections.emptyList()
- : setupMacs(SshConfigFileReader.MACS_CONFIG_PROP, argVal, null, stderr);
- }
-
- public static List<NamedFactory<Mac>> setupMacs(String argName, String argVal, List<NamedFactory<Mac>> current, PrintStream stderr) {
- if (GenericUtils.size(current) > 0) {
- showError(stderr, argName + " option value re-specified: " + NamedResource.getNames(current));
- return null;
- }
-
- BuiltinMacs.ParseResult result = BuiltinMacs.parseMacsList(argVal);
- Collection<? extends NamedFactory<Mac>> available = result.getParsedFactories();
- if (GenericUtils.isEmpty(available)) {
- showError(stderr, "No known MACs in " + argVal);
- return null;
- }
-
- Collection<String> unsupported = result.getUnsupportedFactories();
- if (GenericUtils.size(unsupported) > 0) {
- stderr.append("Ignored unsupported MACs: ").println(GenericUtils.join(unsupported, ','));
- }
-
- return new ArrayList<>(available);
- }
-
- public static List<NamedFactory<Cipher>> setupCiphers(PropertyResolver options, PrintStream stderr) {
- String argVal = PropertyResolverUtils.getString(options, SshConfigFileReader.CIPHERS_CONFIG_PROP);
- return GenericUtils.isEmpty(argVal)
- ? Collections.emptyList()
- : setupCiphers(SshConfigFileReader.CIPHERS_CONFIG_PROP, argVal, null, stderr);
- }
-
- // returns null - e.g., re-specified or no supported cipher found
- public static List<NamedFactory<Cipher>> setupCiphers(String argName, String argVal, List<NamedFactory<Cipher>> current, PrintStream stderr) {
- if (GenericUtils.size(current) > 0) {
- showError(stderr, argName + " option value re-specified: " + NamedResource.getNames(current));
- return null;
- }
-
- BuiltinCiphers.ParseResult result = BuiltinCiphers.parseCiphersList(argVal);
- Collection<? extends NamedFactory<Cipher>> available = result.getParsedFactories();
- if (GenericUtils.isEmpty(available)) {
- showError(stderr, "No known ciphers in " + argVal);
- return null;
- }
-
- Collection<String> unsupported = result.getUnsupportedFactories();
- if (GenericUtils.size(unsupported) > 0) {
- stderr.append("Ignored unsupported ciphers: ").println(GenericUtils.join(unsupported, ','));
- }
-
- return new ArrayList<>(available);
- }
-
- public static Handler setupLogging(Level level, final PrintStream stdout, final PrintStream stderr, final OutputStream outputStream) {
- Handler fh = new ConsoleHandler() {
- {
- setOutputStream(outputStream); // override the default (stderr)
- }
-
- @Override
- protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
- if ((out == stdout) || (out == stderr)) {
- super.setOutputStream(new NoCloseOutputStream(out));
- } else {
- super.setOutputStream(out);
- }
- }
- };
- fh.setLevel(Level.FINEST);
- fh.setFormatter(new Formatter() {
- @Override
- public String format(LogRecord record) {
- String message = formatMessage(record);
- String throwable = "";
- Throwable t = record.getThrown();
- if (t != null) {
- StringWriter sw = new StringWriter();
- try (PrintWriter pw = new PrintWriter(sw)) {
- pw.println();
- t.printStackTrace(pw); // NOPMD
- }
- throwable = sw.toString();
- }
- return String.format("%1$tY-%1$tm-%1$td: %2$-7.7s: %3$-32.32s: %4$s%5$s%n",
- new Date(record.getMillis()), record.getLevel().getName(),
- record.getLoggerName(), message, throwable);
- }
- });
-
- Logger root = Logger.getLogger("");
- for (Handler handler : root.getHandlers()) {
- root.removeHandler(handler);
- }
- root.addHandler(fh);
- root.setLevel(level);
- return fh;
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- public static void main(String[] args) throws Exception {
- PrintStream stdout = System.out;
- PrintStream stderr = System.err;
- boolean agentForward = false;
- List<String> command = null;
- int socksPort = -1;
- int numArgs = GenericUtils.length(args);
- boolean error = false;
- String target = null;
- Level level = Level.WARNING;
- OutputStream logStream = stderr;
- for (int i = 0; i < numArgs; i++) {
- String argName = args[i];
- // handled by 'setupClientSession'
- if (GenericUtils.isEmpty(command) && isArgumentedOption("-p", argName)) {
- if ((i + 1) >= numArgs) {
- error = showError(stderr, "option requires an argument: " + argName);
- break;
- }
-
- i++;
- continue;
- }
-
- // verbosity handled separately
- if (GenericUtils.isEmpty(command) && ("-v".equals(argName) || "-vv".equals(argName) || "-vvv".equals(argName))) {
- continue;
- }
-
- if (GenericUtils.isEmpty(command) && "-D".equals(argName)) {
- if ((i + 1) >= numArgs) {
- error = showError(stderr, "option requires an argument: " + argName);
- break;
- }
- if (socksPort > 0) {
- error = showError(stderr, argName + " option value re-specified: " + socksPort);
- break;
- }
-
- socksPort = Integer.parseInt(args[++i]);
- if (socksPort <= 0) {
- error = showError(stderr, "Bad option value for " + argName + ": " + socksPort);
- break;
- }
- } else if (GenericUtils.isEmpty(command) && "-A".equals(argName)) {
- agentForward = true;
- } else if (GenericUtils.isEmpty(command) && "-a".equals(argName)) {
- agentForward = false;
- } else {
- level = resolveLoggingVerbosity(args, i);
- logStream = resolveLoggingTargetStream(stdout, stderr, args, i);
- if (logStream == null) {
- error = true;
- break;
- }
- if (GenericUtils.isEmpty(command) && target == null) {
- target = argName;
- } else {
- if (command == null) {
- command = new ArrayList<>();
- }
- command.add(argName);
- }
- }
- }
-
- ClientSession session = null;
- try (BufferedReader stdin = new BufferedReader(
- new InputStreamReader(new NoCloseInputStream(System.in), Charset.defaultCharset()))) {
- if (!error) {
- setupLogging(level, stdout, stderr, logStream);
-
- session = setupClientSession(SSH_CLIENT_PORT_OPTION, stdin, stdout, stderr, args);
- if (session == null) {
- error = true;
- }
- }
-
- if (error) {
- System.err.println("usage: ssh [-A|-a] [-v[v][v]] [-E logoutputfile] [-D socksPort]"
- + " [-l login] [" + SSH_CLIENT_PORT_OPTION + " port] [-o option=value]"
- + " [-w password] [-c cipherslist] [-m maclist] [-C]"
- + " hostname/user@host [command]");
- System.exit(-1);
- return;
- }
-
- try (SshClient client = (SshClient) session.getFactoryManager()) {
- /*
- String authSock = System.getenv(SshAgent.SSH_AUTHSOCKET_ENV_NAME);
- if (authSock == null && provider != null) {
- Iterable<KeyPair> keys = provider.loadKeys();
- AgentServer server = new AgentServer();
- authSock = server.start();
- SshAgent agent = new AgentClient(authSock);
- for (KeyPair key : keys) {
- agent.addIdentity(key, "");
- }
- agent.close();
- props.put(SshAgent.SSH_AUTHSOCKET_ENV_NAME, authSock);
- }
- */
-
- try {
- if (socksPort >= 0) {
- session.startDynamicPortForwarding(new SshdSocketAddress(SshdSocketAddress.LOCALHOST_NAME, socksPort));
- Thread.sleep(Long.MAX_VALUE);
- } else {
- ClientChannel channel;
- if (GenericUtils.isEmpty(command)) {
- channel = session.createShellChannel();
- ((ChannelShell) channel).setAgentForwarding(agentForward);
- channel.setIn(new NoCloseInputStream(System.in));
- } else {
- channel = session.createExecChannel(String.join(" ", command).trim());
- }
-
- try (OutputStream channelOut = new NoCloseOutputStream(System.out);
- OutputStream channelErr = new NoCloseOutputStream(System.err)) {
- channel.setOut(channelOut);
- channel.setErr(channelErr);
- channel.open().await(); // TODO use verify and a configurable timeout
- channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), 0L);
- } finally {
- channel.close();
- }
- session.close(false);
- }
- } finally {
- client.stop();
- }
- } finally {
- session.close();
- }
- } finally {
- if (logStream != null && logStream != stdout && logStream != stderr) {
- logStream.close();
- }
- }
- }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/536effdc/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java b/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
deleted file mode 100644
index 6aa7dbb..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.sshd.client;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.InterruptedIOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintStream;
-import java.io.Writer;
-import java.net.ConnectException;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.nio.channels.Channel;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.logging.Level;
-
-import org.apache.sshd.client.auth.keyboard.UserInteraction;
-import org.apache.sshd.client.future.ConnectFuture;
-import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.cipher.ECCurves;
-import org.apache.sshd.common.config.SshConfigFileReader;
-import org.apache.sshd.common.config.keys.BuiltinIdentities;
-import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.config.keys.PublicKeyEntry;
-import org.apache.sshd.common.io.IoSession;
-import org.apache.sshd.common.kex.KexProposalOption;
-import org.apache.sshd.common.keyprovider.KeyPairProvider;
-import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.session.SessionListener;
-import org.apache.sshd.common.signature.BuiltinSignatures;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.io.IoUtils;
-import org.apache.sshd.common.util.io.NoCloseInputStream;
-import org.apache.sshd.common.util.logging.LoggingUtils;
-import org.apache.sshd.common.util.logging.SimplifiedLog;
-import org.apache.sshd.common.util.net.SshdSocketAddress;
-import org.apache.sshd.common.util.security.SecurityUtils;
-
-/**
- * A naive implementation of <A HREF="https://www.freebsd.org/cgi/man.cgi?query=ssh-keyscan&sektion=1">ssh-keyscan(1)</A>
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class SshKeyScan implements Channel, Callable<Void>, ServerKeyVerifier, SessionListener, SimplifiedLog {
- /**
- * Default key types if not overridden from the command line
- */
- public static final List<String> DEFAULT_KEY_TYPES =
- Collections.unmodifiableList(Arrays.asList(BuiltinIdentities.Constants.RSA, BuiltinIdentities.Constants.ECDSA));
- public static final long DEFAULT_TIMEOUT = TimeUnit.SECONDS.toMillis(5L);
- public static final Level DEFAULT_LEVEL = Level.INFO;
-
- private final AtomicBoolean open = new AtomicBoolean(true);
- private SshClient client;
- private int port;
- private long timeout;
- private List<String> keyTypes;
- private InputStream input;
- private Level level;
- private final Map<String, String> currentHostFingerprints = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
-
- public SshKeyScan() {
- super();
- }
-
- public int getPort() {
- return port;
- }
-
- public void setPort(int port) {
- this.port = port;
- }
-
- public InputStream getInputStream() {
- return input;
- }
-
- public void setInputStream(InputStream input) {
- this.input = input;
- }
-
- public List<String> getKeyTypes() {
- return keyTypes;
- }
-
- public void setKeyTypes(List<String> keyTypes) {
- this.keyTypes = keyTypes;
- }
-
- public long getTimeout() {
- return timeout;
- }
-
- public void setTimeout(long timeout) {
- this.timeout = timeout;
- }
-
- public Level getLogLevel() {
- return level;
- }
-
- public void setLogLevel(Level level) {
- this.level = level;
- }
-
- @Override
- public void log(Level level, Object message, Throwable t) {
- if (isEnabled(level)) {
- PrintStream ps = System.out;
- if ((t != null) || Level.SEVERE.equals(level) || Level.WARNING.equals(level)) {
- ps = System.err;
- }
-
- ps.append('\t').println(message);
- if (t != null) {
- ps.append("\t\t").append(t.getClass().getSimpleName()).append(": ").println(t.getMessage());
- }
- }
- }
-
- @Override
- public boolean isEnabled(Level level) {
- return LoggingUtils.isLoggable(level, getLogLevel());
- }
-
- @Override
- public Void call() throws Exception {
- ValidateUtils.checkTrue(isOpen(), "Scanner is closed");
-
- Collection<String> typeNames = getKeyTypes();
- Map<String, List<KeyPair>> pairsMap = createKeyPairs(typeNames);
- /*
- * We will need to switch signature factories for each specific
- * key type in order to force the server to send ONLY that specific
- * key, so pre-create the factories map according to the selected
- * key types
- */
- SortedMap<String, List<NamedFactory<Signature>>> sigFactories = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- Collection<String> sigTypes = GenericUtils.asSortedSet(sigFactories.comparator(), pairsMap.keySet());
- for (String kt : sigTypes) {
- List<NamedFactory<Signature>> factories = resolveSignatureFactories(kt);
- if (GenericUtils.isEmpty(factories)) {
- if (isEnabled(Level.FINEST)) {
- log(Level.FINEST, "Skip empty signature factories for " + kt);
- }
- pairsMap.remove(kt);
- } else {
- sigFactories.put(kt, factories);
- }
- }
-
- ValidateUtils.checkTrue(!GenericUtils.isEmpty(pairsMap), "No client key pairs");
- ValidateUtils.checkTrue(!GenericUtils.isEmpty(sigFactories), "No signature factories");
-
- Exception err = null;
- try {
- ValidateUtils.checkTrue(client == null, "Client still active");
- client = SshClient.setUpDefaultClient();
- client.setServerKeyVerifier(this);
-
- try (BufferedReader rdr = new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8))) {
- client.setUserInteraction(new UserInteraction() {
- @Override
- public boolean isInteractionAllowed(ClientSession session) {
- return true;
- }
-
- @Override
- public String[] interactive(ClientSession session, String name, String instruction, String lang, String[] prompt, boolean[] echo) {
- return null;
- }
-
- @Override
- public String getUpdatedPassword(ClientSession session, String prompt, String lang) {
- return null;
- }
-
- @Override
- public void serverVersionInfo(ClientSession session, List<String> lines) {
- if (isEnabled(Level.FINE) && GenericUtils.isNotEmpty(lines)) {
- for (String l : lines) {
- log(Level.FINE, "Server Info: " + l);
- }
- }
- }
-
- @Override
- public void welcome(ClientSession session, String banner, String lang) {
- if (isEnabled(Level.FINE) && GenericUtils.isNotEmpty(banner)) {
- String[] lines = GenericUtils.split(banner, '\n');
- for (String l : lines) {
- log(Level.FINE, "Welcome[" + lang + "]: " + l);
- }
- }
- }
- });
-
- client.start();
- for (String line = rdr.readLine(); line != null; line = rdr.readLine()) {
- line = GenericUtils.replaceWhitespaceAndTrim(line);
-
- String[] hosts = GenericUtils.split(line, ',');
- if (GenericUtils.isEmpty(hosts)) {
- continue;
- }
-
- for (String h : hosts) {
- if (!isOpen()) {
- throw new InterruptedIOException("Closed while preparing to contact host=" + h);
- }
-
- try {
- resolveServerKeys(client, h, pairsMap, sigFactories);
- } catch (Exception e) {
- // check if interrupted while scanning host keys
- if (e instanceof InterruptedIOException) {
- throw e;
- }
-
- if (isEnabled(Level.FINE)) {
- log(Level.FINE, "Failed to retrieve keys from " + h, e);
- }
- err = GenericUtils.accumulateException(err, e);
- } finally {
- currentHostFingerprints.clear();
- }
- }
- }
- }
- } finally {
- try {
- close();
- } catch (IOException e) {
- err = GenericUtils.accumulateException(err, e);
- }
- }
-
- if (err != null) {
- throw err;
- }
-
- return null;
- }
-
- protected void resolveServerKeys(SshClient client, String host,
- Map<String, List<KeyPair>> pairsMap, Map<String, List<NamedFactory<Signature>>> sigFactories)
- throws IOException {
- // Cannot use forEach because of the potential for throwing IOException by the invoked code
- for (Map.Entry<String, List<KeyPair>> pe : pairsMap.entrySet()) {
- String kt = pe.getKey();
- if (!isOpen()) {
- throw new InterruptedIOException("Closed while attempting to retrieve key type=" + kt + " from " + host);
- }
-
- List<NamedFactory<Signature>> current = client.getSignatureFactories();
- try {
- /*
- * Replace whatever factories there are right now with the
- * specific one for the key in order to extract only the
- * specific host key type
- */
- List<NamedFactory<Signature>> forced = sigFactories.get(kt);
- client.setSignatureFactories(forced);
- resolveServerKeys(client, host, kt, pe.getValue());
- } catch (Exception e) {
- if (isEnabled(Level.FINE)) {
- log(Level.FINE, "Failed to resolve key=" + kt + " for " + host);
- }
-
- if (e instanceof ConnectException) {
- return; // makes no sense to try again with another key type...
- }
- } finally {
- client.setSignatureFactories(current); // don't have to, but be nice...
- }
- }
- }
-
- protected void resolveServerKeys(SshClient client, String host, String kt, List<KeyPair> ids) throws Exception {
- int connectPort = getPort();
- if (isEnabled(Level.FINE)) {
- log(Level.FINE, "Connecting to " + host + ":" + connectPort + " to retrieve key type=" + kt);
- }
-
- ConnectFuture future = client.connect(UUID.randomUUID().toString(), host, connectPort);
- long waitTime = getTimeout();
- if (!future.await(waitTime)) {
- throw new ConnectException("Failed to connect to " + host + ":" + connectPort
- + " within " + waitTime + " msec."
- + " to retrieve key type=" + kt);
- }
-
- try (ClientSession session = future.getSession()) {
- IoSession ioSession = session.getIoSession();
- SocketAddress remoteAddress = ioSession.getRemoteAddress();
- String remoteLocation = toString(remoteAddress);
- if (isEnabled(Level.FINE)) {
- log(Level.FINE, "Connected to " + remoteLocation + " to retrieve key type=" + kt);
- }
-
- try {
- session.addSessionListener(this);
- if (isEnabled(Level.FINER)) {
- log(Level.FINER, "Authenticating with key type=" + kt + " to " + remoteLocation);
- }
-
- GenericUtils.forEach(ids, session::addPublicKeyIdentity);
-
- try {
- // shouldn't really succeed, but do it since key exchange occurs only on auth attempt
- session.auth().verify(waitTime);
- log(Level.WARNING, "Unexpected authentication success using key type=" + kt + " with " + remoteLocation);
- } catch (Exception e) {
- if (isEnabled(Level.FINER)) {
- log(Level.FINER, "Failed to authenticate using key type=" + kt + " with " + remoteLocation);
- }
- } finally {
- GenericUtils.forEach(ids, session::removePublicKeyIdentity);
- }
- } finally {
- session.removeSessionListener(this);
- }
- }
- }
-
- @Override
- public void sessionCreated(Session session) {
- logSessionEvent(session, "Created");
- }
-
- @Override
- public void sessionEvent(Session session, Event event) {
- logSessionEvent(session, event);
- if (isEnabled(Level.FINEST) && Event.KexCompleted.equals(event)) {
- IoSession ioSession = session.getIoSession();
- SocketAddress remoteAddress = ioSession.getRemoteAddress();
- String remoteLocation = toString(remoteAddress);
- for (KexProposalOption paramType : KexProposalOption.VALUES) {
- String paramValue = session.getNegotiatedKexParameter(paramType);
- log(Level.FINEST, remoteLocation + "[" + paramType.getDescription() + "]: " + paramValue);
- }
- }
- }
-
- @Override
- public void sessionException(Session session, Throwable t) {
- logSessionEvent(session, t);
- }
-
- @Override
- public void sessionClosed(Session session) {
- logSessionEvent(session, "Closed");
- }
-
- @Override
- public void sessionNegotiationStart(
- Session session, Map<KexProposalOption, String> clientProposal, Map<KexProposalOption, String> serverProposal) {
- logSessionEvent(session, "sessionNegotiationStart");
- logNegotiationProposal("c2s", clientProposal);
- logNegotiationProposal("s2c", serverProposal);
- }
-
- protected void logNegotiationProposal(String type, Map<KexProposalOption, String> proposal) {
- if (!isEnabled(Level.FINEST)) {
- return;
- }
-
- proposal.forEach((option, value) -> log(Level.FINEST, option.getDescription() + "[" + type + "]: " + value));
- }
-
- @Override
- public void sessionNegotiationEnd(Session session, Map<KexProposalOption, String> clientProposal,
- Map<KexProposalOption, String> serverProposal, Map<KexProposalOption, String> negotiatedOptions,
- Throwable reason) {
- if (reason == null) {
- logSessionEvent(session, "sessionNegotiationStart");
- } else {
- logSessionEvent(session, reason);
- }
- }
-
- protected void logSessionEvent(Session session, Object event) {
- if (isEnabled(Level.FINEST)) {
- IoSession ioSession = session.getIoSession();
- SocketAddress remoteAddress = ioSession.getRemoteAddress();
- log(Level.FINEST, "Session " + toString(remoteAddress) + " event: " + event);
- }
- }
-
- @Override
- public boolean verifyServerKey(ClientSession sshClientSession, SocketAddress remoteAddress, PublicKey serverKey) {
- String remoteLocation = toString(remoteAddress);
- String extra = KeyUtils.getFingerPrint(serverKey);
- try {
- String keyType = KeyUtils.getKeyType(serverKey);
- String current = GenericUtils.isEmpty(keyType) ? null : currentHostFingerprints.get(keyType);
- if (Objects.equals(current, extra)) {
- if (isEnabled(Level.FINER)) {
- log(Level.FINER, "verifyServerKey(" + remoteLocation + ")[" + keyType + "] skip existing key: " + extra);
- }
- } else {
- if (isEnabled(Level.FINE)) {
- log(Level.FINE, "verifyServerKey(" + remoteLocation + ")[" + keyType + "] found new key: " + extra);
- }
-
- writeServerKey(remoteLocation, keyType, serverKey);
-
- if (!GenericUtils.isEmpty(keyType)) {
- currentHostFingerprints.put(keyType, extra);
- }
- }
- } catch (Exception e) {
- log(Level.SEVERE, "Failed to output the public key " + extra + " from " + remoteLocation, e);
- }
-
- return true;
- }
-
- protected void writeServerKey(String remoteLocation, String keyType, PublicKey serverKey) throws Exception {
- StringBuilder sb = new StringBuilder(256).append(remoteLocation).append(' ');
- PublicKeyEntry.appendPublicKeyEntry(sb, serverKey);
- log(Level.INFO, sb);
- }
-
- private static String toString(SocketAddress addr) {
- if (addr == null) {
- return null;
- } else if (addr instanceof InetSocketAddress) {
- return ((InetSocketAddress) addr).getHostString();
- } else if (addr instanceof SshdSocketAddress) {
- return ((SshdSocketAddress) addr).getHostName();
- } else {
- return addr.toString();
- }
- }
-
- protected List<NamedFactory<Signature>> resolveSignatureFactories(String keyType) throws GeneralSecurityException {
- if (isEnabled(Level.FINE)) {
- log(Level.FINE, "Resolve signature factories for " + keyType);
- }
-
- if (BuiltinIdentities.Constants.RSA.equalsIgnoreCase(keyType)) {
- return Collections.singletonList(BuiltinSignatures.rsa);
- } else if (BuiltinIdentities.Constants.DSA.equalsIgnoreCase(keyType)) {
- return Collections.singletonList(BuiltinSignatures.dsa);
- } else if (BuiltinIdentities.Constants.ECDSA.equalsIgnoreCase(keyType)) {
- List<NamedFactory<Signature>> factories = new ArrayList<>(ECCurves.NAMES.size());
- for (String n : ECCurves.NAMES) {
- if (isEnabled(Level.FINER)) {
- log(Level.FINER, "Resolve signature factory for curve=" + n);
- }
-
- NamedFactory<Signature> f =
- ValidateUtils.checkNotNull(BuiltinSignatures.fromString(n), "Unknown curve signature: %s", n);
- factories.add(f);
- }
-
- return factories;
- } else if (BuiltinIdentities.Constants.ED25519.equalsIgnoreCase(keyType)) {
- return Collections.singletonList(BuiltinSignatures.ed25519);
- } else {
- throw new NoSuchAlgorithmException("Unknown key type: " + keyType);
- }
- }
-
- protected Map<String, List<KeyPair>> createKeyPairs(Collection<String> typeNames) throws GeneralSecurityException {
- if (GenericUtils.isEmpty(typeNames)) {
- return Collections.emptyMap();
- }
-
- Map<String, List<KeyPair>> pairsMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- for (String kt : typeNames) {
- if ("*".equalsIgnoreCase(kt) || "all".equalsIgnoreCase(kt)) {
- ValidateUtils.checkTrue(typeNames.size() == 1, "Wildcard key type must be the only one specified: %s", typeNames);
- return createKeyPairs(BuiltinIdentities.NAMES);
- }
-
- if (pairsMap.containsKey(kt)) {
- log(Level.WARNING, "Key type " + kt + " re-specified");
- continue;
- }
-
- List<KeyPair> kps = createKeyPairs(kt);
- if (GenericUtils.isEmpty(kps)) {
- log(Level.WARNING, "No key-pairs generated for key type " + kt);
- continue;
- }
-
- pairsMap.put(kt, kps);
- }
-
- return pairsMap;
- }
-
- protected List<KeyPair> createKeyPairs(String keyType) throws GeneralSecurityException {
- if (isEnabled(Level.FINE)) {
- log(Level.FINE, "Generate key pairs for " + keyType);
- }
-
- if (BuiltinIdentities.Constants.RSA.equalsIgnoreCase(keyType)) {
- return Collections.singletonList(KeyUtils.generateKeyPair(KeyPairProvider.SSH_RSA, 1024));
- } else if (BuiltinIdentities.Constants.DSA.equalsIgnoreCase(keyType)) {
- return Collections.singletonList(KeyUtils.generateKeyPair(KeyPairProvider.SSH_DSS, 512));
- } else if (BuiltinIdentities.Constants.ECDSA.equalsIgnoreCase(keyType)) {
- if (!SecurityUtils.isECCSupported()) {
- throw new NoSuchAlgorithmException("ECC not supported: " + keyType);
- }
-
- List<KeyPair> kps = new ArrayList<>(ECCurves.NAMES.size());
- for (ECCurves curve : ECCurves.VALUES) {
- String curveName = curve.getName();
- if (isEnabled(Level.FINER)) {
- log(Level.FINER, "Generate key pair for curve=" + curveName);
- }
-
- kps.add(KeyUtils.generateKeyPair(curve.getKeyType(), curve.getKeySize()));
- }
-
- return kps;
- } else if (BuiltinIdentities.Constants.ED25519.equalsIgnoreCase(keyType)) {
- if (!SecurityUtils.isEDDSACurveSupported()) {
- throw new NoSuchAlgorithmException("EDDSA curves not supported: " + keyType);
- }
-
- KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA);
- return Collections.singletonList(g.generateKeyPair());
- } else {
- throw new InvalidKeySpecException("Unknown key type: " + keyType);
- }
- }
-
- @Override
- public boolean isOpen() {
- return open.get();
- }
-
- @Override
- public void close() throws IOException {
- if (!open.getAndSet(false)) {
- return; // already closed
- }
-
- IOException err = null;
- if (input != null) {
- try {
- input.close();
- } catch (IOException e) {
- err = GenericUtils.accumulateException(err, e);
- } finally {
- input = null;
- }
- }
-
- if (client != null) {
- try {
- client.close();
- } catch (IOException e) {
- err = GenericUtils.accumulateException(err, e);
- } finally {
- try {
- client.stop();
- } finally {
- client = null;
- }
- }
- }
- if (err != null) {
- throw err;
- }
- }
-
- //////////////////////////////////////////////////////////////////////////
-
- // returns a List of the hosts to be contacted
- public static List<String> parseCommandLineArguments(SshKeyScan scanner, String... args) throws IOException {
- int numArgs = GenericUtils.length(args);
- for (int index = 0; index < numArgs; index++) {
- String optName = args[index];
- if ("-f".equals(optName)) {
- index++;
- ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
- ValidateUtils.checkTrue(scanner.getInputStream() == null, "%s option re-specified", optName);
-
- String filePath = args[index];
- if ("-".equals(filePath)) {
- scanner.setInputStream(new NoCloseInputStream(System.in));
- } else {
- scanner.setInputStream(new FileInputStream(filePath));
- }
- } else if ("-t".equals(optName)) {
- index++;
- ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
- ValidateUtils.checkTrue(GenericUtils.isEmpty(scanner.getKeyTypes()), "%s option re-specified", optName);
-
- String typeList = args[index];
- String[] types = GenericUtils.split(typeList, ',');
- ValidateUtils.checkTrue(GenericUtils.length(types) > 0, "No types specified for %s", optName);
- scanner.setKeyTypes(Arrays.asList(types));
- } else if ("-p".equals(optName)) {
- index++;
- ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
- ValidateUtils.checkTrue(scanner.getPort() <= 0, "%s option re-specified", optName);
-
- String portValue = args[index];
- int port = Integer.parseInt(portValue);
- ValidateUtils.checkTrue((port > 0) && (port <= 0xFFFF), "Bad port: %s", portValue);
- scanner.setPort(port);
- } else if ("-T".equals(optName)) {
- index++;
- ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
- ValidateUtils.checkTrue(scanner.getTimeout() <= 0, "%s option re-specified", optName);
-
- String timeoutValue = args[index];
- long timeout = Long.parseLong(timeoutValue);
- ValidateUtils.checkTrue(timeout > 0L, "Bad timeout: %s", timeoutValue);
- scanner.setTimeout(timeout);
- } else if ("-v".equals(optName)) {
- ValidateUtils.checkTrue(scanner.getLogLevel() == null, "%s option re-specified", optName);
- scanner.setLogLevel(Level.FINEST);
- } else { // stop at first non-option - assume the rest are host names/addresses
- ValidateUtils.checkTrue(optName.charAt(0) != '-', "Unknown option: %s", optName);
-
- int remaining = numArgs - index;
- if (remaining == 1) {
- return Collections.singletonList(optName);
- }
-
- List<String> hosts = new ArrayList<>(remaining);
- for (; index < numArgs; index++) {
- hosts.add(args[index]);
- }
-
- return hosts;
- }
- }
-
- return Collections.emptyList();
- }
-
- /* -------------------------------------------------------------------- */
-
- public static <S extends SshKeyScan> S setInputStream(S scanner, Collection<String> hosts) throws IOException {
- if (GenericUtils.isEmpty(hosts)) {
- Objects.requireNonNull(scanner.getInputStream(), "No hosts or file specified");
- } else {
- ValidateUtils.checkTrue(scanner.getInputStream() == null, "Both hosts and file specified");
-
- // convert the hosts from the arguments into a "file" - one host per line
- try (ByteArrayOutputStream baos = new ByteArrayOutputStream(hosts.size() * 32)) {
- try (Writer w = new OutputStreamWriter(baos, StandardCharsets.UTF_8)) {
- for (String h : hosts) {
- w.append(h).append(IoUtils.EOL);
- }
- }
-
- byte[] data = baos.toByteArray();
- scanner.setInputStream(new ByteArrayInputStream(data));
- }
- }
-
- return scanner;
- }
-
- public static <S extends SshKeyScan> S initializeScanner(S scanner, Collection<String> hosts) throws IOException {
- setInputStream(scanner, hosts);
- if (scanner.getPort() <= 0) {
- scanner.setPort(SshConfigFileReader.DEFAULT_PORT);
- }
-
- if (scanner.getTimeout() <= 0L) {
- scanner.setTimeout(DEFAULT_TIMEOUT);
- }
-
- if (GenericUtils.isEmpty(scanner.getKeyTypes())) {
- scanner.setKeyTypes(DEFAULT_KEY_TYPES);
- }
-
- if (scanner.getLogLevel() == null) {
- scanner.setLogLevel(DEFAULT_LEVEL);
- }
-
- return scanner;
- }
-
- /* -------------------------------------------------------------------- */
-
- public static void main(String[] args) throws Exception {
- try (SshKeyScan scanner = new SshKeyScan()) {
- Collection<String> hosts = parseCommandLineArguments(scanner, args);
- initializeScanner(scanner, hosts);
- scanner.call();
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/536effdc/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
index dfc7f7d..16d0cb2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/scp/DefaultScpClient.java
@@ -18,26 +18,17 @@
*/
package org.apache.sshd.client.scp;
-import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
import java.io.OutputStream;
-import java.io.PrintStream;
-import java.nio.charset.Charset;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.List;
import java.util.Objects;
-import java.util.Set;
-import java.util.logging.Level;
-import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.channel.ChannelExec;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.FactoryManager;
@@ -46,23 +37,15 @@ import org.apache.sshd.common.file.util.MockFileSystem;
import org.apache.sshd.common.file.util.MockPath;
import org.apache.sshd.common.scp.ScpFileOpener;
import org.apache.sshd.common.scp.ScpHelper;
-import org.apache.sshd.common.scp.ScpLocation;
import org.apache.sshd.common.scp.ScpTimestamp;
import org.apache.sshd.common.scp.ScpTransferEventListener;
import org.apache.sshd.common.scp.helpers.DefaultScpFileOpener;
-import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
-import org.apache.sshd.common.util.io.NoCloseInputStream;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class DefaultScpClient extends AbstractScpClient {
- /**
- * Command line option used to indicate a non-default port
- */
- public static final String SCP_PORT_OPTION = "-P";
-
protected final ScpFileOpener opener;
protected final ScpTransferEventListener listener;
private final ClientSession clientSession;
@@ -172,172 +155,5 @@ public class DefaultScpClient extends AbstractScpClient {
channel.close(false);
}
}
-
- //////////////////////////////////////////////////////////////////////////
-
- private static boolean showError(PrintStream stderr, String message) {
- stderr.println(message);
- return true;
- }
-
- private static String[] normalizeCommandArguments(PrintStream stdout, PrintStream stderr, String... args) {
- int numArgs = GenericUtils.length(args);
- if (numArgs <= 0) {
- return args;
- }
-
- List<String> effective = new ArrayList<>(numArgs);
- boolean error = false;
- for (int index = 0; (index < numArgs) && (!error); index++) {
- String argName = args[index];
- // handled by 'setupClientSession'
- if (SshClient.isArgumentedOption(SCP_PORT_OPTION, argName)) {
- if ((index + 1) >= numArgs) {
- error = showError(stderr, "option requires an argument: " + argName);
- break;
- }
-
- effective.add(argName);
- effective.add(args[++index]);
- } else if ("-r".equals(argName) || "-p".equals(argName)
- || "-q".equals(argName) || "-C".equals(argName)
- || "-v".equals(argName) || "-vv".equals(argName) || "-vvv".equals(argName)) {
- effective.add(argName);
- } else if (argName.charAt(0) == '-') {
- error = showError(stderr, "Unknown option: " + argName);
- break;
- } else {
- if ((index + 1) >= numArgs) {
- error = showError(stderr, "Not enough arguments");
- break;
- }
-
- ScpLocation source = new ScpLocation(argName);
- ScpLocation target = new ScpLocation(args[++index]);
- if (index < (numArgs - 1)) {
- error = showError(stderr, "Unexpected extra arguments");
- break;
- }
-
- if (source.isLocal() == target.isLocal()) {
- error = showError(stderr, "Both targets are either remote or local");
- break;
- }
-
- ScpLocation remote = source.isLocal() ? target : source;
- effective.add(remote.resolveUsername() + "@" + remote.getHost());
- effective.add(source.toString());
- effective.add(target.toString());
- break;
- }
- }
-
- if (error) {
- return null;
- }
-
- return effective.toArray(new String[effective.size()]);
- }
-
- public static void main(String[] args) throws Exception {
- final PrintStream stdout = System.out;
- final PrintStream stderr = System.err;
- OutputStream logStream = stdout;
- try (BufferedReader stdin = new BufferedReader(
- new InputStreamReader(new NoCloseInputStream(System.in), Charset.defaultCharset()))) {
- args = normalizeCommandArguments(stdout, stderr, args);
- int numArgs = GenericUtils.length(args);
- // see the way normalizeCommandArguments works...
- if (numArgs >= 2) {
- Level level = SshClient.resolveLoggingVerbosity(args, numArgs - 2);
- logStream = SshClient.resolveLoggingTargetStream(stdout, stderr, args, numArgs - 2);
- if (logStream != null) {
- SshClient.setupLogging(level, stdout, stderr, logStream);
- }
- }
-
- ClientSession session = (logStream == null) || GenericUtils.isEmpty(args)
- ? null : SshClient.setupClientSession(SCP_PORT_OPTION, stdin, stdout, stderr, args);
- if (session == null) {
- stderr.println("usage: scp [" + SCP_PORT_OPTION + " port] [-i identity]"
- + " [-v[v][v]] [-E logoutput] [-r] [-p] [-q] [-o option=value]"
- + " [-c cipherlist] [-m maclist] [-w password] [-C] <source> <target>");
- stderr.println();
- stderr.println("Where <source> or <target> are either 'user@host:file' or a local file path");
- stderr.println("NOTE: exactly ONE of the source or target must be remote and the other one local");
- System.exit(-1);
- return; // not that we really need it...
- }
-
- try {
- // see the way normalizeCommandArguments works...
- Collection<Option> options = EnumSet.noneOf(Option.class);
- boolean quiet = false;
- for (int index = 0; index < numArgs; index++) {
- String argName = args[index];
- if ("-r".equals(argName)) {
- options.add(Option.Recursive);
- } else if ("-p".equals(argName)) {
- options.add(Option.PreserveAttributes);
- } else if ("-q".equals(argName)) {
- quiet = true;
- }
- }
-
- if (!quiet) {
- session.setScpTransferEventListener(new ScpTransferEventListener() {
- @Override
- public void startFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms) {
- logEvent("startFolderEvent", op, file, -1L, perms, null);
- }
-
- @Override
- public void endFolderEvent(FileOperation op, Path file, Set<PosixFilePermission> perms, Throwable thrown) {
- logEvent("endFolderEvent", op, file, -1L, perms, thrown);
- }
-
- @Override
- public void startFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms) {
- logEvent("startFileEvent", op, file, length, perms, null);
- }
-
- @Override
- public void endFileEvent(FileOperation op, Path file, long length, Set<PosixFilePermission> perms, Throwable thrown) {
- logEvent("endFileEvent", op, file, length, perms, thrown);
- }
-
- private void logEvent(String name, FileOperation op, Path file, long length, Collection<PosixFilePermission> perms, Throwable thrown) {
- PrintStream ps = (thrown == null) ? stdout : stderr;
- ps.append('\t').append(name).append('[').append(op.name()).append(']').append(' ').append(file.toString());
- if (length > 0L) {
- ps.append(' ').append("length=").append(Long.toString(length));
- }
- ps.append(' ').append(String.valueOf(perms));
-
- if (thrown != null) {
- ps.append(" - ").append(thrown.getClass().getSimpleName()).append(": ").append(thrown.getMessage());
- }
- ps.println();
- }
- });
- }
-
- ScpClient client = session.createScpClient();
- ScpLocation source = new ScpLocation(args[numArgs - 2]);
- ScpLocation target = new ScpLocation(args[numArgs - 1]);
- if (source.isLocal()) {
- client.upload(source.getPath(), target.getPath(), options);
- } else {
- client.download(source.getPath(), target.getPath(), options);
- }
- } finally {
- session.close();
- }
- } finally {
- if ((logStream != stdout) && (logStream != stderr)) {
- logStream.close();
- }
- }
- }
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/536effdc/sshd-core/src/test/java/org/apache/sshd/client/SshClientMain.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/SshClientMain.java b/sshd-core/src/test/java/org/apache/sshd/client/SshClientMain.java
deleted file mode 100644
index 66f66dd..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/SshClientMain.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.sshd.client;
-
-/**
- * Just a test class used to invoke {@link SshClient#main(String[])} in
- * order to have logging - which is in {@code test} scope
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public final class SshClientMain {
- private SshClientMain() {
- throw new UnsupportedOperationException("No instance");
- }
-
- public static void main(String[] args) throws Exception {
- SshClient.main(args);
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/536effdc/sshd-core/src/test/java/org/apache/sshd/client/SshKeyScanMain.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/SshKeyScanMain.java b/sshd-core/src/test/java/org/apache/sshd/client/SshKeyScanMain.java
deleted file mode 100644
index 856b324..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/SshKeyScanMain.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.sshd.client;
-
-/**
- * Just a test class used to invoke {@link SshKeyScan#main(String[])} in
- * order to have logging - which is in {@code test} scope
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public final class SshKeyScanMain {
- private SshKeyScanMain() {
- throw new UnsupportedOperationException("No instance");
- }
-
- public static void main(String[] args) throws Exception {
- SshKeyScan.main(args);
- }
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/536effdc/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecMain.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecMain.java b/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecMain.java
deleted file mode 100644
index 798fe70..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/channel/ChannelExecMain.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.sshd.client.channel;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
-import java.nio.charset.Charset;
-
-import org.apache.sshd.client.SshClient;
-import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.io.NoCloseInputStream;
-import org.apache.sshd.util.test.BaseTestSupport;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public class ChannelExecMain extends BaseTestSupport {
- public static void doExecuteCommands(
- BufferedReader stdin, PrintStream stdout, PrintStream stderr, ClientSession session) throws Exception {
- while (true) {
- stdout.print("> ");
-
- String command = stdin.readLine();
- if ("q".equalsIgnoreCase(command) || "quit".equalsIgnoreCase(command)) {
- break;
- }
- if (GenericUtils.isEmpty(command)) {
- continue;
- }
-
- while (true) {
- try {
- String response = session.executeRemoteCommand(command);
- String[] lines = GenericUtils.split(response, '\n');
- for (String l : lines) {
- stdout.append('\t').println(l);
- }
- } catch (Exception e) {
- stderr.append(e.getClass().getSimpleName()).append(": ").println(e.getMessage());
- }
-
- stdout.append("Execute ").append(command).print(" again [y]/n ");
- String ans = stdin.readLine();
- if ((GenericUtils.length(ans) > 0) && (Character.toLowerCase(ans.charAt(0)) != 'y')) {
- break;
- }
- }
- }
- }
-
- public static void main(String[] args) throws Exception {
- PrintStream stdout = System.out;
- PrintStream stderr = System.err;
- try (BufferedReader stdin = new BufferedReader(
- new InputStreamReader(new NoCloseInputStream(System.in), Charset.defaultCharset()))) {
- ClientSession session = SshClient.setupClientSession("-P", stdin, stdout, stderr, args);
- if (session == null) {
- System.err.println("usage: channelExec [-i identity] [-l login] [-P port] [-o option=value]"
- + " [-w password] [-c cipherlist] [-m maclist] [-C] hostname/user@host");
- System.exit(-1);
- return;
- }
-
- try (SshClient client = (SshClient) session.getFactoryManager()) {
- try (ClientSession clientSession = session) {
- doExecuteCommands(stdin, stdout, stderr, session);
- } finally {
- client.stop();
- }
- }
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/536effdc/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpCommandMain.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpCommandMain.java b/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpCommandMain.java
deleted file mode 100644
index 75b0454..0000000
--- a/sshd-core/src/test/java/org/apache/sshd/client/scp/ScpCommandMain.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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.
- */
-
-package org.apache.sshd.client.scp;
-
-/**
- * Just a test class used to invoke {@link org.apache.sshd.client.scp.DefaultScpClient#main(String[])} in
- * order to have logging - which is in {@code test} scope
- *
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public final class ScpCommandMain {
- private ScpCommandMain() {
- throw new UnsupportedOperationException("No instance");
- }
-
- public static void main(String[] args) throws Exception {
- DefaultScpClient.main(args);
- }
-}