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 2015/05/07 10:29:34 UTC

[2/2] mina-sshd git commit: [SSHD-454] Allow lenient parsing of configuration values from ~/etc/sshd_config

[SSHD-454] Allow lenient parsing of configuration values from ~/etc/sshd_config


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

Branch: refs/heads/master
Commit: cca7cc743acbe2082b0fea5fb12d0b2f1630441d
Parents: 99ebcc9
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Thu May 7 11:29:20 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Thu May 7 11:29:20 2015 +0300

----------------------------------------------------------------------
 pom.xml                                         |   2 +-
 .../sshd/client/session/ClientSessionImpl.java  |   3 +-
 .../sshd/common/AbstractFactoryManager.java     |  18 +++
 .../java/org/apache/sshd/common/Factory.java    |   5 +-
 .../org/apache/sshd/common/NamedFactory.java    |  33 ++--
 .../org/apache/sshd/common/NamedResource.java   |  37 +++++
 .../sshd/common/cipher/BuiltinCiphers.java      |  48 ++++--
 .../common/config/FactoriesListParseResult.java |  49 ++++++
 .../sshd/common/config/ListParseResult.java     |  65 ++++++++
 .../config/NamedFactoriesListParseResult.java   |  45 ++++++
 .../config/NamedResourceListParseResult.java    |  57 +++++++
 .../sshd/common/config/SshConfigFileReader.java | 127 ++++++++++-----
 .../sshd/common/digest/BuiltinDigests.java      |   2 +-
 .../sshd/common/kex/BuiltinDHFactories.java     |  59 +++++--
 .../org/apache/sshd/common/mac/BuiltinMacs.java |  54 +++++--
 .../sshd/common/session/AbstractSession.java    |  33 ++--
 .../common/signature/BuiltinSignatures.java     |  47 ++++--
 .../apache/sshd/common/util/ValidateUtils.java  |  28 ++--
 .../sshd/server/session/ServerSession.java      |   6 +-
 .../server/session/ServerUserAuthService.java   |   6 +-
 .../java/org/apache/sshd/SshBuilderTest.java    |   3 +-
 .../sshd/common/cipher/BuiltinCiphersTest.java  |  44 +++++
 .../common/config/SshConfigFileReaderTest.java  | 161 +++++++++++++++++--
 .../sshd/common/kex/BuiltinDHFactoriesTest.java |  44 +++++
 .../apache/sshd/common/mac/BuiltinMacsTest.java |  45 ++++++
 .../common/signature/BuiltinSignaturesTest.java |  46 ++++++
 .../sshd/common/util/ValidateUtilsTest.java     |  32 ++++
 .../java/org/apache/sshd/util/BaseTest.java     |  12 ++
 28 files changed, 934 insertions(+), 177 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 7795da5..0a9d175 100644
--- a/pom.xml
+++ b/pom.xml
@@ -562,7 +562,7 @@
 			            	<goal>remove-project-artifact</goal>
 			            </goals>
 			            <configuration>
-			            	<removeAll>true</removeAll>
+			            	<removeAll>false</removeAll>
 			            </configuration>
 			          </execution>
 		        </executions>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index 0e14596..2b3b60a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -45,6 +45,7 @@ import org.apache.sshd.client.sftp.DefaultSftpClient;
 import org.apache.sshd.client.sftp.SftpFileSystem;
 import org.apache.sshd.client.sftp.SftpFileSystemProvider;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.Service;
 import org.apache.sshd.common.ServiceFactory;
 import org.apache.sshd.common.SessionListener;
@@ -360,7 +361,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
     }
 
     protected void sendKexInit() throws IOException {
-        String algs = NamedFactory.Utils.getNames(getFactoryManager().getSignatureFactories());
+        String algs = NamedResource.Utils.getNames(getFactoryManager().getSignatureFactories());
         clientProposal = createProposal(algs);
         I_C = sendKexInit(clientProposal);
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
index 8b1ff41..22af67e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
@@ -71,6 +71,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         loadVersion();
     }
 
+    @Override
     public IoServiceFactory getIoServiceFactory() {
         synchronized (ioServiceFactoryFactory) {
             if (ioServiceFactory == null) {
@@ -88,6 +89,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.ioServiceFactoryFactory = ioServiceFactory;
     }
 
+    @Override
     public List<NamedFactory<KeyExchange>> getKeyExchangeFactories() {
         return keyExchangeFactories;
     }
@@ -96,6 +98,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.keyExchangeFactories = keyExchangeFactories;
     }
 
+    @Override
     public List<NamedFactory<Cipher>> getCipherFactories() {
         return cipherFactories;
     }
@@ -104,6 +107,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.cipherFactories = cipherFactories;
     }
 
+    @Override
     public List<NamedFactory<Compression>> getCompressionFactories() {
         return compressionFactories;
     }
@@ -112,6 +116,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.compressionFactories = compressionFactories;
     }
 
+    @Override
     public List<NamedFactory<Mac>> getMacFactories() {
         return macFactories;
     }
@@ -120,6 +125,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.macFactories = macFactories;
     }
 
+    @Override
     public List<NamedFactory<Signature>> getSignatureFactories() {
         return signatureFactories;
     }
@@ -128,6 +134,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.signatureFactories = signatureFactories;
     }
 
+    @Override
     public Factory<Random> getRandomFactory() {
         return randomFactory;
     }
@@ -136,6 +143,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.randomFactory = randomFactory;
     }
 
+    @Override
     public KeyPairProvider getKeyPairProvider() {
         return keyPairProvider;
     }
@@ -144,6 +152,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.keyPairProvider = keyPairProvider;
     }
 
+    @Override
     public Map<String, String> getProperties() {
         return properties;
     }
@@ -152,6 +161,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.properties = properties;
     }
 
+    @Override
     public String getVersion() {
         return version;
     }
@@ -169,6 +179,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         }
     }
 
+    @Override
     public List<NamedFactory<Channel>> getChannelFactories() {
         return channelFactories;
     }
@@ -194,6 +205,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         }
     }
 
+    @Override
     public SshAgentFactory getAgentFactory() {
         return agentFactory;
     }
@@ -202,6 +214,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.agentFactory = agentFactory;
     }
 
+    @Override
     public ScheduledExecutorService getScheduledExecutorService() {
         return executor;
     }
@@ -215,6 +228,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.shutdownExecutor = shutdownExecutor;
     }
 
+    @Override
     public TcpipForwarderFactory getTcpipForwarderFactory() {
         return tcpipForwarderFactory;
     }
@@ -223,6 +237,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.tcpipForwarderFactory = tcpipForwarderFactory;
     }
 
+    @Override
     public ForwardingFilter getTcpipForwardingFilter() {
         return tcpipForwardingFilter;
     }
@@ -231,6 +246,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.tcpipForwardingFilter = tcpipForwardingFilter;
     }
 
+    @Override
     public FileSystemFactory getFileSystemFactory() {
         return fileSystemFactory;
     }
@@ -239,6 +255,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.fileSystemFactory = fileSystemFactory;
     }
 
+    @Override
     public List<ServiceFactory> getServiceFactories() {
         return serviceFactories;
     }
@@ -247,6 +264,7 @@ public abstract class AbstractFactoryManager extends CloseableUtils.AbstractInne
         this.serviceFactories = serviceFactories;
     }
 
