[SSHD-771] Added capability to configure server-side MAC(s) via standard 
command line option


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/a65c2f27
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/a65c2f27
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/a65c2f27

Branch: refs/heads/master
Commit: a65c2f272e1192a38fd720b5acc6a59147b3f0a2
Parents: e0a6b8d
Author: Goldstein Lyor <l...@c-b4.com>
Authored: Tue Sep 12 09:21:26 2017 +0300
Committer: Goldstein Lyor <l...@c-b4.com>
Committed: Tue Sep 12 10:57:53 2017 +0300

----------------------------------------------------------------------
 .../java/org/apache/sshd/client/SshClient.java  |  20 +-
 .../config/SshClientConfigFileReader.java       |  40 ++++
 .../sshd/common/PropertyResolverUtils.java      |  27 ++-
 .../sshd/common/config/SshConfigFileReader.java | 189 +++----------------
 .../java/org/apache/sshd/server/SshServer.java  |  20 +-
 .../config/SshServerConfigFileReader.java       |  21 ++-
 .../common/config/SshConfigFileReaderTest.java  |  13 +-
 7 files changed, 141 insertions(+), 189 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a65c2f27/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 876b2ca..ce4b192 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
@@ -44,10 +44,10 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.EnumSet;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.TreeMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.logging.ConsoleHandler;
 import java.util.logging.Formatter;
@@ -91,6 +91,7 @@ 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;
@@ -800,7 +801,7 @@ public class SshClient extends AbstractFactoryManager 
implements ClientFactoryMa
         String password = null;
         boolean error = false;
         List<Path> identities = new ArrayList<>();
-        Map<String, String> options = new LinkedHashMap<>();
+        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;
@@ -954,28 +955,29 @@ public class SshClient extends AbstractFactoryManager 
implements ClientFactoryMa
 
     // returns null if error encountered
     public static SshClient setupClient(
-            Map<String, ?> options,
+            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(options, stderr);
+            ciphers = setupCiphers(resolver, stderr);
             if (ciphers == null) {
                 return null;
             }
         }
 
         if (GenericUtils.isEmpty(macs)) {
-            macs = setupMacs(options, stderr);
+            macs = setupMacs(resolver, stderr);
             if (macs == null) {
                 return null;
             }
         }
 
         if (GenericUtils.isEmpty(compressions)) {
-            compressions = setupCompressions(options, stderr);
+            compressions = setupCompressions(resolver, stderr);
             if (compressions == null) {
                 return null;
             }
@@ -1177,7 +1179,7 @@ public class SshClient extends AbstractFactoryManager 
implements ClientFactoryMa
         return stderr;
     }
 
-    public static List<NamedFactory<Compression>> 
setupCompressions(Map<String, ?> options, PrintStream 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();
@@ -1214,7 +1216,7 @@ public class SshClient extends AbstractFactoryManager 
implements ClientFactoryMa
         return new ArrayList<>(available);
     }
 
-    public static List<NamedFactory<Mac>> setupMacs(Map<String, ?> options, 
PrintStream stderr) {
+    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()
@@ -1242,7 +1244,7 @@ public class SshClient extends AbstractFactoryManager 
implements ClientFactoryMa
         return new ArrayList<>(available);
     }
 
