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 2019/11/17 17:36:02 UTC
[mina-sshd] 06/06: [SSHD-955] Provide SSH command line option to
control user authentication mechanisms in client/server
This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
commit b43e9df4ed059b2ebd1c80e8f13321fce5720994
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Sat Nov 16 11:47:53 2019 +0200
[SSHD-955] Provide SSH command line option to control user authentication mechanisms in client/server
---
.../main/java/org/apache/sshd/cli/CliSupport.java | 31 +++++-
.../sshd/cli/client/SshClientCliSupport.java | 110 +++++++++++++--------
.../org/apache/sshd/cli/client/SshClientMain.java | 12 ++-
.../org/apache/sshd/cli/server/SshServerMain.java | 8 +-
.../sshd/common/auth/UserAuthFactoriesManager.java | 68 +++++++++++++
.../common/config/ConfigFileReaderSupport.java | 29 +++++-
.../sshd/client/ClientAuthenticationManager.java | 40 ++------
.../sshd/client/session/ClientUserAuthService.java | 6 +-
.../sshd/server/ServerAuthenticationManager.java | 43 +++-----
9 files changed, 229 insertions(+), 118 deletions(-)
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java b/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
index 3b6e417..f3920a8 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/CliSupport.java
@@ -30,6 +30,9 @@ import java.util.logging.Level;
import org.apache.sshd.common.AttributeRepository;
import org.apache.sshd.common.PropertyResolver;
import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.auth.UserAuthFactoriesManager;
+import org.apache.sshd.common.auth.UserAuthInstance;
+import org.apache.sshd.common.auth.UserAuthMethodFactory;
import org.apache.sshd.common.config.ConfigFileReaderSupport;
import org.apache.sshd.common.config.LogLevelValue;
import org.apache.sshd.common.helpers.AbstractFactoryManager;
@@ -40,6 +43,7 @@ import org.apache.sshd.common.io.IoServiceEventListener;
import org.apache.sshd.common.io.IoServiceFactoryFactory;
import org.apache.sshd.common.kex.KexProposalOption;
import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.session.SessionContext;
import org.apache.sshd.common.session.SessionListener;
import org.apache.sshd.common.util.GenericUtils;
@@ -69,6 +73,18 @@ public abstract class CliSupport {
return true;
}
+ public static <S extends SessionContext,
+ M extends UserAuthInstance<S>, F extends UserAuthMethodFactory<S, M>,
+ I extends UserAuthFactoriesManager<S, M, F>>
+ void setupUserAuthFactories(
+ I manager, PropertyResolver options) {
+ String methods = options.getString(ConfigFileReaderSupport.PREFERRED_AUTHS_CONFIG_PROP);
+ if (GenericUtils.isNotEmpty(methods)) {
+ manager.setUserAuthFactoriesNameList(methods);
+ return;
+ }
+ }
+
/**
* Scans the arguments for the "-io" command line option and sets the I/O
* service accordingly. If no specific option specified then {@link #DEFAULT_IO_SERVICE_FACTORY}
@@ -115,7 +131,8 @@ public abstract class CliSupport {
public static BuiltinIoServiceFactoryFactories resolveBuiltinIoServiceFactory(
PrintStream stderr, String argName, String provider) {
- BuiltinIoServiceFactoryFactories factory = BuiltinIoServiceFactoryFactories.fromFactoryName(provider);
+ BuiltinIoServiceFactoryFactories factory =
+ BuiltinIoServiceFactoryFactories.fromFactoryName(provider);
if (factory == null) {
System.err.println(argName + " - unknown provider (" + provider + ")"
+ " should be one of " + BuiltinIoServiceFactoryFactories.VALUES);
@@ -170,7 +187,8 @@ public abstract class CliSupport {
@Override
public void abortEstablishedConnection(
- IoConnector connector, SocketAddress local, AttributeRepository context, SocketAddress remote, Throwable reason)
+ IoConnector connector, SocketAddress local, AttributeRepository context,
+ SocketAddress remote, Throwable reason)
throws IOException {
out.append("Abort established connection ").append(Objects.toString(connector))
.append(" - local=").append(Objects.toString(local))
@@ -182,8 +200,10 @@ public abstract class CliSupport {
}
@Override
- public void connectionAccepted(IoAcceptor acceptor, SocketAddress local, SocketAddress remote, SocketAddress service)
- throws IOException {
+ public void connectionAccepted(
+ IoAcceptor acceptor, SocketAddress local,
+ SocketAddress remote, SocketAddress service)
+ throws IOException {
out.append("Connection accepted via ").append(Objects.toString(acceptor))
.append(" - local=").append(Objects.toString(local))
.append(", remote=").append(Objects.toString(remote))
@@ -193,7 +213,8 @@ public abstract class CliSupport {
@Override
public void abortAcceptedConnection(
- IoAcceptor acceptor, SocketAddress local, SocketAddress remote, SocketAddress service, Throwable reason)
+ IoAcceptor acceptor, SocketAddress local, SocketAddress remote,
+ SocketAddress service, Throwable reason)
throws IOException {
out.append("Abort accepted connection ").append(Objects.toString(acceptor))
.append(" - local=").append(Objects.toString(local))
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
index 0116ea8..3b7c0e4 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientCliSupport.java
@@ -116,7 +116,8 @@ public abstract class SshClientCliSupport extends CliSupport {
// NOTE: ClientSession#getFactoryManager is the SshClient
public static ClientSession setupClientSession(
- String portOption, BufferedReader stdin, Level level, PrintStream stdout, PrintStream stderr, String... args)
+ String portOption, BufferedReader stdin, Level level,
+ PrintStream stdout, PrintStream stderr, String... args)
throws Exception {
int port = -1;
String host = null;
@@ -178,7 +179,9 @@ public abstract class SshClientCliSupport extends CliSupport {
compressions = setupCompressions(argName,
GenericUtils.join(
Arrays.asList(
- BuiltinCompressions.Constants.ZLIB, BuiltinCompressions.Constants.DELAYED_ZLIB), ','),
+ BuiltinCompressions.Constants.ZLIB,
+ BuiltinCompressions.Constants.DELAYED_ZLIB),
+ ','),
compressions, stderr);
if (GenericUtils.isEmpty(compressions)) {
error = true;
@@ -239,7 +242,8 @@ public abstract class SshClientCliSupport extends CliSupport {
return null;
}
- PropertyResolver resolver = PropertyResolverUtils.toPropertyResolver(options);
+ PropertyResolver resolver =
+ PropertyResolverUtils.toPropertyResolver(options);
SshClient client = setupClient(
resolver, ciphers, macs, compressions, identities,
stdin, stdout, stderr, level, args);
@@ -259,7 +263,9 @@ public abstract class SshClientCliSupport extends CliSupport {
}
// TODO use a configurable wait time
- ClientSession session = client.connect(login, host, port).verify().getSession();
+ ClientSession session = client.connect(login, host, port)
+ .verify()
+ .getSession();
try {
if (GenericUtils.length(password) > 0) {
session.addPasswordIdentity(password);
@@ -288,7 +294,8 @@ public abstract class SshClientCliSupport extends CliSupport {
}
public static Map<String, ?> resolveClientEnvironment(PropertyResolver resolver) {
- return resolveClientEnvironment((resolver == null) ? Collections.emptyMap() : resolver.getProperties());
+ return resolveClientEnvironment(
+ (resolver == null) ? Collections.emptyMap() : resolver.getProperties());
}
public static Map<String, ?> resolveClientEnvironment(Map<String, ?> options) {
@@ -325,12 +332,15 @@ public abstract class SshClientCliSupport extends CliSupport {
public static PtyChannelConfiguration resolveClientPtyOptions(PropertyResolver resolver)
throws IOException, InterruptedException {
- return resolveClientPtyOptions((resolver == null) ? Collections.emptyMap() : resolver.getProperties());
+ return resolveClientPtyOptions(
+ (resolver == null) ? Collections.emptyMap() : resolver.getProperties());
}
public static PtyChannelConfiguration resolveClientPtyOptions(Map<String, ?> options)
throws IOException, InterruptedException {
- Object v = GenericUtils.isEmpty(options) ? null : options.get(SshClientConfigFileReader.REQUEST_TTY_OPTION);
+ Object v = GenericUtils.isEmpty(options)
+ ? null
+ : options.get(SshClientConfigFileReader.REQUEST_TTY_OPTION);
String s = Objects.toString(v, "auto");
boolean autoDetect = "auto".equalsIgnoreCase(s);
Boolean ptyEnabled = autoDetect ? Boolean.TRUE : PropertyResolverUtils.parseBoolean(s);
@@ -365,7 +375,8 @@ public abstract class SshClientCliSupport extends CliSupport {
for (String kve : kvp) {
int pos = kve.indexOf('=');
String key = (pos >= 0) ? kve.substring(0, pos) : kve;
- PtyMode mode = ValidateUtils.checkNotNull(PtyMode.fromName(key), "Unknown PTY mode: %s", key);
+ PtyMode mode = ValidateUtils.checkNotNull(
+ PtyMode.fromName(key), "Unknown PTY mode: %s", key);
s = (pos >= 0) ? kve.substring(pos + 1) : "";
Integer value = GenericUtils.isEmpty(s) ? Integer.valueOf(1) : Integer.valueOf(s);
Integer prev = ptyModes.put(mode, value);
@@ -378,8 +389,10 @@ public abstract class SshClientCliSupport extends CliSupport {
}
public static SshClient setupDefaultClient(
- PropertyResolver resolver, Level level, PrintStream stdout, PrintStream stderr, String... args) {
- SshClient client = setupIoServiceFactory(SshClient.setUpDefaultClient(), resolver, level, stdout, stderr, args);
+ PropertyResolver resolver, Level level,
+ PrintStream stdout, PrintStream stderr, String... args) {
+ SshClient client = setupIoServiceFactory(
+ SshClient.setUpDefaultClient(), resolver, level, stdout, stderr, args);
SshClientConfigFileReader.setupClientHeartbeat(client, resolver);
return client;
}
@@ -441,6 +454,7 @@ public abstract class SshClientCliSupport extends CliSupport {
}
setupServerKeyVerifier(client, resolver, stdin, stdout, stderr);
+ setupUserAuthFactories(client, resolver);
setupSessionUserInteraction(client, stdin, stdout, stderr);
setupSessionExtensions(client, resolver, stdin, stdout, stderr);
@@ -536,10 +550,12 @@ public abstract class SshClientCliSupport extends CliSupport {
}
public static void setupSessionExtensions(
- KexFactoryManager manager, PropertyResolver resolver, BufferedReader stdin, PrintStream stdout, PrintStream stderr)
+ KexFactoryManager manager, PropertyResolver resolver,
+ BufferedReader stdin, PrintStream stdout, PrintStream stderr)
throws Exception {
Map<String, ?> options = resolver.getProperties();
- String kexExtension = Objects.toString(options.remove(KexExtensionHandler.class.getSimpleName()), null);
+ String kexExtension = Objects.toString(
+ options.remove(KexExtensionHandler.class.getSimpleName()), null);
if (GenericUtils.isEmpty(kexExtension)) {
return;
}
@@ -551,7 +567,8 @@ public abstract class SshClientCliSupport extends CliSupport {
ClassLoader cl = ThreadUtils.resolveDefaultClassLoader(KexExtensionHandler.class);
try {
Class<?> clazz = cl.loadClass(kexExtension);
- KexExtensionHandler handler = KexExtensionHandler.class.cast(clazz.newInstance());
+ KexExtensionHandler handler =
+ KexExtensionHandler.class.cast(clazz.newInstance());
manager.setKexExtensionHandler(handler);
} catch (Exception e) {
stderr.append("ERROR: Failed (").append(e.getClass().getSimpleName()).append(')')
@@ -576,43 +593,49 @@ public abstract class SshClientCliSupport extends CliSupport {
Map<String, ?> options = resolver.getProperties();
String strictValue =
- Objects.toString(options.remove(KnownHostsServerKeyVerifier.STRICT_CHECKING_OPTION), "true");
+ Objects.toString(
+ options.remove(KnownHostsServerKeyVerifier.STRICT_CHECKING_OPTION), "true");
if (!ConfigFileReaderSupport.parseBooleanValue(strictValue)) {
return current;
}
- String filePath = Objects.toString(options.remove(KnownHostsServerKeyVerifier.KNOWN_HOSTS_FILE_OPTION), null);
+ 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("WARNING: Mismatched keys presented by ").append(Objects.toString(remoteAddress))
- .append(" for entry=").println(entry);
- stderr.append(" ").append("Expected=").append(KeyUtils.getKeyType(expected))
- .append('-').println(KeyUtils.getFingerPrint(expected));
- stderr.append(" ").append("Actual=").append(KeyUtils.getKeyType(actual))
- .append('-').println(KeyUtils.getFingerPrint(actual));
- stderr.flush(); // just making sure
+ ((KnownHostsServerKeyVerifier) current).setModifiedServerKeyAcceptor(
+ (clientSession, remoteAddress, entry, expected, actual) -> {
+ stderr.append("WARNING: Mismatched keys presented by ").append(Objects.toString(remoteAddress))
+ .append(" for entry=").println(entry);
+ stderr.append(" ").append("Expected=").append(KeyUtils.getKeyType(expected))
+ .append('-').println(KeyUtils.getFingerPrint(expected));
+ stderr.append(" ").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
+ 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');
- });
+ String ans = GenericUtils.trimToEmpty(stdin.readLine());
+ return (GenericUtils.length(ans) > 0)
+ && (Character.toLowerCase(ans.charAt(0)) == 'y');
+ });
manager.setServerKeyVerifier(current);
return current;
}
- public static OutputStream resolveLoggingTargetStream(PrintStream stdout, PrintStream stderr, String... args) {
+ 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) {
+ 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)) {
@@ -640,7 +663,8 @@ public abstract class SshClientCliSupport extends CliSupport {
}
public static List<NamedFactory<Compression>> setupCompressions(PropertyResolver options, PrintStream stderr) {
- String argVal = PropertyResolverUtils.getString(options, ConfigFileReaderSupport.COMPRESSION_PROP);
+ String argVal = PropertyResolverUtils.getString(
+ options, ConfigFileReaderSupport.COMPRESSION_PROP);
if (GenericUtils.isEmpty(argVal)) {
return Collections.emptyList();
}
@@ -661,7 +685,8 @@ public abstract class SshClientCliSupport extends CliSupport {
return null;
}
- BuiltinCompressions.ParseResult result = BuiltinCompressions.parseCompressionsList(argVal);
+ BuiltinCompressions.ParseResult result =
+ BuiltinCompressions.parseCompressionsList(argVal);
Collection<? extends NamedFactory<Compression>> available = result.getParsedFactories();
if (GenericUtils.isEmpty(available)) {
showError(stderr, "No known compressions in " + argVal);
@@ -670,14 +695,16 @@ public abstract class SshClientCliSupport extends CliSupport {
Collection<String> unsupported = result.getUnsupportedFactories();
if (GenericUtils.size(unsupported) > 0) {
- stderr.append("WARNING: Ignored unsupported compressions: ").println(GenericUtils.join(unsupported, ','));
+ stderr.append("WARNING: 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, ConfigFileReaderSupport.MACS_CONFIG_PROP);
+ String argVal = PropertyResolverUtils.getString(
+ options, ConfigFileReaderSupport.MACS_CONFIG_PROP);
return GenericUtils.isEmpty(argVal)
? Collections.emptyList()
: setupMacs(ConfigFileReaderSupport.MACS_CONFIG_PROP, argVal, null, stderr);
@@ -699,21 +726,24 @@ public abstract class SshClientCliSupport extends CliSupport {
Collection<String> unsupported = result.getUnsupportedFactories();
if (GenericUtils.size(unsupported) > 0) {
- stderr.append("WARNING: Ignored unsupported MACs: ").println(GenericUtils.join(unsupported, ','));
+ stderr.append("WARNING: 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, ConfigFileReaderSupport.CIPHERS_CONFIG_PROP);
+ String argVal = PropertyResolverUtils.getString(
+ options, ConfigFileReaderSupport.CIPHERS_CONFIG_PROP);
return GenericUtils.isEmpty(argVal)
? Collections.emptyList()
: setupCiphers(ConfigFileReaderSupport.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) {
+ 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;
@@ -728,13 +758,15 @@ public abstract class SshClientCliSupport extends CliSupport {
Collection<String> unsupported = result.getUnsupportedFactories();
if (GenericUtils.size(unsupported) > 0) {
- stderr.append("WARNING: Ignored unsupported ciphers: ").println(GenericUtils.join(unsupported, ','));
+ stderr.append("WARNING: Ignored unsupported ciphers: ")
+ .println(GenericUtils.join(unsupported, ','));
}
return new ArrayList<>(available);
}
- public static Handler setupLogging(Level level, PrintStream stdout, PrintStream stderr, OutputStream outputStream) {
+ public static Handler setupLogging(
+ Level level, PrintStream stdout, PrintStream stderr, OutputStream outputStream) {
Handler fh = new ConsoleHandler() {
{
setOutputStream(outputStream); // override the default (stderr)
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientMain.java
index 8a3c3d2..e62b071 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/client/SshClientMain.java
@@ -121,11 +121,13 @@ public class SshClientMain extends SshClientCliSupport {
ClientSession session = null;
try (BufferedReader stdin = new BufferedReader(
- new InputStreamReader(new NoCloseInputStream(System.in), Charset.defaultCharset()))) {
+ new InputStreamReader(
+ new NoCloseInputStream(System.in), Charset.defaultCharset()))) {
if (!error) {
setupLogging(level, stdout, stderr, logStream);
- session = setupClientSession(SSH_CLIENT_PORT_OPTION, stdin, level, stdout, stderr, args);
+ session = setupClientSession(
+ SSH_CLIENT_PORT_OPTION, stdin, level, stdout, stderr, args);
if (session == null) {
error = true;
}
@@ -158,7 +160,8 @@ public class SshClientMain extends SshClientCliSupport {
try {
if (socksPort >= 0) {
- session.startDynamicPortForwarding(new SshdSocketAddress(SshdSocketAddress.LOCALHOST_NAME, socksPort));
+ session.startDynamicPortForwarding(
+ new SshdSocketAddress(SshdSocketAddress.LOCALHOST_NAME, socksPort));
Thread.sleep(Long.MAX_VALUE);
} else {
Map<String, ?> env = resolveClientEnvironment(client);
@@ -169,7 +172,8 @@ public class SshClientMain extends SshClientCliSupport {
((ChannelShell) channel).setAgentForwarding(agentForward);
channel.setIn(new NoCloseInputStream(System.in));
} else {
- channel = session.createExecChannel(String.join(" ", command).trim(), ptyConfig, env);
+ channel = session.createExecChannel(
+ String.join(" ", command).trim(), ptyConfig, env);
}
try (OutputStream channelOut = new NoCloseOutputStream(System.out);
diff --git a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
index 99c4901..321ae1e 100644
--- a/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
+++ b/sshd-cli/src/main/java/org/apache/sshd/cli/server/SshServerMain.java
@@ -152,7 +152,9 @@ public class SshServerMain extends SshServerCliSupport {
Level level = resolveLoggingVerbosity(resolver, args);
SshServer sshd = error
? null
- : setupIoServiceFactory(SshServer.setUpDefaultServer(), resolver, level, System.out, System.err, args);
+ : setupIoServiceFactory(
+ SshServer.setUpDefaultServer(), resolver,
+ level, System.out, System.err, args);
if (sshd == null) {
error = true;
}
@@ -166,7 +168,8 @@ public class SshServerMain extends SshServerCliSupport {
props.putAll(options);
SshServerConfigFileReader.setupServerHeartbeat(sshd, resolver);
- KeyPairProvider hostKeyProvider = resolveServerKeys(System.err, hostKeyType, hostKeySize, keyFiles);
+ KeyPairProvider hostKeyProvider =
+ resolveServerKeys(System.err, hostKeyType, hostKeySize, keyFiles);
sshd.setKeyPairProvider(hostKeyProvider);
// Should come AFTER key pair provider setup so auto-welcome can be generated if needed
setupServerBanner(sshd, resolver);
@@ -185,6 +188,7 @@ public class SshServerMain extends SshServerCliSupport {
sshd.setPasswordAuthenticator((username, password, session) -> Objects.equals(username, password));
sshd.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
+ setupUserAuthFactories(sshd, resolver);
setupServerForwarding(sshd, level, System.out, System.err, resolver);
sshd.setCommandFactory(new ScpCommandFactory.Builder()
.withDelegate(ProcessShellCommandFactory.INSTANCE)
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/auth/UserAuthFactoriesManager.java b/sshd-common/src/main/java/org/apache/sshd/common/auth/UserAuthFactoriesManager.java
new file mode 100644
index 0000000..c64c1d8
--- /dev/null
+++ b/sshd-common/src/main/java/org/apache/sshd/common/auth/UserAuthFactoriesManager.java
@@ -0,0 +1,68 @@
+/*
+ * 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.common.auth;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.session.SessionContext;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * @param <S> Type of session being managed
+ * @param <M> Type of {@code UserAuth} being used
+ * @param <F> Type of user authentication mechanism factory
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public interface UserAuthFactoriesManager<S extends SessionContext,
+ M extends UserAuthInstance<S>, F extends UserAuthMethodFactory<S, M>> {
+ /**
+ * Retrieve the list of named factories for <code>UserAuth</code> objects.
+ *
+ * @return a list of named <code>UserAuth</code> factories, never {@code null}/empty
+ */
+ List<F> getUserAuthFactories();
+
+ default String getUserAuthFactoriesNameList() {
+ return NamedResource.getNames(getUserAuthFactories());
+ }
+
+ default List<String> getUserAuthFactoriesNames() {
+ return NamedResource.getNameList(getUserAuthFactories());
+ }
+
+ void setUserAuthFactories(List<F> userAuthFactories);
+
+ default void setUserAuthFactoriesNameList(String names) {
+ setUserAuthFactoriesNames(GenericUtils.split(names, ','));
+ }
+
+ default void setUserAuthFactoriesNames(String... names) {
+ setUserAuthFactoriesNames(
+ GenericUtils.isEmpty((Object[]) names)
+ ? Collections.emptyList()
+ : Arrays.asList(names));
+ }
+
+ void setUserAuthFactoriesNames(Collection<String> names);
+}
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/config/ConfigFileReaderSupport.java b/sshd-common/src/main/java/org/apache/sshd/common/config/ConfigFileReaderSupport.java
index 05a107b..ec6c114 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/config/ConfigFileReaderSupport.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/config/ConfigFileReaderSupport.java
@@ -30,10 +30,14 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.auth.UserAuthMethodFactory;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.io.NoCloseInputStream;
@@ -52,9 +56,29 @@ public final class ConfigFileReaderSupport {
public static final String DEFAULT_COMPRESSION = CompressionConfigValue.NO.getName();
public static final String MAX_SESSIONS_CONFIG_PROP = "MaxSessions";
public static final int DEFAULT_MAX_SESSIONS = 10;
+
+ public static final String PUBKEY_AUTH_CONFIG_PROP = "PubkeyAuthentication";
+ public static final String DEFAULT_PUBKEY_AUTH = "yes";
+ public static final boolean DEFAULT_PUBKEY_AUTH_VALUE = parseBooleanValue(DEFAULT_PUBKEY_AUTH);
+
public static final String PASSWORD_AUTH_CONFIG_PROP = "PasswordAuthentication";
- public static final String DEFAULT_PASSWORD_AUTH = "no";
+ public static final String DEFAULT_PASSWORD_AUTH = "yes";
public static final boolean DEFAULT_PASSWORD_AUTH_VALUE = parseBooleanValue(DEFAULT_PASSWORD_AUTH);
+
+ public static final String KBD_INTERACTIVE_CONFIG_PROP = "KbdInteractiveAuthentication";
+ public static final String DEFAULT_KBD_INTERACTIVE_AUTH = "yes";
+ public static final boolean DEFAULT_KBD_INTERACTIVE_AUTH_VALUE = parseBooleanValue(DEFAULT_KBD_INTERACTIVE_AUTH);
+
+ public static final String PREFERRED_AUTHS_CONFIG_PROP = "PreferredAuthentications";
+ public static final List<String> DEFAULT_PREFERRED_AUTHS =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ UserAuthMethodFactory.PUBLIC_KEY,
+ UserAuthMethodFactory.KB_INTERACTIVE,
+ UserAuthMethodFactory.PASSWORD));
+ public static final String DEFAULT_PREFERRED_AUTHS_VALUE =
+ GenericUtils.join(DEFAULT_PREFERRED_AUTHS, ',');
+
public static final String LISTEN_ADDRESS_CONFIG_PROP = "ListenAddress";
public static final String DEFAULT_BIND_ADDRESS = SshdSocketAddress.IPV4_ANYADDR;
public static final String PORT_CONFIG_PROP = "Port";
@@ -63,9 +87,6 @@ public final class ConfigFileReaderSupport {
public static final String USE_DNS_CONFIG_PROP = "UseDNS";
// NOTE: the usual default is TRUE
public static final boolean DEFAULT_USE_DNS = true;
- public static final String PUBKEY_AUTH_CONFIG_PROP = "PubkeyAuthentication";
- public static final String DEFAULT_PUBKEY_AUTH = "yes";
- public static final boolean DEFAULT_PUBKEY_AUTH_VALUE = parseBooleanValue(DEFAULT_PUBKEY_AUTH);
public static final String AUTH_KEYS_FILE_CONFIG_PROP = "AuthorizedKeysFile";
public static final String MAX_AUTH_TRIES_CONFIG_PROP = "MaxAuthTries";
public static final int DEFAULT_MAX_AUTH_TRIES = 6;
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
index b1fedc0..102d97c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientAuthenticationManager.java
@@ -20,18 +20,18 @@
package org.apache.sshd.client;
import java.security.KeyPair;
-import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
import org.apache.sshd.client.auth.AuthenticationIdentitiesProvider;
import org.apache.sshd.client.auth.BuiltinUserAuthFactories;
+import org.apache.sshd.client.auth.UserAuth;
import org.apache.sshd.client.auth.UserAuthFactory;
import org.apache.sshd.client.auth.keyboard.UserInteraction;
import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
-import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.auth.UserAuthFactoriesManager;
import org.apache.sshd.common.keyprovider.KeyIdentityProviderHolder;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
@@ -40,7 +40,9 @@ import org.apache.sshd.common.util.ValidateUtils;
* Holds information required for the client to perform authentication with the server
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface ClientAuthenticationManager extends KeyIdentityProviderHolder {
+public interface ClientAuthenticationManager
+ extends UserAuthFactoriesManager<ClientSession, UserAuth, UserAuthFactory>,
+ KeyIdentityProviderHolder {
/**
* Ordered comma separated list of authentications methods.
@@ -128,40 +130,16 @@ public interface ClientAuthenticationManager extends KeyIdentityProviderHolder {
void setUserInteraction(UserInteraction userInteraction);
- /**
- * @return a {@link List} of {@link UserAuthFactory}-ies - never
- * {@code null}/empty
- */
- List<UserAuthFactory> getUserAuthFactories();
-
- default String getUserAuthFactoriesNameList() {
- return NamedResource.getNames(getUserAuthFactories());
- }
-
- default List<String> getUserAuthFactoriesNames() {
- return NamedResource.getNameList(getUserAuthFactories());
- }
-
- void setUserAuthFactories(List<UserAuthFactory> userAuthFactories);
-
- default void setUserAuthFactoriesNameList(String names) {
- setUserAuthFactoriesNames(GenericUtils.split(names, ','));
- }
-
- default void setUserAuthFactoriesNames(String... names) {
- setUserAuthFactoriesNames(
- GenericUtils.isEmpty((Object[]) names) ? Collections.emptyList() : Arrays.asList(names));
- }
-
+ @Override
default void setUserAuthFactoriesNames(Collection<String> names) {
BuiltinUserAuthFactories.ParseResult result =
BuiltinUserAuthFactories.parseFactoriesList(names);
List<UserAuthFactory> factories =
ValidateUtils.checkNotNullAndNotEmpty(
- result.getParsedFactories(), "No supported cipher factories: %s", names);
+ result.getParsedFactories(), "No supported user authentication factories: %s", names);
Collection<String> unsupported = result.getUnsupportedFactories();
ValidateUtils.checkTrue(
- GenericUtils.isEmpty(unsupported), "Unsupported cipher factories found: %s", unsupported);
+ GenericUtils.isEmpty(unsupported), "Unsupported user authentication factories found: %s", unsupported);
setUserAuthFactories(factories);
}
}
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
index 5c00c6a..86d2a4e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
@@ -307,7 +307,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
currentMethod++;
} else {
if (debugEnabled) {
- log.debug("tryNext({}) successfully processed initial buffer by method={}", session, userAuth.getName());
+ log.debug("tryNext({}) successfully processed initial buffer by method={}",
+ session, userAuth.getName());
}
return;
}
@@ -337,7 +338,8 @@ public class ClientUserAuthService extends AbstractCloseable implements Service,
userAuth = UserAuthMethodFactory.createUserAuth(session, authFactories, method);
if (userAuth == null) {
- throw new UnsupportedOperationException("Failed to find a user-auth factory for method=" + method);
+ throw new UnsupportedOperationException(
+ "Failed to find a user-auth factory for method=" + method);
}
if (debugEnabled) {
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
index ad4406e..72877e6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
@@ -20,13 +20,12 @@
package org.apache.sshd.server;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.auth.UserAuthFactoriesManager;
import org.apache.sshd.common.keyprovider.KeyPairProviderHolder;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
@@ -43,12 +42,15 @@ import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.auth.password.UserAuthPasswordFactory;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
import org.apache.sshd.server.auth.pubkey.UserAuthPublicKeyFactory;
+import org.apache.sshd.server.session.ServerSession;
/**
* Holds providers and helpers related to the server side authentication process
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface ServerAuthenticationManager extends KeyPairProviderHolder {
+public interface ServerAuthenticationManager
+ extends UserAuthFactoriesManager<ServerSession, UserAuth, UserAuthFactory>,
+ KeyPairProviderHolder {
/**
* Key used to retrieve the value in the configuration properties map
* of the maximum number of failed authentication requests before the
@@ -153,37 +155,16 @@ public interface ServerAuthenticationManager extends KeyPairProviderHolder {
UserAuthKeyboardInteractiveFactory DEFAULT_USER_AUTH_KB_INTERACTIVE_FACTORY = UserAuthKeyboardInteractiveFactory.INSTANCE;
- /**
- * Retrieve the list of named factories for <code>UserAuth</code> objects.
- *
- * @return a list of named <code>UserAuth</code> factories, never {@code null}/empty
- */
- List<UserAuthFactory> getUserAuthFactories();
-
- default String getUserAuthFactoriesNameList() {
- return NamedResource.getNames(getUserAuthFactories());
- }
-
- default List<String> getUserAuthFactoriesNames() {
- return NamedResource.getNameList(getUserAuthFactories());
- }
-
- void setUserAuthFactories(List<UserAuthFactory> userAuthFactories);
-
- default void setUserAuthFactoriesNameList(String names) {
- setUserAuthFactoriesNames(GenericUtils.split(names, ','));
- }
-
- default void setUserAuthFactoriesNames(String... names) {
- setUserAuthFactoriesNames(GenericUtils.isEmpty((Object[]) names) ? Collections.emptyList() : Arrays.asList(names));
- }
-
+ @Override
default void setUserAuthFactoriesNames(Collection<String> names) {
- BuiltinUserAuthFactories.ParseResult result = BuiltinUserAuthFactories.parseFactoriesList(names);
+ BuiltinUserAuthFactories.ParseResult result =
+ BuiltinUserAuthFactories.parseFactoriesList(names);
List<UserAuthFactory> factories =
- ValidateUtils.checkNotNullAndNotEmpty(result.getParsedFactories(), "No supported cipher factories: %s", names);
+ ValidateUtils.checkNotNullAndNotEmpty(
+ result.getParsedFactories(), "No supported cipher factories: %s", names);
Collection<String> unsupported = result.getUnsupportedFactories();
- ValidateUtils.checkTrue(GenericUtils.isEmpty(unsupported), "Unsupported cipher factories found: %s", unsupported);
+ ValidateUtils.checkTrue(
+ GenericUtils.isEmpty(unsupported), "Unsupported cipher factories found: %s", unsupported);
setUserAuthFactories(factories);
}