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 &quot;-io&quot; 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);
     }