-    public static List<NamedFactory<Cipher>> setupCiphers(Map<String, ?> 
options, PrintStream stderr) {
+    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()

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a65c2f27/sshd-core/src/main/java/org/apache/sshd/client/config/SshClientConfigFileReader.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/client/config/SshClientConfigFileReader.java
 
b/sshd-core/src/main/java/org/apache/sshd/client/config/SshClientConfigFileReader.java
new file mode 100644
index 0000000..ccd8f26
--- /dev/null
+++ 
b/sshd-core/src/main/java/org/apache/sshd/client/config/SshClientConfigFileReader.java
@@ -0,0 +1,40 @@
+/*
+ * 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.config;
+
+import org.apache.sshd.client.ClientBuilder;
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.common.PropertyResolver;
+import org.apache.sshd.common.config.SshConfigFileReader;
+import org.apache.sshd.common.helpers.AbstractFactoryManager;
+
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+public final class SshClientConfigFileReader {
+    private SshClientConfigFileReader() {
+        throw new UnsupportedOperationException("No instance allowed");
+    }
+
+    public static <C extends SshClient> C configure(C client, PropertyResolver 
props, boolean lenient, boolean ignoreUnsupported) {
+        SshConfigFileReader.configure((AbstractFactoryManager) client, props, 
lenient, ignoreUnsupported);
+        SshConfigFileReader.configureKeyExchanges(client, props, lenient, 
ClientBuilder.DH2KEX, ignoreUnsupported);
+        return client;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a65c2f27/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java 
b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
index 584668e..78ebea6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
@@ -21,9 +21,12 @@ package org.apache.sshd.common;
 
 import java.nio.charset.Charset;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+import java.util.Properties;
+import java.util.TreeMap;
 
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
@@ -426,19 +429,37 @@ public final class PropertyResolverUtils {
         return null;
     }
 
+    public static PropertyResolver toPropertyResolver(Properties props) {
+        if (GenericUtils.isEmpty(props)) {
+            return PropertyResolver.EMPTY;
+        }
+
+        Map<String, Object> propsMap = new 
TreeMap<>(Comparator.naturalOrder());
+        Collection<String> names = props.stringPropertyNames();
+        for (String key : names) {
+            String value = props.getProperty(key);
+            if (value == null) {
+                continue;
+            }
+            propsMap.put(key, value);
+        }
+
+        return toPropertyResolver(propsMap);
+    }
+
     /**
      * Wraps a {@link Map} into a {@link PropertyResolver} so it can be used
      * with these utilities
      *
      * @param props The properties map - may be {@code null}/empty if no 
properties
-     *              are updated
+     * are updated
      * @return The resolver wrapper
      */
-    public static PropertyResolver toPropertyResolver(final Map<String, 
Object> props) {
+    public static PropertyResolver toPropertyResolver(Map<String, Object> 
props) {
         return toPropertyResolver(props, null);
     }
 
-    public static PropertyResolver toPropertyResolver(final Map<String, 
Object> props, final PropertyResolver parent) {
+    public static PropertyResolver toPropertyResolver(Map<String, Object> 
props, PropertyResolver parent) {
         return new PropertyResolver() {
             @Override
             public PropertyResolver getParentPropertyResolver() {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a65c2f27/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
index b6d87d4..4a93294 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
@@ -40,10 +40,9 @@ import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 
-import org.apache.sshd.client.ClientBuilder;
-import org.apache.sshd.client.SshClient;
 import org.apache.sshd.common.BuiltinFactory;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.PropertyResolver;
 import org.apache.sshd.common.cipher.BuiltinCiphers;
 import org.apache.sshd.common.cipher.Cipher;
 import org.apache.sshd.common.compression.BuiltinCompressions;
@@ -64,8 +63,6 @@ import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
 import org.apache.sshd.common.util.io.NoCloseReader;
 import org.apache.sshd.common.util.net.SshdSocketAddress;
-import org.apache.sshd.server.ServerBuilder;
-import org.apache.sshd.server.SshServer;
 
 /**
  * Reads and interprets some useful configurations from an OpenSSH
@@ -228,120 +225,6 @@ public final class SshConfigFileReader {
     }
 
     /**
-     * @param props        The {@link Properties} - ignored if {@code 
null}/empty
-     * @param name         The property name
-     * @param defaultValue The default value to return if the specified 
property
-     *                     does not exist in the properties map or is an empty 
string
-     * @return The resolved property
-     * @throws NumberFormatException if malformed value
-     */
-    public static long getLongProperty(Properties props, String name, long 
defaultValue) {
-        String value = (props == null) ? null : props.getProperty(name);
-        if (GenericUtils.isEmpty(value)) {
-            return defaultValue;
-        } else {
-            return Long.parseLong(value);
-        }
-    }
-
-    /**
-     * @param props The {@link Properties} - ignored if {@code null}/empty
-     * @param name  The property name
-     * @return The {@link Long} value or {@code null} if property not found or
-     * empty string
-     * @throws NumberFormatException if malformed value
-     */
-    public static Long getLong(Properties props, String name) {
-        String value = (props == null) ? null : props.getProperty(name);
-        if (GenericUtils.isEmpty(value)) {
-            return null;
-        } else {
-            return Long.valueOf(value);
-        }
-    }
-
-    /**
-     * @param props        The {@link Properties} - ignored if {@code 
null}/empty
-     * @param name         The property name
-     * @param defaultValue The default value to return if the specified 
property
-     *                     does not exist in the properties map or is an empty 
string
-     * @return The resolved property
-     * @throws NumberFormatException if malformed value
-     */
-    public static int getIntProperty(Properties props, String name, int 
defaultValue) {
-        String value = (props == null) ? null : props.getProperty(name);
-        if (GenericUtils.isEmpty(value)) {
-            return defaultValue;
-        } else {
-            return Integer.parseInt(value);
-        }
-    }
-
-    /**
-     * @param props The {@link Properties} - ignored if {@code null}/empty
-     * @param name  The property name
-     * @return The {@link Integer} value or {@code null} if property not found 
or
-     * empty string
-     * @throws NumberFormatException if malformed value
-     */
-    public static Integer getInteger(Properties props, String name) {
-        String value = (props == null) ? null : props.getProperty(name);
-        if (GenericUtils.isEmpty(value)) {
-            return null;
-        } else {
-            return Integer.valueOf(value);
-        }
-    }
-
-    /**
-     * @param props        The {@link Properties} - ignored if {@code 
null}/empty
-     * @param name         The property name
-     * @param defaultValue The default value to return if the specified 
property
-     *                     does not exist in the properties map or is an empty 
string
-     * @return The resolved property
-     * @throws NumberFormatException if malformed value
-     */
-    public static boolean getBooleanProperty(Properties props, String name, 
boolean defaultValue) {
-        String value = (props == null) ? null : props.getProperty(name);
-        if (GenericUtils.isEmpty(value)) {
-            return defaultValue;
-        } else {
-            return parseBooleanValue(value);
-        }
-    }
-
-    /**
-     * @param props The {@link Properties} - ignored if {@code null}/empty
-     * @param name  The property name
-     * @return The {@link Boolean} value or {@code null} if property not found 
or
-     * empty string
-     * @throws NumberFormatException if malformed value
-     */
-    public static Boolean getBoolean(Properties props, String name) {
-        String value = (props == null) ? null : props.getProperty(name);
-        if (GenericUtils.isEmpty(value)) {
-            return null;
-        } else {
-            return parseBooleanValue(value);
-        }
-    }
-
-    /**
-     * @param v            The value to parse - if {@code null}/empty then the 
default
-     *                     value is returned, otherwise {@link 
#parseBooleanValue(String)} is used
-     * @param defaultValue The default value to return if {@code null}/empty
-     *                     input string
-     * @return The result
-     */
-    public static boolean parseBooleanValue(String v, boolean defaultValue) {
-        if (GenericUtils.isEmpty(v)) {
-            return defaultValue;
-        } else {
-            return parseBooleanValue(v);
-        }
-    }
-
-    /**
      * @param v Checks if the value is &quot;yes&quot;, &quot;y&quot;
      *          or &quot;on&quot; or &quot;true&quot;.
      * @return The result - <B>Note:</B> {@code null}/empty values are
@@ -366,7 +249,7 @@ public final class SshConfigFileReader {
     }
 
     /**
-     * @param props The {@link Properties} - ignored if {@code null}/empty
+     * @param props The {@link PropertyResolver} - ignored if {@code 
null}/empty
      * @return A {@code ParseResult} of all the {@link NamedFactory}-ies
      * whose name appears in the string and represent a built-in cipher.
      * Any unknown name is <U>ignored</U>. The order of the returned result
@@ -376,12 +259,12 @@ public final class SshConfigFileReader {
      * @see #CIPHERS_CONFIG_PROP
      * @see BuiltinCiphers#parseCiphersList(String)
      */
-    public static BuiltinCiphers.ParseResult getCiphers(Properties props) {
-        return BuiltinCiphers.parseCiphersList((props == null) ? null : 
props.getProperty(CIPHERS_CONFIG_PROP));
+    public static BuiltinCiphers.ParseResult getCiphers(PropertyResolver 
props) {
+        return BuiltinCiphers.parseCiphersList((props == null) ? null : 
props.getString(CIPHERS_CONFIG_PROP));
     }
 
     /**
-     * @param props The {@link Properties} - ignored if {@code null}/empty
+     * @param props The {@link PropertyResolver} - ignored if {@code 
null}/empty
      * @return A {@code ParseResult} of all the {@link NamedFactory}-ies
      * whose name appears in the string and represent a built-in MAC. Any
      * unknown name is <U>ignored</U>. The order of the returned result
@@ -391,12 +274,12 @@ public final class SshConfigFileReader {
      * @see #MACS_CONFIG_PROP
      * @see BuiltinMacs#parseMacsList(String)
      */
-    public static BuiltinMacs.ParseResult getMacs(Properties props) {
-        return BuiltinMacs.parseMacsList((props == null) ? null : 
props.getProperty(MACS_CONFIG_PROP));
+    public static BuiltinMacs.ParseResult getMacs(PropertyResolver props) {
+        return BuiltinMacs.parseMacsList((props == null) ? null : 
props.getString(MACS_CONFIG_PROP));
     }
 
     /**
-     * @param props The {@link Properties} - ignored if {@code null}/empty
+     * @param props The {@link PropertyResolver} - ignored if {@code 
null}/empty
      * @return A {@code ParseResult} of all the {@link NamedFactory}
      * whose name appears in the string and represent a built-in signature. Any
      * unknown name is <U>ignored</U>. The order of the returned result is the
@@ -405,12 +288,12 @@ public final class SshConfigFileReader {
      * @see #HOST_KEY_ALGORITHMS_CONFIG_PROP
      * @see BuiltinSignatures#parseSignatureList(String)
      */
-    public static BuiltinSignatures.ParseResult getSignatures(Properties 
props) {
-        return BuiltinSignatures.parseSignatureList((props == null) ? null : 
props.getProperty(HOST_KEY_ALGORITHMS_CONFIG_PROP));
+    public static BuiltinSignatures.ParseResult getSignatures(PropertyResolver 
props) {
+        return BuiltinSignatures.parseSignatureList((props == null) ? null : 
props.getString(HOST_KEY_ALGORITHMS_CONFIG_PROP));
     }
 
     /**
-     * @param props The {@link Properties} - ignored if {@code null}/empty
+     * @param props The {@link PropertyResolver} - ignored if {@code 
null}/empty
      * @return A {@code ParseResult} of all the {@link DHFactory}-ies
      * whose name appears in the string and represent a built-in value. Any
      * unknown name is <U>ignored</U>. The order of the returned result is the
@@ -419,29 +302,17 @@ public final class SshConfigFileReader {
      * @see #KEX_ALGORITHMS_CONFIG_PROP
      * @see BuiltinDHFactories#parseDHFactoriesList(String)
      */
-    public static BuiltinDHFactories.ParseResult getKexFactories(Properties 
props) {
-        return BuiltinDHFactories.parseDHFactoriesList((props == null) ? null 
: props.getProperty(KEX_ALGORITHMS_CONFIG_PROP));
+    public static BuiltinDHFactories.ParseResult 
getKexFactories(PropertyResolver props) {
+        return BuiltinDHFactories.parseDHFactoriesList((props == null) ? null 
: props.getString(KEX_ALGORITHMS_CONFIG_PROP));
     }
 
     /**
-     * @param props The {@link Properties} - ignored if {@code null}/empty
+     * @param props The {@link PropertyResolver} - ignored if {@code 
null}/empty
      * @return The matching {@link NamedFactory} for the configured value.
      * {@code null} if no configuration or unknown name specified
      */
-    public static CompressionFactory getCompression(Properties props) {
-        return CompressionConfigValue.fromName((props == null) ? null : 
props.getProperty(COMPRESSION_PROP));
-    }
-
-    public static <S extends SshServer> S configure(S server, Properties 
props, boolean lenient, boolean ignoreUnsupported) {
-        configure((AbstractFactoryManager) server, props, lenient, 
ignoreUnsupported);
-        configureKeyExchanges(server, props, lenient, ServerBuilder.DH2KEX, 
ignoreUnsupported);
-        return server;
-    }
-
-    public static <C extends SshClient> C configure(C client, Properties 
props, boolean lenient, boolean ignoreUnsupported) {
-        configure((AbstractFactoryManager) client, props, lenient, 
ignoreUnsupported);
-        configureKeyExchanges(client, props, lenient, ClientBuilder.DH2KEX, 
ignoreUnsupported);
-        return client;
+    public static CompressionFactory getCompression(PropertyResolver props) {
+        return CompressionConfigValue.fromName((props == null) ? null : 
props.getString(COMPRESSION_PROP));
     }
 
     /**
@@ -456,7 +327,7 @@ public final class SshConfigFileReader {
      *
      * @param <M>               The generic factory manager
      * @param manager           The {@link AbstractFactoryManager} to configure
-     * @param props             The {@link Properties} to use for 
configuration - <B>Note:</B>
+     * @param props             The {@link PropertyResolver} to use for 
configuration - <B>Note:</B>
      *                          if any known configuration value has a default 
and does not appear in the
      *                          properties, the default is used
      * @param lenient           If {@code true} then any unknown configuration 
values are ignored.
@@ -466,7 +337,7 @@ public final class SshConfigFileReader {
      *                          or unsupported values there is an empty 
configuration exception is thrown
      * @return The configured manager
      */
-    public static <M extends AbstractFactoryManager> M configure(M manager, 
Properties props, boolean lenient, boolean ignoreUnsupported) {
+    public static <M extends AbstractFactoryManager> M configure(M manager, 
PropertyResolver props, boolean lenient, boolean ignoreUnsupported) {
         configureCiphers(manager, props, lenient, ignoreUnsupported);
         configureSignatures(manager, props, lenient, ignoreUnsupported);
         configureMacs(manager, props, lenient, ignoreUnsupported);
@@ -475,9 +346,9 @@ public final class SshConfigFileReader {
         return manager;
     }
 
-    public static <M extends AbstractFactoryManager> M configureCiphers(M 
manager, Properties props, boolean lenient, boolean ignoreUnsupported) {
+    public static <M extends AbstractFactoryManager> M configureCiphers(M 
manager, PropertyResolver props, boolean lenient, boolean ignoreUnsupported) {
         Objects.requireNonNull(props, "No properties to configure");
-        return configureCiphers(manager, 
props.getProperty(CIPHERS_CONFIG_PROP, DEFAULT_CIPHERS), lenient, 
ignoreUnsupported);
+        return configureCiphers(manager, 
props.getStringProperty(CIPHERS_CONFIG_PROP, DEFAULT_CIPHERS), lenient, 
ignoreUnsupported);
     }
 
     public static <M extends AbstractFactoryManager> M configureCiphers(M 
manager, String value, boolean lenient, boolean ignoreUnsupported) {
@@ -493,9 +364,9 @@ public final class SshConfigFileReader {
         return manager;
     }
 
-    public static <M extends AbstractFactoryManager> M configureSignatures(M 
manager, Properties props, boolean lenient, boolean ignoreUnsupported) {
+    public static <M extends AbstractFactoryManager> M configureSignatures(M 
manager, PropertyResolver props, boolean lenient, boolean ignoreUnsupported) {
         Objects.requireNonNull(props, "No properties to configure");
-        return configureSignatures(manager, 
props.getProperty(HOST_KEY_ALGORITHMS_CONFIG_PROP, 
DEFAULT_HOST_KEY_ALGORITHMS), lenient, ignoreUnsupported);
+        return configureSignatures(manager, 
props.getStringProperty(HOST_KEY_ALGORITHMS_CONFIG_PROP, 
DEFAULT_HOST_KEY_ALGORITHMS), lenient, ignoreUnsupported);
     }
 
     public static <M extends AbstractFactoryManager> M configureSignatures(M 
manager, String value, boolean lenient, boolean ignoreUnsupported) {
@@ -511,9 +382,9 @@ public final class SshConfigFileReader {
         return manager;
     }
 
-    public static <M extends AbstractFactoryManager> M configureMacs(M 
manager, Properties props, boolean lenient, boolean ignoreUnsupported) {
-        Objects.requireNonNull(props, "No properties to configure");
-        return configureMacs(manager, props.getProperty(MACS_CONFIG_PROP, 
DEFAULT_MACS), lenient, ignoreUnsupported);
+    public static <M extends AbstractFactoryManager> M configureMacs(M 
manager, PropertyResolver resolver, boolean lenient, boolean ignoreUnsupported) 
{
+        Objects.requireNonNull(resolver, "No properties to configure");
+        return configureMacs(manager, 
resolver.getStringProperty(MACS_CONFIG_PROP, DEFAULT_MACS), lenient, 
ignoreUnsupported);
     }
 
     public static <M extends AbstractFactoryManager> M configureMacs(M 
manager, String value, boolean lenient, boolean ignoreUnsupported) {
@@ -532,7 +403,7 @@ public final class SshConfigFileReader {
     /**
      * @param <M>               The generic factory manager
      * @param manager           The {@link AbstractFactoryManager} to set up 
(may not be {@code null})
-     * @param props             The (non-{@code null}) {@link Properties} 
containing the configuration
+     * @param props             The (non-{@code null}) {@link 
PropertyResolver} containing the configuration
      * @param lenient           If {@code true} then any unknown/unsupported 
configuration
      *                          values are ignored. Otherwise an {@link 
IllegalArgumentException} is thrown
      * @param xformer           A {@link Function} to convert the configured 
{@link DHFactory}-ies
@@ -545,9 +416,9 @@ public final class SshConfigFileReader {
      * @see #DEFAULT_KEX_ALGORITHMS
      */
     public static <M extends AbstractFactoryManager> M configureKeyExchanges(
-            M manager, Properties props, boolean lenient, Function<? super 
DHFactory, ? extends NamedFactory<KeyExchange>> xformer, boolean 
ignoreUnsupported) {
+            M manager, PropertyResolver props, boolean lenient, Function<? 
super DHFactory, ? extends NamedFactory<KeyExchange>> xformer, boolean 
ignoreUnsupported) {
         Objects.requireNonNull(props, "No properties to configure");
-        return configureKeyExchanges(manager, 
props.getProperty(KEX_ALGORITHMS_CONFIG_PROP, DEFAULT_KEX_ALGORITHMS), lenient, 
xformer, ignoreUnsupported);
+        return configureKeyExchanges(manager, 
props.getStringProperty(KEX_ALGORITHMS_CONFIG_PROP, DEFAULT_KEX_ALGORITHMS), 
lenient, xformer, ignoreUnsupported);
     }
 
     public static <M extends AbstractFactoryManager> M configureKeyExchanges(
@@ -578,11 +449,11 @@ public final class SshConfigFileReader {
      * @return The configured manager - <B>Note:</B> if the result of 
filtering due
      * to lenient mode or ignored unsupported value is empty then no factories 
are set
      */
-    public static <M extends AbstractFactoryManager> M configureCompression(M 
manager, Properties props, boolean lenient, boolean ignoreUnsupported) {
+    public static <M extends AbstractFactoryManager> M configureCompression(M 
manager, PropertyResolver props, boolean lenient, boolean ignoreUnsupported) {
         Objects.requireNonNull(manager, "No manager to configure");
         Objects.requireNonNull(props, "No properties to configure");
 
-        String value = props.getProperty(COMPRESSION_PROP, 
DEFAULT_COMPRESSION);
+        String value = props.getStringProperty(COMPRESSION_PROP, 
DEFAULT_COMPRESSION);
         CompressionFactory factory = CompressionConfigValue.fromName(value);
         ValidateUtils.checkTrue(lenient || (factory != null), "Unsupported 
compression value: %s", value);
         if ((factory != null) && factory.isSupported()) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a65c2f27/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java 
b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
index 924c6ee..0985b2b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
@@ -33,17 +33,19 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.TreeMap;
 
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.PropertyResolver;
 import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.ServiceFactory;
+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.helpers.AbstractFactoryManager;
@@ -464,7 +466,7 @@ public class SshServer extends AbstractFactoryManager 
implements ServerFactoryMa
         String hostKeyType = 
AbstractGeneratorHostKeyProvider.DEFAULT_ALGORITHM;
         int hostKeySize = 0;
         Collection<String> keyFiles = null;
-        Map<String, String> options = new LinkedHashMap<>();
+        Map<String, Object> options = new 
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
         int numArgs = GenericUtils.length(args);
         for (int i = 0; i < numArgs; i++) {
@@ -576,16 +578,22 @@ public class SshServer extends AbstractFactoryManager 
implements ServerFactoryMa
         Map<String, Object> props = sshd.getProperties();
         props.putAll(options);
 
+        PropertyResolver resolver = 
PropertyResolverUtils.toPropertyResolver(options);
         KeyPairProvider hostKeyProvider = setupServerKeys(sshd, hostKeyType, 
hostKeySize, keyFiles);
         sshd.setKeyPairProvider(hostKeyProvider);
         // Should come AFTER key pair provider setup so auto-welcome can be 
generated if needed
-        setupServerBanner(sshd, options);
+        setupServerBanner(sshd, resolver);
         sshd.setPort(port);
 
+        String macsOverride = 
resolver.getString(SshConfigFileReader.MACS_CONFIG_PROP);
+        if (GenericUtils.isNotEmpty(macsOverride)) {
+            SshConfigFileReader.configureMacs(sshd, macsOverride, true, true);
+        }
+
         sshd.setShellFactory(InteractiveProcessShellFactory.INSTANCE);
         sshd.setPasswordAuthenticator((username, password, session) -> 
Objects.equals(username, password));
         
sshd.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE);
-        setupServerForwarding(sshd, options);
+        setupServerForwarding(sshd, resolver);
         sshd.setCommandFactory(new ScpCommandFactory.Builder().withDelegate(
             command -> new ProcessShellFactory(GenericUtils.split(command, ' 
')).create()
         ).build());
@@ -595,13 +603,13 @@ public class SshServer extends AbstractFactoryManager 
implements ServerFactoryMa
         Thread.sleep(Long.MAX_VALUE);
     }
 
-    public static ForwardingFilter setupServerForwarding(SshServer server, 
Map<String, ?> options) {
+    public static ForwardingFilter setupServerForwarding(SshServer server, 
PropertyResolver options) {
         ForwardingFilter forwardFilter = 
SshServerConfigFileReader.resolveServerForwarding(options);
         server.setForwardingFilter(forwardFilter);
         return forwardFilter;
     }
 
-    public static Object setupServerBanner(ServerFactoryManager server, 
Map<String, ?> options) {
+    public static Object setupServerBanner(ServerFactoryManager server, 
PropertyResolver options) {
         Object banner = SshServerConfigFileReader.resolveBanner(options);
         PropertyResolverUtils.updateProperty(server, 
ServerAuthenticationManager.WELCOME_BANNER, banner);
         return banner;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a65c2f27/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java
index c5acd09..381d2a3 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/config/SshServerConfigFileReader.java
@@ -19,13 +19,16 @@
 package org.apache.sshd.server.config;
 
 import java.nio.file.Paths;
-import java.util.Map;
 
+import org.apache.sshd.common.PropertyResolver;
 import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.config.SshConfigFileReader;
+import org.apache.sshd.common.helpers.AbstractFactoryManager;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.server.ServerAuthenticationManager;
+import org.apache.sshd.server.ServerBuilder;
+import org.apache.sshd.server.SshServer;
 import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
 import org.apache.sshd.server.forward.AgentForwardingFilter;
 import org.apache.sshd.server.forward.ForwardingFilter;
@@ -59,7 +62,13 @@ public final class SshServerConfigFileReader {
         throw new UnsupportedOperationException("No instance allowed");
     }
 
-    public static ForwardingFilter resolveServerForwarding(Map<String, ?> 
options) {
+    public static <S extends SshServer> S configure(S server, PropertyResolver 
props, boolean lenient, boolean ignoreUnsupported) {
+        SshConfigFileReader.configure((AbstractFactoryManager) server, props, 
lenient, ignoreUnsupported);
+        SshConfigFileReader.configureKeyExchanges(server, props, lenient, 
ServerBuilder.DH2KEX, ignoreUnsupported);
+        return server;
+    }
+
+    public static ForwardingFilter resolveServerForwarding(PropertyResolver 
options) {
         if (GenericUtils.isEmpty(options)) {
             return AcceptAllForwardingFilter.INSTANCE;
         }
@@ -70,24 +79,24 @@ public final class SshServerConfigFileReader {
         return ForwardingFilter.asForwardingFilter(agentFilter, x11Filter, 
tcpFilter);
     }
 
-    public static AgentForwardingFilter 
resolveAgentForwardingFilter(Map<String, ?> options) {
+    public static AgentForwardingFilter 
resolveAgentForwardingFilter(PropertyResolver options) {
         String value = PropertyResolverUtils.getStringProperty(options, 
ALLOW_AGENT_FORWARDING_CONFIG_PROP, DEFAULT_AGENT_FORWARDING);
         return 
AgentForwardingFilter.of(SshConfigFileReader.parseBooleanValue(value));
     }
 
-    public static TcpForwardingFilter resolveTcpForwardingFilter(Map<String, 
?> options) {
+    public static TcpForwardingFilter 
resolveTcpForwardingFilter(PropertyResolver options) {
         String value = PropertyResolverUtils.getStringProperty(options, 
ALLOW_TCP_FORWARDING_CONFIG_PROP, DEFAULT_TCP_FORWARDING);
         TcpForwardingFilter filter = AllowTcpForwardingValue.fromString(value);
         ValidateUtils.checkNotNull(filter, "Unknown %s value: %s", 
ALLOW_TCP_FORWARDING_CONFIG_PROP, value);
         return filter;
     }
 
-    public static X11ForwardingFilter resolveX11ForwardingFilter(Map<String, 
?> options) {
+    public static X11ForwardingFilter 
resolveX11ForwardingFilter(PropertyResolver options) {
         String value = PropertyResolverUtils.getStringProperty(options, 
ALLOW_X11_FORWARDING_CONFIG_PROP, DEFAULT_X11_FORWARDING);
         return 
X11ForwardingFilter.of(SshConfigFileReader.parseBooleanValue(value));
     }
 
-    public static Object resolveBanner(Map<String, ?> options) {
+    public static Object resolveBanner(PropertyResolver options) {
         String bannerOption = PropertyResolverUtils.getString(options, 
BANNER_CONFIG_PROP);
         if (GenericUtils.isEmpty(bannerOption)) {
             bannerOption = PropertyResolverUtils.getStringProperty(options, 
VISUAL_HOST_KEY, DEFAULT_VISUAL_HOST_KEY);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a65c2f27/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
index b806f9e..4477da1 100644
--- 
a/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
+++ 
b/sshd-core/src/test/java/org/apache/sshd/common/config/SshConfigFileReaderTest.java
@@ -32,6 +32,7 @@ import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.cipher.BuiltinCiphers;
 import org.apache.sshd.common.cipher.Cipher;
 import org.apache.sshd.common.compression.BuiltinCompressions;
@@ -80,7 +81,7 @@ public class SshConfigFileReaderTest extends BaseTestSupport {
     public void testParseCiphersList() {
         List<? extends NamedResource> expected = 
BaseBuilder.DEFAULT_CIPHERS_PREFERENCE;
         Properties props = 
initNamedResourceProperties(SshConfigFileReader.CIPHERS_CONFIG_PROP, expected);
-        BuiltinCiphers.ParseResult result = 
SshConfigFileReader.getCiphers(props);
+        BuiltinCiphers.ParseResult result = 
SshConfigFileReader.getCiphers(PropertyResolverUtils.toPropertyResolver(props));
         testParsedFactoriesList(expected, result.getParsedFactories(), 
result.getUnsupportedFactories());
     }
 
@@ -88,7 +89,7 @@ public class SshConfigFileReaderTest extends BaseTestSupport {
     public void testParseMacsList() {
         List<? extends NamedResource> expected = 
BaseBuilder.DEFAULT_MAC_PREFERENCE;
         Properties props = 
initNamedResourceProperties(SshConfigFileReader.MACS_CONFIG_PROP, expected);
-        BuiltinMacs.ParseResult result = SshConfigFileReader.getMacs(props);
+        BuiltinMacs.ParseResult result = 
SshConfigFileReader.getMacs(PropertyResolverUtils.toPropertyResolver(props));
         testParsedFactoriesList(expected, result.getParsedFactories(), 
result.getUnsupportedFactories());
     }
 
@@ -96,7 +97,7 @@ public class SshConfigFileReaderTest extends BaseTestSupport {
     public void testParseSignaturesList() {
         List<? extends NamedResource> expected = 
BaseBuilder.DEFAULT_SIGNATURE_PREFERENCE;
         Properties props = 
initNamedResourceProperties(SshConfigFileReader.HOST_KEY_ALGORITHMS_CONFIG_PROP,
 expected);
-        BuiltinSignatures.ParseResult result = 
SshConfigFileReader.getSignatures(props);
+        BuiltinSignatures.ParseResult result = 
SshConfigFileReader.getSignatures(PropertyResolverUtils.toPropertyResolver(props));
         testParsedFactoriesList(expected, result.getParsedFactories(), 
result.getUnsupportedFactories());
     }
 
@@ -104,7 +105,7 @@ public class SshConfigFileReaderTest extends 
BaseTestSupport {
     public void testParseKexFactoriesList() {
         List<? extends NamedResource> expected = 
BaseBuilder.DEFAULT_KEX_PREFERENCE;
         Properties props = 
initNamedResourceProperties(SshConfigFileReader.KEX_ALGORITHMS_CONFIG_PROP, 
expected);
-        BuiltinDHFactories.ParseResult result = 
SshConfigFileReader.getKexFactories(props);
+        BuiltinDHFactories.ParseResult result = 
SshConfigFileReader.getKexFactories(PropertyResolverUtils.toPropertyResolver(props));
         testParsedFactoriesList(expected, result.getParsedFactories(), 
result.getUnsupportedFactories());
     }
 
@@ -114,7 +115,7 @@ public class SshConfigFileReaderTest extends 
BaseTestSupport {
         for (CompressionConfigValue expected : CompressionConfigValue.VALUES) {
             props.setProperty(SshConfigFileReader.COMPRESSION_PROP, 
expected.name().toLowerCase());
 
-            NamedResource actual = SshConfigFileReader.getCompression(props);
+            NamedResource actual = 
SshConfigFileReader.getCompression(PropertyResolverUtils.toPropertyResolver(props));
             assertNotNull("No match for " + expected.name(), actual);
             assertEquals(expected.name(), expected.getName(), 
actual.getName());
         }
@@ -130,7 +131,7 @@ public class SshConfigFileReaderTest extends 
BaseTestSupport {
             }
         };
         // must be lenient since we do not cover the full default spectrum
-        AbstractFactoryManager actual = 
SshConfigFileReader.configure(expected, props, true, true);
+        AbstractFactoryManager actual = 
SshConfigFileReader.configure(expected, 
PropertyResolverUtils.toPropertyResolver(props), true, true);
         assertSame("Mismatched configured result", expected, actual);
         validateAbstractFactoryManagerConfiguration(expected, props, true);
     }

Reply via email to