+    @Override
     public List<RequestHandler<ConnectionService>> getGlobalRequestHandlers() {
         return globalRequestHandlers;
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/Factory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/Factory.java b/sshd-core/src/main/java/org/apache/sshd/common/Factory.java
index 864dbd2..3d3590e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/Factory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/Factory.java
@@ -18,6 +18,7 @@
  */
 package org.apache.sshd.common;
 
+
 /**
  * Fatory is a simple interface that is used to create other objects.
  *
@@ -28,9 +29,7 @@ package org.apache.sshd.common;
 public interface Factory<T> {
 
     /**
-     * Create a new instance
-     * @return
+     * @return A new instance
      */
     T create();
-
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
index 77b8cdc..f12ca99 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
@@ -20,7 +20,6 @@ package org.apache.sshd.common;
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
 import org.apache.sshd.common.util.GenericUtils;
@@ -28,32 +27,23 @@ import org.apache.sshd.common.util.GenericUtils;
 /**
  * A named factory is a factory identified by a name.
  * Such names are used mainly in the algorithm negotiation at the beginning of the SSH connection.
- *
- * @param <T>
- *
+ * @param <T> The create object instance type
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public interface NamedFactory<T> extends Factory<T>, NamedResource {
     /**
      * Utility class to help using NamedFactories
      */
-    public static class Utils {
+    public static final class Utils {
     	/**
     	 * @param factories The named factories
     	 * @return A {@link List} of all the factories names - in same order
     	 * as they appear in the input collection
+    	 * @deprecated Use {@link NamedResource.Utils#getNameList(Collection)}
     	 */
+        @Deprecated
         public static List<String> getNameList(Collection<? extends NamedFactory<?>> factories) {
-            if (GenericUtils.isEmpty(factories)) {
-                return Collections.emptyList();
-            }
-
-            List<String> names = new ArrayList<>(factories.size());
-            for (NamedFactory<?> f : factories) {
-                names.add(f.getName());
-            }
-
-            return names;
+            return NamedResource.Utils.getNameList(factories);
         }
 
         /**
@@ -79,16 +69,11 @@ public interface NamedFactory<T> extends Factory<T>, NamedResource {
          *
          * @param factories list of available factories
          * @return a comma separated list of factory names
+         * @deprecated Use {@link NamedResource.Utils#getNames(Collection)}
          */
+        @Deprecated
         public static String getNames(Collection<? extends NamedFactory<?>> factories) {
-            StringBuilder sb = new StringBuilder();
-            for (NamedFactory<?> f : factories) {
-                if (sb.length() > 0) {
-                    sb.append(",");
-                }
-                sb.append(f.getName());
-            }
-            return sb.toString();
+            return NamedResource.Utils.getNames(factories);
         }
 
         /**
@@ -128,7 +113,6 @@ public interface NamedFactory<T> extends Factory<T>, NamedResource {
             return null;
         }
         
-        
         public static final <T,E extends NamedFactory<T> & OptionalFeature> List<NamedFactory<T>> setUpBuiltinFactories(
                 boolean ignoreUnsupported, Collection<? extends E> preferred) {
             List<NamedFactory<T>>   avail=new ArrayList<>(preferred.size());
@@ -141,4 +125,5 @@ public interface NamedFactory<T> extends Factory<T>, NamedResource {
             return avail;
         }
     }
+
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
index 85f78a8..494a1a9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
@@ -19,6 +19,13 @@
 
 package org.apache.sshd.common;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.util.GenericUtils;
+
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
@@ -27,4 +34,34 @@ public interface NamedResource {
      * @return The resource name
      */
     String getName();
+    /**
+     * Utility class to help using {@link NamedResource}s
+     */
+    public static final class Utils {
+        /**
+         * @param resources The named resources
+         * @return A {@link List} of all the factories names - in same order
+         * as they appear in the input collection
+         */
+        public static List<String> getNameList(Collection<? extends NamedResource> resources) {
+            if (GenericUtils.isEmpty(resources)) {
+                return Collections.emptyList();
+            }
+
+            List<String> names = new ArrayList<>(resources.size());
+            for (NamedResource r : resources) {
+                names.add(r.getName());
+            }
+
+            return names;
+        }
+        
+        /**
+         * @param resources list of available resources
+         * @return A comma separated list of factory names
+         */
+        public static String getNames(Collection<? extends NamedResource> resources) {
+            return GenericUtils.join(getNameList(resources), ',');
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java
index 2ff52a0..da8550d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/BuiltinCiphers.java
@@ -30,8 +30,8 @@ import java.util.Set;
 import org.apache.sshd.common.Cipher;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.OptionalFeature;
+import org.apache.sshd.common.config.NamedFactoriesListParseResult;
 import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
 
 /**
  * Provides easy access to the currently implemented ciphers
@@ -205,33 +205,51 @@ public enum BuiltinCiphers implements NamedFactory<Cipher>, OptionalFeature {
     /**
      * @param ciphers A comma-separated list of ciphers' names - ignored
      * if {@code null}/empty
-     * @return A {@link List} 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
-     * is the same as the original order - bar the unknown ciphers.
-     * <B>Note:</B> it is up to caller to ensure that the list does not
-     * contain duplicates
+     * @return A {@link ParseResult} containing the successfully parsed
+     * factories and the unknown ones. <B>Note:</B> it is up to caller to
+     * ensure that the lists do not contain duplicates
      */
-    public static final List<NamedFactory<Cipher>> parseCiphersList(String ciphers) {
+    public static final ParseResult parseCiphersList(String ciphers) {
         return parseCiphersList(GenericUtils.split(ciphers, ','));
     }
 
-    public static final List<NamedFactory<Cipher>> parseCiphersList(String ... ciphers) {
+    public static final ParseResult parseCiphersList(String ... ciphers) {
         return parseCiphersList(GenericUtils.isEmpty((Object[]) ciphers) ? Collections.<String>emptyList() : Arrays.asList(ciphers));
     }
 
-    public static final List<NamedFactory<Cipher>> parseCiphersList(Collection<String> ciphers) {
+    public static final ParseResult parseCiphersList(Collection<String> ciphers) {
         if (GenericUtils.isEmpty(ciphers)) {
-            return Collections.emptyList();
+            return ParseResult.EMPTY;
         }
         
-        List<NamedFactory<Cipher>>    result=new ArrayList<NamedFactory<Cipher>>(ciphers.size());
+        List<NamedFactory<Cipher>>  factories=new ArrayList<NamedFactory<Cipher>>(ciphers.size());
+        List<String>                unknown=Collections.<String>emptyList();
         for (String name : ciphers) {
-            BuiltinCiphers  c=ValidateUtils.checkNotNull(fromFactoryName(name), "Bad factory name (%s) in %s", name, ciphers);
-            result.add(c);
+            BuiltinCiphers  c=fromFactoryName(name);
+            if (c != null) {
+                factories.add(c);
+            } else {
+                // replace the (unmodifiable) empty list with a real one
+                if (unknown.isEmpty()) {
+                    unknown = new ArrayList<String>();
+                }
+                unknown.add(name);
+            }
         }
         
-        return result;
+        return new ParseResult(factories, unknown);
+    }
+
+    /**
+     * Holds the result of {@link BuiltinCiphers#parseCiphersList(String)}
+     * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+     */
+    public static final class ParseResult extends NamedFactoriesListParseResult<Cipher,NamedFactory<Cipher>> {
+        public static final ParseResult EMPTY=new ParseResult(Collections.<NamedFactory<Cipher>>emptyList(), Collections.<String>emptyList());
+        
+        public ParseResult(List<NamedFactory<Cipher>> parsed, List<String> unsupported) {
+            super(parsed, unsupported);
+        }
     }
 
     public static final class Constants {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/config/FactoriesListParseResult.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/FactoriesListParseResult.java b/sshd-core/src/main/java/org/apache/sshd/common/config/FactoriesListParseResult.java
new file mode 100644
index 0000000..853e16d
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/FactoriesListParseResult.java
@@ -0,0 +1,49 @@
+/*
+ * 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.config;
+
+import java.util.List;
+
+import org.apache.sshd.common.Factory;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class FactoriesListParseResult<T,F extends Factory<T>> extends ListParseResult<F> {
+    protected FactoriesListParseResult(List<F> parsed, List<String> unsupported) {
+        super(parsed, unsupported);
+    }
+    
+    /**
+     * @return The {@link List} of successfully parsed {@link Factory} instances
+     * in the <U>same order</U> as they were encountered during parsing
+     */
+    public final List<F> getParsedFactories() {
+        return getParsedValues();
+    }
+
+    /**
+     * @return A {@link List} of unknown/unsupported configuration values for
+     * the factories
+     */
+    public List<String> getUnsupportedFactories() {
+        return getUnsupportedValues();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/config/ListParseResult.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/ListParseResult.java b/sshd-core/src/main/java/org/apache/sshd/common/config/ListParseResult.java
new file mode 100644
index 0000000..bf39c89
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/ListParseResult.java
@@ -0,0 +1,65 @@
+/*
+ * 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.config;
+
+import java.util.List;
+
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * Used to hold the result of parsing a list of value. Such result contains known
+ * and unknown values - which are accessible via the respective {@link #getParsedValues()}
+ * and {@link #getUnsupportedValues()} methods. <B>Note:</B> the returned {@link List}s may
+ * be un-modifiable, so it is recommended to avoid attempting changing the, returned
+ * list(s)
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class ListParseResult<E> {
+    private final List<E> parsed;
+    private final List<String> unsupported;
+
+    protected ListParseResult(List<E> parsed, List<String> unsupported) {
+        this.parsed = parsed;
+        this.unsupported = unsupported;
+    }
+
+    /**
+     * @return The {@link List} of successfully parsed value instances
+     * in the <U>same order</U> as they were encountered during parsing
+     */
+    public final List<E> getParsedValues() {
+        return parsed;
+    }
+
+    /**
+     * @return A {@link List} of unknown/unsupported configuration values for
+     * the factories
+     */
+    public List<String> getUnsupportedValues() {
+        return unsupported;
+    }
+    
+    @Override
+    public String toString() {
+        return "parsed=" + GenericUtils.join(getParsedValues(), ',')
+             + ";unsupported=" + GenericUtils.join(getUnsupportedValues(), ',')
+               ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/config/NamedFactoriesListParseResult.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/NamedFactoriesListParseResult.java b/sshd-core/src/main/java/org/apache/sshd/common/config/NamedFactoriesListParseResult.java
new file mode 100644
index 0000000..9e1b817
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/NamedFactoriesListParseResult.java
@@ -0,0 +1,45 @@
+/*
+ * 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.config;
+
+import java.util.List;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * Holds the result of parsing a list of {@link NamedFactory}ies
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class NamedFactoriesListParseResult<T,F extends NamedFactory<T>>
+                       extends FactoriesListParseResult<T,F> {
+
+    protected NamedFactoriesListParseResult(List<F> parsed, List<String> unsupported) {
+        super(parsed, unsupported);
+    }
+
+    @Override
+    public String toString() {
+        return "parsed=" + NamedResource.Utils.getNames(getParsedFactories())
+             + ";unknown=" + GenericUtils.join(getUnsupportedFactories(), ',')
+              ;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/config/NamedResourceListParseResult.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/NamedResourceListParseResult.java b/sshd-core/src/main/java/org/apache/sshd/common/config/NamedResourceListParseResult.java
new file mode 100644
index 0000000..03805ef
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/NamedResourceListParseResult.java
@@ -0,0 +1,57 @@
+/*
+ * 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.config;
+
+import java.util.List;
+
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.util.GenericUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public abstract class NamedResourceListParseResult<R extends NamedResource> extends ListParseResult<R> {
+    protected NamedResourceListParseResult(List<R> parsed, List<String> unsupported) {
+        super(parsed, unsupported);
+    }
+
+    /**
+     * @return The {@link List} of successfully parsed {@link NamedResource} instances
+     * in the <U>same order</U> as they were encountered during parsing
+     */
+    public final List<R> getParsedResources() {
+        return getParsedValues();
+    }
+
+    /**
+     * @return A {@link List} of unknown/unsupported configuration values for
+     * the resources
+     */
+    public List<String> getUnsupportedResources() {
+        return getUnsupportedValues();
+    }
+
+    @Override
+    public String toString() {
+        return "parsed=" + NamedResource.Utils.getNames(getParsedResources())
+             + ";unknown=" + GenericUtils.join(getUnsupportedResources(), ',')
+              ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/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 45c7aff..38e0272 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
@@ -29,8 +29,8 @@ import java.io.Reader;
 import java.io.StreamCorruptedException;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
+import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
@@ -347,23 +347,23 @@ public class SshConfigFileReader {
     
     /**
      * @param props The {@link Properties} - ignored if {@code null}/empty
-     * @return A {@link List} 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
+     * @return A {@BuiltinCiphers.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
      * is the same as the original order - bar the unknown ciphers.
-     * <B>Note:</B> it is up to caller to ensure that the list does not
+     * <B>Note:</B> it is up to caller to ensure that the lists do not
      * contain duplicates
      * @see #CIPHERS_CONFIG_PROP
      * @see BuiltinCiphers#parseCiphersList(String)
      */
-    public static final List<NamedFactory<Cipher>> getCiphers(Properties props) {
+    public static final BuiltinCiphers.ParseResult getCiphers(Properties props) {
         return BuiltinCiphers.parseCiphersList((props == null) ? null : props.getProperty(CIPHERS_CONFIG_PROP));
     }
     
     /**
      * @param props The {@link Properties} - ignored if {@code null}/empty
-     * @return A {@link List} of all the {@link NamedFactory}-ies whose
-     * name appears in the string and represent a built-in MAC. Any
+     * @return A {@link BuiltinMacs.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
      * is the same as the original order - bar the unknown MACs.
      * <B>Note:</B> it is up to caller to ensure that the list does not
@@ -371,37 +371,35 @@ public class SshConfigFileReader {
      * @see #MACS_CONFIG_PROP
      * @see BuiltinMacs#parseMacsList(String)
      */
-    public static final List<NamedFactory<Mac>> getMacs(Properties props) {
+    public static final BuiltinMacs.ParseResult getMacs(Properties props) {
         return BuiltinMacs.parseMacsList((props == null) ? null : props.getProperty(MACS_CONFIG_PROP));
     }
     
     /**
      * @param props The {@link Properties} - ignored if {@code null}/empty
-     * @return A {@link List} of all the {@link NamedFactory} whose
-     * name appears in the string and represent a built-in signature. Any
-     * unknown name is <U>ignored</I>. The order of the returned result
-     * is the same as the original order - bar the unknown signatures.
-     * <B>Note:</B> it is up to caller to ensure that the list does not
-     * contain duplicates
+     * @return A {@link BuiltinSignatures.ParseResult} of all the {@link NamedFactory}
+     * whose name appears in the string and represent a built-in signature. Any
+     * unknown name is <U>ignored</I>. The order of the returned result is the
+     * same as the original order - bar the unknown signatures. <B>Note:</B> it
+     * is up to caller to ensure that the list does not contain duplicates
      * @see #HOST_KEY_ALGORITHMS_CONFIG_PROP
      * @see BuiltinSignatures#parseSignatureList(String)
      */
-    public static final List<NamedFactory<Signature>> getSignatures(Properties props) {
+    public static final BuiltinSignatures.ParseResult getSignatures(Properties props) {
         return BuiltinSignatures.parseSignatureList((props == null) ? null : props.getProperty(HOST_KEY_ALGORITHMS_CONFIG_PROP));
     }
     
     /**
      * @param props The {@link Properties} - ignored if {@code null}/empty
-     * @return A {@link List} 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 same as the original order - bar the unknown ones.
-     * <B>Note:</B> it is up to caller to ensure that the list does not
-     * contain duplicates
+     * @return A {@link BuiltinDHFactories.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
+     * same as the original order - bar the unknown ones. <B>Note:</B> it is
+     * up to caller to ensure that the list does not contain duplicates
      * @see #KEX_ALGORITHMS_CONFIG_PROP
      * @see BuiltinDHFactories#parseDHFactoriesList(String)
      */
-    public static final List<DHFactory> getKexFactories(Properties props) {
+    public static final BuiltinDHFactories.ParseResult getKexFactories(Properties props) {
         return BuiltinDHFactories.parseDHFactoriesList((props == null) ? null : props.getProperty(KEX_ALGORITHMS_CONFIG_PROP));
     }
     
@@ -427,32 +425,77 @@ public class SshConfigFileReader {
      * @param props The {@link Properties} 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/unsupported configuration
+     * values are ignored. Otherwise an {@link IllegalArgumentException} is thrown
      * @return The configured manager
      */
-    public static final <M extends AbstractFactoryManager> M configure(M manager, Properties props) {
+    public static final <M extends AbstractFactoryManager> M configure(M manager, Properties props, boolean lenient) {
+        configureCiphers(manager, props, lenient);
+        configureSignatures(manager, props, lenient);
+        configureMacs(manager, props, lenient);
+        configureCompression(manager, props, lenient);
+
+        return manager;
+    }
+
+    public static final <M extends AbstractFactoryManager> M configureCiphers(M manager, Properties props, boolean lenient) {
+        ValidateUtils.checkNotNull(props, "No properties to configure", GenericUtils.EMPTY_OBJECT_ARRAY);
+        return configureCiphers(manager, props.getProperty(CIPHERS_CONFIG_PROP, DEFAULT_CIPHERS), lenient);
+    }
+
+    public static final <M extends AbstractFactoryManager> M configureCiphers(M manager, String value, boolean lenient) {
         ValidateUtils.checkNotNull(manager, "No manager to configure", GenericUtils.EMPTY_OBJECT_ARRAY);
+
+        BuiltinCiphers.ParseResult  result=BuiltinCiphers.parseCiphersList(value);
+        Collection<String>          unsupported=result.getUnsupportedFactories();
+        ValidateUtils.checkTrue(lenient || GenericUtils.isEmpty(unsupported), "Unsupported cipher(s) (%s) in %s", unsupported, value);
+        manager.setCipherFactories(ValidateUtils.checkNotNullAndNotEmpty(result.getParsedFactories(), "No known ciphers(s): %s", value));
+        return manager;
+    }
+
+    public static final <M extends AbstractFactoryManager> M configureSignatures(M manager, Properties props, boolean lenient) {
         ValidateUtils.checkNotNull(props, "No properties to configure", GenericUtils.EMPTY_OBJECT_ARRAY);
-        
-        {
-            String  value=props.getProperty(HOST_KEY_ALGORITHMS_CONFIG_PROP, DEFAULT_HOST_KEY_ALGORITHMS);
-            manager.setSignatureFactories(ValidateUtils.checkNotNullAndNotEmpty(BuiltinSignatures.parseSignatureList(value), "Bad signatures: %s", value));
-        }
+        return configureSignatures(manager, props.getProperty(HOST_KEY_ALGORITHMS_CONFIG_PROP, DEFAULT_HOST_KEY_ALGORITHMS), lenient);
+    }
 
-        {
-            String  value=props.getProperty(MACS_CONFIG_PROP, DEFAULT_MACS);
-            manager.setMacFactories(ValidateUtils.checkNotNullAndNotEmpty(BuiltinMacs.parseMacsList(value), "Bad MAC(s): %s", value));
-        }
+    public static final <M extends AbstractFactoryManager> M configureSignatures(M manager, String value, boolean lenient) {
+        ValidateUtils.checkNotNull(manager, "No manager to configure", GenericUtils.EMPTY_OBJECT_ARRAY);
 
-        {
-            String  value=props.getProperty(CIPHERS_CONFIG_PROP, DEFAULT_CIPHERS);
-            manager.setCipherFactories(ValidateUtils.checkNotNullAndNotEmpty(BuiltinCiphers.parseCiphersList(value), "Bad ciphers(s): %s", value));
-        }
+        BuiltinSignatures.ParseResult   result=BuiltinSignatures.parseSignatureList(value);
+        Collection<String>              unsupported=result.getUnsupportedFactories();
+        ValidateUtils.checkTrue(lenient || GenericUtils.isEmpty(unsupported), "Unsupported signatures (%s) in %s", unsupported, value);
+        manager.setSignatureFactories(ValidateUtils.checkNotNullAndNotEmpty(result.getParsedFactories(), "No known signatures: %s", value));
+        return manager;
+    }
+    
+    public static final <M extends AbstractFactoryManager> M configureMacs(M manager, Properties props, boolean lenient) {
+        ValidateUtils.checkNotNull(props, "No properties to configure", GenericUtils.EMPTY_OBJECT_ARRAY);
+        return configureMacs(manager, props.getProperty(MACS_CONFIG_PROP, DEFAULT_MACS), lenient);
+    }
+
+    public static final <M extends AbstractFactoryManager> M configureMacs(M manager, String value, boolean lenient) {
+        ValidateUtils.checkNotNull(manager, "No manager to configure", GenericUtils.EMPTY_OBJECT_ARRAY);
+
+        BuiltinMacs.ParseResult result=BuiltinMacs.parseMacsList(value);
+        Collection<String>      unsupported=result.getUnsupportedFactories();
+        ValidateUtils.checkTrue(lenient || GenericUtils.isEmpty(unsupported), "Unsupported MAC(s) (%s) in %s", unsupported, value);
+        manager.setMacFactories(ValidateUtils.checkNotNullAndNotEmpty(result.getParsedFactories(), "No known MAC(s): %s", value));
+        return manager;
+    }
+
+    // NOTE: if no compression is resolved it is OK since SSH can function without it
+    public static final <M extends AbstractFactoryManager> M configureCompression(M manager, Properties props, boolean lenient) {
+        ValidateUtils.checkNotNull(props, "No properties to configure", GenericUtils.EMPTY_OBJECT_ARRAY);
+        return configureCompression(manager, props.getProperty(COMPRESSION_PROP, DEFAULT_COMPRESSION), lenient);
+    }
+
+    public static final <M extends AbstractFactoryManager> M configureCompression(M manager, String value, boolean lenient) {
+        ValidateUtils.checkNotNull(manager, "No manager to configure", GenericUtils.EMPTY_OBJECT_ARRAY);
 
-        {
-            String  value=props.getProperty(COMPRESSION_PROP, DEFAULT_COMPRESSION);
-            manager.setCompressionFactories(
-                    Collections.<NamedFactory<Compression>>singletonList(
-                            ValidateUtils.checkNotNull(CompressionConfigValue.fromName(value), "Bad compression: %s", value)));
+        NamedFactory<Compression>   factory=CompressionConfigValue.fromName(value);
+        ValidateUtils.checkTrue(lenient || (factory != null), "Unsupported compression value: %s", value);
+        if (factory != null) {
+            manager.setCompressionFactories(Collections.<NamedFactory<Compression>>singletonList(factory));
         }
 
         return manager;

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/digest/BuiltinDigests.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/digest/BuiltinDigests.java b/sshd-core/src/main/java/org/apache/sshd/common/digest/BuiltinDigests.java
index 8b342ba..2b90287 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/digest/BuiltinDigests.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/digest/BuiltinDigests.java
@@ -135,7 +135,7 @@ public enum BuiltinDigests implements NamedFactory<Digest> {
         return null;
     }
 
-    private static class Constants {
+    public static final class Constants {
         public static final String MD5 = "md5";
         public static final String SHA1 = "sha1";
         public static final String SHA256 = "sha256";

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java
index 452dc5f..be29fa2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/BuiltinDHFactories.java
@@ -30,10 +30,10 @@ import java.util.Set;
 
 import org.apache.sshd.common.OptionalFeature;
 import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.NamedResourceListParseResult;
 import org.apache.sshd.common.digest.BuiltinDigests;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.SecurityUtils;
-import org.apache.sshd.common.util.ValidateUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -191,35 +191,64 @@ public enum BuiltinDHFactories implements DHFactory, OptionalFeature {
     }
 
     /**
-     * @param factories A comma-separated list of ciphers' names - ignored
+     * @param dhList A comma-separated list of ciphers' names - ignored
      * if {@code null}/empty
-     * @return A {@link List} of all the {@link DHFactory}-ies whose
+     * @return A {@link 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 same as the original order - bar the unknown ones.
      * <B>Note:</B> it is up to caller to ensure that the list does not
      * contain duplicates
      */
-    public static final List<DHFactory> parseDHFactoriesList(String factories) {
-        return parseDHFactoriesList(GenericUtils.split(factories, ','));
+    public static final ParseResult parseDHFactoriesList(String dhList) {
+        return parseDHFactoriesList(GenericUtils.split(dhList, ','));
     }
 
-    public static final List<DHFactory> parseDHFactoriesList(String ... factories) {
-        return parseDHFactoriesList(GenericUtils.isEmpty((Object[]) factories) ? Collections.<String>emptyList() : Arrays.asList(factories));
+    public static final ParseResult parseDHFactoriesList(String ... dhList) {
+        return parseDHFactoriesList(GenericUtils.isEmpty((Object[]) dhList) ? Collections.<String>emptyList() : Arrays.asList(dhList));
     }
 
-    public static final List<DHFactory> parseDHFactoriesList(Collection<String> factories) {
-        if (GenericUtils.isEmpty(factories)) {
-            return Collections.emptyList();
+    public static final ParseResult parseDHFactoriesList(Collection<String> dhList) {
+        if (GenericUtils.isEmpty(dhList)) {
+            return ParseResult.EMPTY;
         }
         
-        List<DHFactory>    result=new ArrayList<DHFactory>(factories.size());
-        for (String name : factories) {
-            DHFactory  c=ValidateUtils.checkNotNull(fromFactoryName(name), "Unknown factory name (%s) in %s", name, factories);
-            result.add(c);
+        List<DHFactory> factories=new ArrayList<DHFactory>(dhList.size());
+        List<String>    unknown=Collections.<String>emptyList();
+        for (String name : dhList) {
+            DHFactory  f=fromFactoryName(name);
+            if (f != null) {
+                factories.add(f);
+            } else {
+                // replace the (unmodifiable) empty list with a real one
+                if (unknown.isEmpty()) {
+                    unknown = new ArrayList<String>();
+                }
+                unknown.add(name);
+            }
         }
         
-        return result;
+        return new ParseResult(factories, unknown);
+    }
+
+    /**
+     * Represents the result of {@link BuiltinDHFactories#parseDHFactoriesList(String)}
+     * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+     */
+    public static final class ParseResult extends NamedResourceListParseResult<DHFactory> {
+        public static final ParseResult EMPTY=new ParseResult(Collections.<DHFactory>emptyList(), Collections.<String>emptyList());
+        
+        public ParseResult(List<DHFactory> parsed, List<String> unsupported) {
+            super(parsed, unsupported);
+        }
+        
+        public List<DHFactory> getParsedFactories() {
+            return getParsedResources();
+        }
+        
+        public List<String> getUnsupportedFactories() {
+            return getUnsupportedResources();
+        }
     }
 
     public static final class Constants {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java b/sshd-core/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java
index e8d9239..5756dc5 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/mac/BuiltinMacs.java
@@ -32,7 +32,6 @@ import org.apache.sshd.common.Mac;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.OptionalFeature;
 import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.ValidateUtils;
 
 /**
  * Provides easy access to the currently implemented macs
@@ -156,33 +155,58 @@ public enum BuiltinMacs implements NamedFactory<Mac>, OptionalFeature {
     /**
      * @param macs A comma-separated list of MACs' names - ignored
      * if {@code null}/empty
-     * @return A {@link List} 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
-     * is the same as the original order - bar the unknown MACs.
-     * <B>Note:</B> it is up to caller to ensure that the list does not
-     * contain duplicates
+     * @return A {@link ParseResult} containing the successfully parsed
+     * factories and the unknown ones. <B>Note:</B> it is up to caller to
+     * ensure that the lists do not contain duplicates
      */
-    public static final List<NamedFactory<Mac>> parseMacsList(String macs) {
+    public static final ParseResult parseMacsList(String macs) {
         return parseMacsList(GenericUtils.split(macs, ','));
     }
 
-    public static final List<NamedFactory<Mac>> parseMacsList(String ... macs) {
+    public static final ParseResult parseMacsList(String ... macs) {
         return parseMacsList(GenericUtils.isEmpty((Object[]) macs) ? Collections.<String>emptyList() : Arrays.asList(macs));
     }
 
-    public static final List<NamedFactory<Mac>> parseMacsList(Collection<String> macs) {
+    public static final ParseResult parseMacsList(Collection<String> macs) {
         if (GenericUtils.isEmpty(macs)) {
-            return Collections.emptyList();
+            return ParseResult.EMPTY;
         }
         
-        List<NamedFactory<Mac>>    result=new ArrayList<NamedFactory<Mac>>(macs.size());
+        List<NamedFactory<Mac>> factories=new ArrayList<NamedFactory<Mac>>(macs.size());
+        List<String>            unknown=Collections.<String>emptyList();
         for (String name : macs) {
-            BuiltinMacs  m=ValidateUtils.checkNotNull(fromFactoryName(name), "Bad factory name (%s) in %s", name, macs);
-            result.add(m);
+            BuiltinMacs  m=fromFactoryName(name);
+            if (m != null) {
+                factories.add(m);
+            } else {
+                // replace the (unmodifiable) empty list with a real one
+                if (unknown.isEmpty()) {
+                    unknown = new ArrayList<String>();
+                }
+                unknown.add(name);
+            }
         }
         
-        return result;
+        return new ParseResult(factories, unknown);
+    }
+
+    public static final class ParseResult {
+        public static final ParseResult EMPTY=new ParseResult(Collections.<NamedFactory<Mac>>emptyList(), Collections.<String>emptyList());
+        private final List<NamedFactory<Mac>> parsed;
+        private final List<String> unsupported;
+        
+        public ParseResult(List<NamedFactory<Mac>> parsed, List<String> unsupported) {
+            this.parsed = parsed;
+            this.unsupported = unsupported;
+        }
+        
+        public List<NamedFactory<Mac>> getParsedFactories() {
+            return parsed;
+        }
+        
+        public List<String> getUnsupportedFactories() {
+            return unsupported;
+        }
     }
 
     public static final class Constants {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
index 15f01ba..0903c39 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
@@ -18,6 +18,15 @@
  */
 package org.apache.sshd.common.session;
 
+import static org.apache.sshd.common.SshConstants.SSH_MSG_DEBUG;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_DISCONNECT;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_IGNORE;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_KEXINIT;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_NEWKEYS;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_SERVICE_ACCEPT;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_SERVICE_REQUEST;
+import static org.apache.sshd.common.SshConstants.SSH_MSG_UNIMPLEMENTED;
+
 import java.io.IOException;
 import java.io.InterruptedIOException;
 import java.util.LinkedList;
@@ -39,6 +48,7 @@ import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.KeyExchange;
 import org.apache.sshd.common.Mac;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.Random;
 import org.apache.sshd.common.Service;
 import org.apache.sshd.common.Session;
@@ -57,15 +67,6 @@ import org.apache.sshd.common.util.CloseableUtils;
 import org.apache.sshd.common.util.EventListenerUtils;
 import org.apache.sshd.common.util.Readable;
 
-import static org.apache.sshd.common.SshConstants.SSH_MSG_DEBUG;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_DISCONNECT;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_IGNORE;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_KEXINIT;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_NEWKEYS;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_SERVICE_ACCEPT;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_SERVICE_REQUEST;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_UNIMPLEMENTED;
-
 /**
  * The AbstractSession handles all the basic SSH protocol such as key exchange, authentication,
  * encoding and decoding. Both server side and client side sessions should inherit from this
@@ -873,14 +874,14 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
      */
     protected String[] createProposal(String hostKeyTypes) {
         return new String[] {
-                NamedFactory.Utils.getNames(factoryManager.getKeyExchangeFactories()),
+                NamedResource.Utils.getNames(factoryManager.getKeyExchangeFactories()),
                 hostKeyTypes,
-                NamedFactory.Utils.getNames(factoryManager.getCipherFactories()),
-                NamedFactory.Utils.getNames(factoryManager.getCipherFactories()),
-                NamedFactory.Utils.getNames(factoryManager.getMacFactories()),
-                NamedFactory.Utils.getNames(factoryManager.getMacFactories()),
-                NamedFactory.Utils.getNames(factoryManager.getCompressionFactories()),
-                NamedFactory.Utils.getNames(factoryManager.getCompressionFactories()),
+                NamedResource.Utils.getNames(factoryManager.getCipherFactories()),
+                NamedResource.Utils.getNames(factoryManager.getCipherFactories()),
+                NamedResource.Utils.getNames(factoryManager.getMacFactories()),
+                NamedResource.Utils.getNames(factoryManager.getMacFactories()),
+                NamedResource.Utils.getNames(factoryManager.getCompressionFactories()),
+                NamedResource.Utils.getNames(factoryManager.getCompressionFactories()),
                 "",
                 ""
         };

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java b/sshd-core/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
index 2aee77d..23f72c0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/signature/BuiltinSignatures.java
@@ -36,7 +36,6 @@ import org.apache.sshd.common.Signature;
 import org.apache.sshd.common.cipher.ECCurves;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.SecurityUtils;
-import org.apache.sshd.common.util.ValidateUtils;
 
 /**
  * Provides easy access to the currently implemented signatures
@@ -179,32 +178,60 @@ public enum BuiltinSignatures implements NamedFactory<Signature>, OptionalFeatur
     /**
      * @param sigs A comma-separated list of signatures' names - ignored
      * if {@code null}/empty
-     * @return A {@link List} of all the {@link NamedFactory} whose
+     * @return A {@link ParseResult} of all the {@link NamedFactory} whose
      * name appears in the string and represent a built-in signature. Any
      * unknown name is <U>ignored</I>. The order of the returned result
      * is the same as the original order - bar the unknown signatures.
      * <B>Note:</B> it is up to caller to ensure that the list does not
      * contain duplicates
      */
-    public static final List<NamedFactory<Signature>> parseSignatureList(String sigs) {
+    public static final ParseResult parseSignatureList(String sigs) {
         return parseSignatureList(GenericUtils.split(sigs, ','));
     }
 
-    public static final List<NamedFactory<Signature>> parseSignatureList(String ... sigs) {
+    public static final ParseResult parseSignatureList(String ... sigs) {
         return parseSignatureList(GenericUtils.isEmpty((Object[]) sigs) ? Collections.<String>emptyList() : Arrays.asList(sigs));
     }
 
-    public static final List<NamedFactory<Signature>> parseSignatureList(Collection<String> sigs) {
+    public static final ParseResult parseSignatureList(Collection<String> sigs) {
         if (GenericUtils.isEmpty(sigs)) {
-            return Collections.emptyList();
+            return ParseResult.EMPTY;
         }
         
-        List<NamedFactory<Signature>>    result=new ArrayList<NamedFactory<Signature>>(sigs.size());
+        List<NamedFactory<Signature>>   factories=new ArrayList<NamedFactory<Signature>>(sigs.size());
+        List<String>                    unknown=Collections.<String>emptyList();
         for (String name : sigs) {
-            BuiltinSignatures  s=ValidateUtils.checkNotNull(fromFactoryName(name), "Bad factory name (%s) in %s", name, sigs);
-            result.add(s);
+            BuiltinSignatures  s=fromFactoryName(name);
+            if (s != null) {
+                factories.add(s);
+            } else {
+                // replace the (unmodifiable) empty list with a real one
+                if (unknown.isEmpty()) {
+                    unknown = new ArrayList<String>();
+                }
+                unknown.add(name);
+            }
         }
         
-        return result;
+        return new ParseResult(factories, unknown);
+    }
+
+    public static final class ParseResult {
+        public static final ParseResult EMPTY=new ParseResult(Collections.<NamedFactory<Signature>>emptyList(), Collections.<String>emptyList());
+        private final List<NamedFactory<Signature>> parsed;
+        private final List<String> unsupported;
+        
+        public ParseResult(List<NamedFactory<Signature>> parsed, List<String> unsupported) {
+            this.parsed = parsed;
+            this.unsupported = unsupported;
+        }
+        
+        public List<NamedFactory<Signature>> getParsedFactories() {
+            return parsed;
+        }
+        
+        public List<String> getUnsupportedFactories() {
+            return unsupported;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
index f856ea9..9e270ab 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/ValidateUtils.java
@@ -27,43 +27,37 @@ import java.util.Map;
  */
 public class ValidateUtils {
     public static final <T> T checkNotNull(T t, String message, Object ... args) {
-        if (t == null) {
-            throw new IllegalStateException(String.format(message, args));
-        }
+        checkTrue(t != null, message, args);
         return t;
     }
 
     public static final String checkNotNullAndNotEmpty(String t, String message, Object ... args) {
         t = checkNotNull(t, message, args).trim();
-        if (t.isEmpty()) {
-            throw new IllegalArgumentException(String.format(message, args));
-        }
+        checkTrue(GenericUtils.length(t) > 0, message, args);
         return t;
     }
 
     public static final <K,V,M extends Map<K,V>> M checkNotNullAndNotEmpty(M t, String message, Object ... args) {
         t = checkNotNull(t, message, args);
-        if (GenericUtils.size(t) <= 0) {
-            throw new IllegalArgumentException(String.format(message, args));
-        }
-        
+        checkTrue(GenericUtils.size(t) > 0, message, args);
         return t;
     }
 
     public static final <T,C extends Collection<T>> C checkNotNullAndNotEmpty(C t, String message, Object ... args) {
         t = checkNotNull(t, message, args);
-        if (GenericUtils.size(t) <= 0) {
-            throw new IllegalArgumentException(String.format(message, args));
-        }
-        
+        checkTrue(GenericUtils.size(t) > 0, message, args);
         return t;
     }
 
     public static final <T> T[] checkNotNullAndNotEmpty(T[] t, String message, Object ... args) {
         t = checkNotNull(t, message, args);
-        if (GenericUtils.length(t) <= 0) {
-            throw new IllegalArgumentException(String.format(message, t, args));
-        }
+        checkTrue(GenericUtils.length(t) > 0, message, args);
         return t;
     }
+    
+    public static final void checkTrue(boolean flag, String message, Object ... args) {
+        if (!flag) {
+            throw new IllegalArgumentException(String.format(message, args));
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
index fa87cb4..0a779a7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerSession.java
@@ -25,7 +25,7 @@ import java.util.List;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.KeyPairProvider;
-import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.ServiceFactory;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
@@ -109,8 +109,8 @@ public class ServerSession extends AbstractSession {
         FactoryManager manager = getFactoryManager();
         KeyPairProvider kpp = manager.getKeyPairProvider();
         String hostKeyTypes = kpp.getKeyTypes();
-        List<String> supported = NamedFactory.Utils.getNameList(manager.getSignatureFactories());
-        String[] provided = hostKeyTypes.split(",");
+        List<String> supported = NamedResource.Utils.getNameList(manager.getSignatureFactories());
+        String[] provided = GenericUtils.split(hostKeyTypes, ',');
         StringBuilder resolvedHostKeys = null;
         for (int index = 0; index < provided.length; index++) {
             String keyType = provided[index];

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
index 8929896..49d7712 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
@@ -28,6 +28,7 @@ import org.apache.sshd.SshServer;
 import org.apache.sshd.common.FactoryManager;
 import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.Service;
 import org.apache.sshd.common.ServiceFactory;
 import org.apache.sshd.common.Session;
@@ -81,7 +82,7 @@ public class ServerUserAuthService extends CloseableUtils.AbstractCloseable impl
         authMethods = new ArrayList<>();
         
         ServerFactoryManager  manager=getFactoryManager();
-        String mths = FactoryManagerUtils.getString(manager, SshServer.AUTH_METHODS);
+        String mths = FactoryManagerUtils.getString(manager, ServerFactoryManager.AUTH_METHODS);
         if (GenericUtils.isEmpty(mths)) {
             for (NamedFactory<UserAuth> uaf : manager.getUserAuthFactories()) {
                 authMethods.add(new ArrayList<>(Collections.singletonList(uaf.getName())));
@@ -101,11 +102,12 @@ public class ServerUserAuthService extends CloseableUtils.AbstractCloseable impl
         }
         
         if (log.isDebugEnabled()) {
-            log.debug("Authorized authentication methods: {}", NamedFactory.Utils.getNames(userAuthFactories));
+            log.debug("Authorized authentication methods: {}", NamedResource.Utils.getNames(userAuthFactories));
         }
     }
 
     public void start() {
+        // do nothing
     }
 
     public ServerSession getSession() {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java b/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
index 4046d15..d7204de 100644
--- a/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/SshBuilderTest.java
@@ -27,6 +27,7 @@ import java.util.Set;
 import org.apache.sshd.SshBuilder.BaseBuilder;
 import org.apache.sshd.common.Cipher;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
 import org.apache.sshd.common.cipher.BuiltinCiphers;
 import org.apache.sshd.common.kex.BuiltinDHFactories;
 import org.apache.sshd.common.mac.BuiltinMacs;
@@ -114,7 +115,7 @@ public class SshBuilderTest extends BaseTest {
             }
             
             // make sure order is according to the default preference list
-            List<String>    cipherNames=NamedFactory.Utils.getNameList(ciphers);
+            List<String>    cipherNames=NamedResource.Utils.getNameList(ciphers);
             int             nameIndex=0;
             for (BuiltinCiphers c : BaseBuilder.DEFAULT_CIPHERS_PREFERENCE) {
                 if ((!c.isSupported()) && (!ignoreUnsupported)) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.java b/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.java
index e90e64a..4a70140 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/cipher/BuiltinCiphersTest.java
@@ -20,11 +20,19 @@
 package org.apache.sshd.common.cipher;
 
 import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.EnumSet;
+import java.util.List;
+import java.util.Random;
 import java.util.Set;
 
 import org.apache.sshd.common.Cipher;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.cipher.BuiltinCiphers.ParseResult;
+import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.util.BaseTest;
 import org.junit.Assert;
 import org.junit.Test;
@@ -106,4 +114,40 @@ public class BuiltinCiphersTest extends BaseTest {
             cipher.init(Cipher.Mode.Encrypt, key, iv);
         }
     }
+
+    @Test
+    public void testParseCiphersList() {
+        List<String>    builtin=NamedResource.Utils.getNameList(BuiltinCiphers.VALUES);
+        List<String>    unknown=Arrays.asList(getClass().getPackage().getName(), getClass().getSimpleName(), getCurrentTestName());
+        Random          rnd=new Random();
+        for (int index=0; index < (builtin.size() + unknown.size()); index++) {
+            Collections.shuffle(builtin, rnd);
+            Collections.shuffle(unknown, rnd);
+            
+            List<String>    weavedList=new ArrayList<String>(builtin.size() + unknown.size());
+            for (int bIndex=0, uIndex=0; (bIndex < builtin.size()) || (uIndex < unknown.size()); ) {
+                boolean useBuiltin=false;
+                if (bIndex < builtin.size()) {
+                    useBuiltin = (uIndex < unknown.size()) ? rnd.nextBoolean() : true;
+                }
+
+                if (useBuiltin) {
+                    weavedList.add(builtin.get(bIndex));
+                    bIndex++;
+                } else if (uIndex < unknown.size()){
+                    weavedList.add(unknown.get(uIndex));
+                    uIndex++;
+                }
+            }
+
+            String          fullList=GenericUtils.join(weavedList, ',');
+            ParseResult     result=BuiltinCiphers.parseCiphersList(fullList);
+            List<String>    parsed=NamedResource.Utils.getNameList(result.getParsedFactories());
+            List<String>    missing=result.getUnsupportedFactories();
+            
+            // makes sure not only that the contents are the same but also the order
+            assertListEquals(fullList + "[parsed]", builtin, parsed);
+            assertListEquals(fullList + "[unsupported]", unknown, missing);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/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 f47666e..e3cfcb3 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
@@ -22,11 +22,24 @@ package org.apache.sshd.common.config;
 import java.io.IOException;
 import java.net.URL;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Properties;
 
 import org.apache.sshd.SshBuilder;
+import org.apache.sshd.common.AbstractFactoryManager;
+import org.apache.sshd.common.Cipher;
+import org.apache.sshd.common.Closeable;
+import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.Mac;
+import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.Signature;
+import org.apache.sshd.common.cipher.BuiltinCiphers;
+import org.apache.sshd.common.compression.Compression;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
+import org.apache.sshd.common.mac.BuiltinMacs;
+import org.apache.sshd.common.signature.BuiltinSignatures;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.util.BaseTest;
 import org.junit.Assert;
@@ -60,29 +73,33 @@ public class SshConfigFileReaderTest extends BaseTest {
     @Test
     public void testParseCiphersList() {
         List<? extends NamedResource>   expected=SshBuilder.BaseBuilder.DEFAULT_CIPHERS_PREFERENCE;
-        Properties                      props=initProperties(SshConfigFileReader.CIPHERS_CONFIG_PROP, expected);
-        testParsedFactoriesList(expected, SshConfigFileReader.getCiphers(props));
+        Properties                      props=initNamedResourceProperties(SshConfigFileReader.CIPHERS_CONFIG_PROP, expected);
+        BuiltinCiphers.ParseResult      result=SshConfigFileReader.getCiphers(props);
+        testParsedFactoriesList(expected, result.getParsedFactories(), result.getUnsupportedFactories());
     }
 
     @Test
     public void testParseMacsList() {
         List<? extends NamedResource>   expected=SshBuilder.BaseBuilder.DEFAULT_MAC_PREFERENCE;
-        Properties                      props=initProperties(SshConfigFileReader.MACS_CONFIG_PROP, expected);
-        testParsedFactoriesList(expected, SshConfigFileReader.getMacs(props));
+        Properties                      props=initNamedResourceProperties(SshConfigFileReader.MACS_CONFIG_PROP, expected);
+        BuiltinMacs.ParseResult         result=SshConfigFileReader.getMacs(props);
+        testParsedFactoriesList(expected, result.getParsedFactories(), result.getUnsupportedFactories());
     }
 
     @Test
     public void testParseSignaturesList() {
         List<? extends NamedResource>   expected=SshBuilder.BaseBuilder.DEFAULT_SIGNATURE_PREFERENCE;
-        Properties                      props=initProperties(SshConfigFileReader.HOST_KEY_ALGORITHMS_CONFIG_PROP, expected);
-        testParsedFactoriesList(expected, SshConfigFileReader.getSignatures(props));
+        Properties                      props=initNamedResourceProperties(SshConfigFileReader.HOST_KEY_ALGORITHMS_CONFIG_PROP, expected);
+        BuiltinSignatures.ParseResult   result=SshConfigFileReader.getSignatures(props);
+        testParsedFactoriesList(expected, result.getParsedFactories(), result.getUnsupportedFactories());
     }
 
     @Test
     public void testParseKexFactoriesList() {
         List<? extends NamedResource>   expected=SshBuilder.BaseBuilder.DEFAULT_KEX_PREFERENCE;
-        Properties                      props=initProperties(SshConfigFileReader.KEX_ALGORITHMS_CONFIG_PROP, expected);
-        testParsedFactoriesList(expected, SshConfigFileReader.getKexFactories(props));
+        Properties                      props=initNamedResourceProperties(SshConfigFileReader.KEX_ALGORITHMS_CONFIG_PROP, expected);
+        BuiltinDHFactories.ParseResult  result=SshConfigFileReader.getKexFactories(props);
+        testParsedFactoriesList(expected, result.getParsedFactories(), result.getUnsupportedFactories());
     }
 
     @Test
@@ -97,7 +114,129 @@ public class SshConfigFileReaderTest extends BaseTest {
         }
     }
 
-    private static <T extends NamedResource> List<T> testParsedFactoriesList(List<? extends NamedResource> expected, List<T> actual) {
+    @Test
+    public void testConfigureAbstractFactoryManagerWithDefaults() {
+        Properties              props=new Properties();   // empty means use defaults
+        AbstractFactoryManager  expected=new AbstractFactoryManager() {
+                @Override
+                protected Closeable getInnerCloseable() {
+                    return null;
+                }
+            };
+        // must be lenient since we do not cover the full default spectrum
+        AbstractFactoryManager  actual=SshConfigFileReader.configure(expected, props, true);
+        Assert.assertSame("Mismatched configured result", expected, actual);
+        validateAbstractFactoryManagerConfiguration(expected, props, true);
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testNonLenientCiphersConfiguration() {
+        FactoryManager  manager=SshConfigFileReader.configureCiphers(
+                new AbstractFactoryManager() {
+                    @Override
+                    protected Closeable getInnerCloseable() {
+                        return null;
+                    }
+                },
+                getCurrentTestName(),
+                false);
+        Assert.fail("Unexpected success: " + NamedResource.Utils.getNames(manager.getCipherFactories()));
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testNonLenientSignaturesConfiguration() {
+        FactoryManager  manager=SshConfigFileReader.configureSignatures(
+                new AbstractFactoryManager() {
+                    @Override
+                    protected Closeable getInnerCloseable() {
+                        return null;
+                    }
+                },
+                getCurrentTestName(),
+                false);
+        Assert.fail("Unexpected success: " + NamedResource.Utils.getNames(manager.getSignatureFactories()));
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testNonLenientMacsConfiguration() {
+        FactoryManager  manager=SshConfigFileReader.configureMacs(
+                new AbstractFactoryManager() {
+                    @Override
+                    protected Closeable getInnerCloseable() {
+                        return null;
+                    }
+                },
+                getCurrentTestName(),
+                false);
+        Assert.fail("Unexpected success: " + NamedResource.Utils.getNames(manager.getMacFactories()));
+    }
+    
+    private static <M extends FactoryManager> M validateAbstractFactoryManagerConfiguration(M manager, Properties props, boolean lenient) {
+        validateFactoryManagerCiphers(manager, props);
+        validateFactoryManagerSignatures(manager, props);
+        validateFactoryManagerMacs(manager, props);
+        validateFactoryManagerCompressions(manager, props, lenient);
+        return manager;
+    }
+
+    private static <M extends FactoryManager> M validateFactoryManagerCiphers(M manager, Properties props) {
+        return validateFactoryManagerCiphers(manager, props.getProperty(SshConfigFileReader.CIPHERS_CONFIG_PROP, SshConfigFileReader.DEFAULT_CIPHERS));
+    }
+
+    private static <M extends FactoryManager> M validateFactoryManagerCiphers(M manager, String value) {
+        BuiltinCiphers.ParseResult  result=BuiltinCiphers.parseCiphersList(value);
+        validateFactoryManagerFactories(Cipher.class, result.getParsedFactories(), manager.getCipherFactories());
+        return manager;
+    }
+
+    private static <M extends FactoryManager> M validateFactoryManagerSignatures(M manager, Properties props) {
+        return validateFactoryManagerSignatures(manager, props.getProperty(SshConfigFileReader.HOST_KEY_ALGORITHMS_CONFIG_PROP, SshConfigFileReader.DEFAULT_HOST_KEY_ALGORITHMS));
+    }
+
+    private static <M extends FactoryManager> M validateFactoryManagerSignatures(M manager, String value) {
+        BuiltinSignatures.ParseResult   result=BuiltinSignatures.parseSignatureList(value);
+        validateFactoryManagerFactories(Signature.class, result.getParsedFactories(), manager.getSignatureFactories());
+        return manager;
+    }
+
+    private static <M extends FactoryManager> M validateFactoryManagerMacs(M manager, Properties props) {
+        return validateFactoryManagerMacs(manager, props.getProperty(SshConfigFileReader.MACS_CONFIG_PROP, SshConfigFileReader.DEFAULT_MACS));
+    }
+
+    private static <M extends FactoryManager> M validateFactoryManagerMacs(M manager, String value) {
+        BuiltinMacs.ParseResult   result=BuiltinMacs.parseMacsList(value);
+        validateFactoryManagerFactories(Mac.class, result.getParsedFactories(), manager.getMacFactories());
+        return manager;
+    }
+
+    private static <M extends FactoryManager> M validateFactoryManagerCompressions(M manager, Properties props, boolean lenient) {
+        return validateFactoryManagerCompressions(manager, props.getProperty(SshConfigFileReader.COMPRESSION_PROP, SshConfigFileReader.DEFAULT_COMPRESSION), lenient);
+    }
+
+    private static <M extends FactoryManager> M validateFactoryManagerCompressions(M manager, String value, boolean lenient) {
+        NamedFactory<Compression>   factory=CompressionConfigValue.fromName(value);
+        Assert.assertTrue("Unknown compression: " + value, lenient || (factory != null));
+        if (factory != null) {
+            validateFactoryManagerFactories(Compression.class, Collections.singletonList(factory), manager.getCompressionFactories());
+        }
+        return manager;
+    }
+
+    private static <T,F extends NamedFactory<T>> void validateFactoryManagerFactories(Class<T> type, List<? extends F> expected, List<? extends F> actual) {
+        validateFactoryManagerSettings(type, expected, actual);
+    }
+
+    private static <R extends NamedResource> void validateFactoryManagerSettings(Class<?> type, List<? extends R> expected, List<? extends R> actual) {
+        validateFactoryManagerSettings(type.getSimpleName(), expected, actual);
+    }
+
+    private static <R extends NamedResource> void validateFactoryManagerSettings(String type, List<? extends R> expected, List<? extends R> actual) {
+        assertListEquals(type, expected, actual);
+    }
+
+    private static <T extends NamedResource> List<T> testParsedFactoriesList(
+            List<? extends NamedResource> expected, List<T> actual, Collection<String> unsupported) {
+        Assert.assertTrue("Unexpected unsupported factories: " + unsupported, GenericUtils.isEmpty(unsupported));
         Assert.assertEquals("Mismatched list size", expected.size(), GenericUtils.size(actual));
         for (int index=0; index < expected.size(); index++) {
             NamedResource   e=expected.get(index), a=actual.get(index);
@@ -108,8 +247,8 @@ public class SshConfigFileReaderTest extends BaseTest {
         return actual;
     }
     
-    private static Properties initProperties(String key, Collection<?> values) {
-        return initProperties(key, GenericUtils.join(values, ','));
+    private static <R extends NamedResource> Properties initNamedResourceProperties(String key, Collection<? extends R> values) {
+        return initProperties(key, NamedResource.Utils.getNames(values));
     }
 
     private static Properties initProperties(String key, String value) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/cca7cc74/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java b/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java
index 61ebcf6..1dd77ce 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/kex/BuiltinDHFactoriesTest.java
@@ -20,9 +20,17 @@
 package org.apache.sshd.common.kex;
 
 import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.EnumSet;
+import java.util.List;
+import java.util.Random;
 import java.util.Set;
 
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.kex.BuiltinDHFactories.ParseResult;
+import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.util.BaseTest;
 import org.junit.Assert;
 import org.junit.Test;
@@ -57,4 +65,40 @@ public class BuiltinDHFactoriesTest extends BaseTest {
         
         Assert.assertEquals("Incomplete coverage", BuiltinDHFactories.VALUES, avail);
     }
+
+    @Test
+    public void testParseDHFactorysList() {
+        List<String>    builtin=NamedResource.Utils.getNameList(BuiltinDHFactories.VALUES);
+        List<String>    unknown=Arrays.asList(getClass().getPackage().getName(), getClass().getSimpleName(), getCurrentTestName());
+        Random          rnd=new Random();
+        for (int index=0; index < (builtin.size() + unknown.size()); index++) {
+            Collections.shuffle(builtin, rnd);
+            Collections.shuffle(unknown, rnd);
+            
+            List<String>    weavedList=new ArrayList<String>(builtin.size() + unknown.size());
+            for (int bIndex=0, uIndex=0; (bIndex < builtin.size()) || (uIndex < unknown.size()); ) {
+                boolean useBuiltin=false;
+                if (bIndex < builtin.size()) {
+                    useBuiltin = (uIndex < unknown.size()) ? rnd.nextBoolean() : true;
+                }
+
+                if (useBuiltin) {
+                    weavedList.add(builtin.get(bIndex));
+                    bIndex++;
+                } else if (uIndex < unknown.size()){
+                    weavedList.add(unknown.get(uIndex));
+                    uIndex++;
+                }
+            }
+
+            String          fullList=GenericUtils.join(weavedList, ',');
+            ParseResult     result=BuiltinDHFactories.parseDHFactoriesList(fullList);
+            List<String>    parsed=NamedResource.Utils.getNameList(result.getParsedFactories());
+            List<String>    missing=result.getUnsupportedFactories();
+            
+            // makes sure not only that the contents are the same but also the order
+            assertListEquals(fullList + "[parsed]", builtin, parsed);
+            assertListEquals(fullList + "[unsupported]", unknown, missing);
+        }
+    }
 }